Update CodeRay version to 1.0 final (#4264).

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@7619 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Etienne Massip
2011-10-08 13:35:15 +00:00
parent d1efb4f148
commit 8c2ae427fa
28 changed files with 4997 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
module CodeRay
module Encoders
class HTML
class CSS # :nodoc:
attr :stylesheet
def CSS.load_stylesheet style = nil
CodeRay::Styles[style]
end
def initialize style = :default
@classes = Hash.new
style = CSS.load_stylesheet style
@stylesheet = [
style::CSS_MAIN_STYLES,
style::TOKEN_COLORS.gsub(/^(?!$)/, '.CodeRay ')
].join("\n")
parse style::TOKEN_COLORS
end
def get_style styles
cl = @classes[styles.first]
return '' unless cl
style = ''
1.upto styles.size do |offset|
break if style = cl[styles[offset .. -1]]
end
# warn 'Style not found: %p' % [styles] if style.empty?
return style
end
private
CSS_CLASS_PATTERN = /
( # $1 = selectors
(?:
(?: \s* \. [-\w]+ )+
\s* ,?
)+
)
\s* \{ \s*
( [^\}]+ )? # $2 = style
\s* \} \s*
|
( [^\n]+ ) # $3 = error
/mx
def parse stylesheet
stylesheet.scan CSS_CLASS_PATTERN do |selectors, style, error|
raise "CSS parse error: '#{error.inspect}' not recognized" if error
for selector in selectors.split(',')
classes = selector.scan(/[-\w]+/)
cl = classes.pop
@classes[cl] ||= Hash.new
@classes[cl][classes] = style.to_s.strip.delete(' ').chomp(';')
end
end
end
end
end
end
end

View File

@@ -0,0 +1,115 @@
module CodeRay
module Encoders
class HTML
module Numbering # :nodoc:
def self.number! output, mode = :table, options = {}
return self unless mode
options = DEFAULT_OPTIONS.merge options
start = options[:line_number_start]
unless start.is_a? Integer
raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start
end
anchor_prefix = options[:line_number_anchors]
anchor_prefix = 'line' if anchor_prefix == true
anchor_prefix = anchor_prefix.to_s[/\w+/] if anchor_prefix
anchoring =
if anchor_prefix
proc do |line|
line = line.to_s
anchor = anchor_prefix + line
"<a href=\"##{anchor}\" name=\"#{anchor}\">#{line}</a>"
end
else
proc { |line| line.to_s } # :to_s.to_proc in Ruby 1.8.7+
end
bold_every = options[:bold_every]
highlight_lines = options[:highlight_lines]
bolding =
if bold_every == false && highlight_lines == nil
anchoring
elsif highlight_lines.is_a? Enumerable
highlight_lines = highlight_lines.to_set
proc do |line|
if highlight_lines.include? line
"<strong class=\"highlighted\">#{anchoring[line]}</strong>" # highlighted line numbers in bold
else
anchoring[line]
end
end
elsif bold_every.is_a? Integer
raise ArgumentError, ":bolding can't be 0." if bold_every == 0
proc do |line|
if line % bold_every == 0
"<strong>#{anchoring[line]}</strong>" # every bold_every-th number in bold
else
anchoring[line]
end
end
else
raise ArgumentError, 'Invalid value %p for :bolding; false or Integer expected.' % bold_every
end
line_count = output.count("\n")
position_of_last_newline = output.rindex(RUBY_VERSION >= '1.9' ? /\n/ : ?\n)
if position_of_last_newline
after_last_newline = output[position_of_last_newline + 1 .. -1]
ends_with_newline = after_last_newline[/\A(?:<\/span>)*\z/]
line_count += 1 if not ends_with_newline
end
case mode
when :inline
max_width = (start + line_count).to_s.size
line_number = start
nesting = []
output.gsub!(/^.*$\n?/) do |line|
line.chomp!
open = nesting.join
line.scan(%r!<(/)?span[^>]*>?!) do |close,|
if close
nesting.pop
else
nesting << $&
end
end
close = '</span>' * nesting.size
line_number_text = bolding.call line_number
indent = ' ' * (max_width - line_number.to_s.size) # TODO: Optimize (10^x)
line_number += 1
"<span class=\"line-numbers\">#{indent}#{line_number_text}</span>#{open}#{line}#{close}\n"
end
when :table
line_numbers = (start ... start + line_count).map(&bolding).join("\n")
line_numbers << "\n"
line_numbers_table_template = Output::TABLE.apply('LINE_NUMBERS', line_numbers)
output.gsub!(/<\/div>\n/, '</div>')
output.wrap_in! line_numbers_table_template
output.wrapped_in = :div
when :list
raise NotImplementedError, 'The :list option is no longer available. Use :table.'
else
raise ArgumentError, 'Unknown value %p for mode: expected one of %p' %
[mode, [:table, :inline]]
end
output
end
end
end
end
end

View File

@@ -0,0 +1,158 @@
module CodeRay
module Encoders
class HTML
# This module is included in the output String of the HTML Encoder.
#
# It provides methods like wrap, div, page etc.
#
# Remember to use #clone instead of #dup to keep the modules the object was
# extended with.
#
# TODO: Rewrite this without monkey patching.
module Output
attr_accessor :css
class << self
# Raises an exception if an object that doesn't respond to to_str is extended by Output,
# to prevent users from misuse. Use Module#remove_method to disable.
def extended o # :nodoc:
warn "The Output module is intended to extend instances of String, not #{o.class}." unless o.respond_to? :to_str
end
def make_stylesheet css, in_tag = false # :nodoc:
sheet = css.stylesheet
sheet = <<-'CSS' if in_tag
<style type="text/css">
#{sheet}
</style>
CSS
sheet
end
def page_template_for_css css # :nodoc:
sheet = make_stylesheet css
PAGE.apply 'CSS', sheet
end
end
def wrapped_in? element
wrapped_in == element
end
def wrapped_in
@wrapped_in ||= nil
end
attr_writer :wrapped_in
def wrap_in! template
Template.wrap! self, template, 'CONTENT'
self
end
def apply_title! title
self.sub!(/(<title>)(<\/title>)/) { $1 + title + $2 }
self
end
def wrap! element, *args
return self if not element or element == wrapped_in
case element
when :div
raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil
wrap_in! DIV
when :span
raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil
wrap_in! SPAN
when :page
wrap! :div if wrapped_in? nil
raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? :div
wrap_in! Output.page_template_for_css(@css)
if args.first.is_a?(Hash) && title = args.first[:title]
apply_title! title
end
self
when nil
return self
else
raise "Unknown value %p for :wrap" % element
end
@wrapped_in = element
self
end
def stylesheet in_tag = false
Output.make_stylesheet @css, in_tag
end
#-- don't include the templates in docu
class Template < String # :nodoc:
def self.wrap! str, template, target
target = Regexp.new(Regexp.escape("<%#{target}%>"))
if template =~ target
str[0,0] = $`
str << $'
else
raise "Template target <%%%p%%> not found" % target
end
end
def apply target, replacement
target = Regexp.new(Regexp.escape("<%#{target}%>"))
if self =~ target
Template.new($` + replacement + $')
else
raise "Template target <%%%p%%> not found" % target
end
end
end
SPAN = Template.new '<span class="CodeRay"><%CONTENT%></span>'
DIV = Template.new <<-DIV
<div class="CodeRay">
<div class="code"><pre><%CONTENT%></pre></div>
</div>
DIV
TABLE = Template.new <<-TABLE
<table class="CodeRay"><tr>
<td class="line-numbers" title="double click to toggle" ondblclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre><%LINE_NUMBERS%></pre></td>
<td class="code"><pre><%CONTENT%></pre></td>
</tr></table>
TABLE
PAGE = Template.new <<-PAGE
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<style type="text/css">
.CodeRay .line-numbers a {
text-decoration: inherit;
color: inherit;
}
<%CSS%>
</style>
</head>
<body style="background-color: white;">
<%CONTENT%>
</body>
</html>
PAGE
end
end
end
end