summaryrefslogtreecommitdiff
path: root/lib/coderay/encoders
diff options
context:
space:
mode:
Diffstat (limited to 'lib/coderay/encoders')
-rw-r--r--lib/coderay/encoders/debug.rb23
-rw-r--r--lib/coderay/encoders/debug_lint.rb63
-rw-r--r--lib/coderay/encoders/html.rb183
-rw-r--r--lib/coderay/encoders/html/css.rb14
-rw-r--r--lib/coderay/encoders/html/numbering.rb4
-rw-r--r--lib/coderay/encoders/lint.rb59
-rw-r--r--lib/coderay/encoders/statistic.rb1
-rw-r--r--lib/coderay/encoders/terminal.rb226
8 files changed, 352 insertions, 221 deletions
diff --git a/lib/coderay/encoders/debug.rb b/lib/coderay/encoders/debug.rb
index c03d3fb..f4db330 100644
--- a/lib/coderay/encoders/debug.rb
+++ b/lib/coderay/encoders/debug.rb
@@ -9,7 +9,6 @@ module Encoders
#
# You cannot fully restore the tokens information from the
# output, because consecutive :space tokens are merged.
- # Use Tokens#dump for caching purposes.
#
# See also: Scanners::Debug
class Debug < Encoder
@@ -18,38 +17,26 @@ module Encoders
FILE_EXTENSION = 'raydebug'
- def initialize options = {}
- super
- @opened = []
- end
-
def text_token text, kind
- raise 'empty token' if $CODERAY_DEBUG && text.empty?
if kind == :space
@out << text
else
- # TODO: Escape (
- text = text.gsub(/[)\\]/, '\\\\\0') if text.index(/[)\\]/)
- @out << kind.to_s << '(' << text << ')'
+ text = text.gsub('\\', '\\\\\\\\') if text.index('\\')
+ text = text.gsub(')', '\\\\)') if text.index(')')
+ @out << "#{kind}(#{text})"
end
end
def begin_group kind
- @opened << kind
- @out << kind.to_s << '<'
+ @out << "#{kind}<"
end
def end_group kind
- if @opened.last != kind
- puts @out
- raise "we are inside #{@opened.inspect}, not #{kind}"
- end
- @opened.pop
@out << '>'
end
def begin_line kind
- @out << kind.to_s << '['
+ @out << "#{kind}["
end
def end_line kind
diff --git a/lib/coderay/encoders/debug_lint.rb b/lib/coderay/encoders/debug_lint.rb
new file mode 100644
index 0000000..a4eba2c
--- /dev/null
+++ b/lib/coderay/encoders/debug_lint.rb
@@ -0,0 +1,63 @@
+module CodeRay
+module Encoders
+
+ load :lint
+
+ # = Debug Lint Encoder
+ #
+ # Debug encoder with additional checks for:
+ #
+ # - empty tokens
+ # - incorrect nesting
+ #
+ # It will raise an InvalidTokenStream exception when any of the above occurs.
+ #
+ # See also: Encoders::Debug
+ class DebugLint < Debug
+
+ register_for :debug_lint
+
+ def text_token text, kind
+ raise Lint::EmptyToken, 'empty token for %p' % [kind] if text.empty?
+ raise Lint::UnknownTokenKind, 'unknown token kind %p (text was %p)' % [kind, text] unless TokenKinds.has_key? kind
+ super
+ end
+
+ def begin_group kind
+ @opened << kind
+ super
+ end
+
+ def end_group kind
+ raise Lint::IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_group)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind
+ @opened.pop
+ super
+ end
+
+ def begin_line kind
+ @opened << kind
+ super
+ end
+
+ def end_line kind
+ raise Lint::IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_line)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind
+ @opened.pop
+ super
+ end
+
+ protected
+
+ def setup options
+ super
+ @opened = []
+ end
+
+ def finish options
+ raise 'Some tokens still open at end of token stream: %p' % [@opened] unless @opened.empty?
+ super
+ end
+
+ end
+
+end
+end
diff --git a/lib/coderay/encoders/html.rb b/lib/coderay/encoders/html.rb
index 0fd1317..d2ebb5a 100644
--- a/lib/coderay/encoders/html.rb
+++ b/lib/coderay/encoders/html.rb
@@ -126,22 +126,21 @@ module Encoders
protected
- HTML_ESCAPE = { #:nodoc:
- '&' => '&amp;',
- '"' => '&quot;',
- '>' => '&gt;',
- '<' => '&lt;',
- }
+ def self.make_html_escape_hash
+ {
+ '&' => '&amp;',
+ '"' => '&quot;',
+ '>' => '&gt;',
+ '<' => '&lt;',
+ # "\t" => will be set to ' ' * options[:tab_width] during setup
+ }.tap do |hash|
+ # Escape ASCII control codes except \x9 == \t and \xA == \n.
+ (Array(0x00..0x8) + Array(0xB..0x1F)).each { |invalid| hash[invalid.chr] = ' ' }
+ end
+ end
- # This was to prevent illegal HTML.
- # Strange chars should still be avoided in codes.
- evil_chars = Array(0x00...0x20) - [?\n, ?\t, ?\s]
- evil_chars.each { |i| HTML_ESCAPE[i.chr] = ' ' }
- #ansi_chars = Array(0x7f..0xff)
- #ansi_chars.each { |i| HTML_ESCAPE[i.chr] = '&#%d;' % i }
- # \x9 (\t) and \xA (\n) not included
- #HTML_ESCAPE_PATTERN = /[\t&"><\0-\x8\xB-\x1f\x7f-\xff]/
- HTML_ESCAPE_PATTERN = /[\t"&><\0-\x8\xB-\x1f]/
+ HTML_ESCAPE = make_html_escape_hash
+ HTML_ESCAPE_PATTERN = /[\t"&><\0-\x8\xB-\x1F]/
TOKEN_KIND_TO_INFO = Hash.new do |h, kind|
h[kind] = kind.to_s.gsub(/_/, ' ').gsub(/\b\w/) { $&.capitalize }
@@ -172,77 +171,41 @@ module Encoders
def setup options
super
+ check_options! options
+
if options[:wrap] || options[:line_numbers]
@real_out = @out
@out = ''
end
- options[:break_lines] = true if options[:line_numbers] == :inline
-
@break_lines = (options[:break_lines] == true)
- @HTML_ESCAPE = HTML_ESCAPE.dup
- @HTML_ESCAPE["\t"] = ' ' * options[:tab_width]
+ @HTML_ESCAPE = HTML_ESCAPE.merge("\t" => ' ' * options[:tab_width])
@opened = []
@last_opened = nil
@css = CSS.new options[:style]
- hint = options[:hint]
- if hint && ![:debug, :info, :info_long].include?(hint)
- raise ArgumentError, "Unknown value %p for :hint; \
- expected :info, :info_long, :debug, false, or nil." % hint
- end
-
- css_classes = TokenKinds
- case options[:css]
- when :class
- @span_for_kind = Hash.new do |h, k|
- if k.is_a? ::Symbol
- kind = k_dup = k
- else
- kind = k.first
- k_dup = k.dup
- end
- if kind != :space && (hint || css_class = css_classes[kind])
- title = HTML.token_path_to_hint hint, k if hint
- css_class ||= css_classes[kind]
- h[k_dup] = "<span#{title}#{" class=\"#{css_class}\"" if css_class}>"
- else
- h[k_dup] = nil
- end
- end
- when :style
- @span_for_kind = Hash.new do |h, k|
- kind = k.is_a?(Symbol) ? k : k.first
- h[k.is_a?(Symbol) ? k : k.dup] =
- if kind != :space && (hint || css_classes[kind])
- title = HTML.token_path_to_hint hint, k if hint
- style = @css.get_style Array(k).map { |c| css_classes[c] }
- "<span#{title}#{" style=\"#{style}\"" if style}>"
- end
- end
- else
- raise ArgumentError, "Unknown value %p for :css." % options[:css]
- end
+ @span_for_kinds = make_span_for_kinds(options[:css], options[:hint])
@set_last_opened = options[:hint] || options[:css] == :style
end
def finish options
unless @opened.empty?
- warn '%d tokens still open: %p' % [@opened.size, @opened] if $CODERAY_DEBUG
@out << '</span>' while @opened.pop
@last_opened = nil
end
- @out.extend Output
- @out.css = @css
- if options[:line_numbers]
- Numbering.number! @out, options[:line_numbers], options
+ if @out.respond_to? :to_str
+ @out.extend Output
+ @out.css = @css
+ if options[:line_numbers]
+ Numbering.number! @out, options[:line_numbers], options
+ end
+ @out.wrap! options[:wrap]
+ @out.apply_title! options[:title]
end
- @out.wrap! options[:wrap]
- @out.apply_title! options[:title]
if defined?(@real_out) && @real_out
@real_out << @out
@@ -255,20 +218,10 @@ module Encoders
public
def text_token text, kind
- if text =~ /#{HTML_ESCAPE_PATTERN}/o
- text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] }
- end
+ style = @span_for_kinds[@last_opened ? [kind, *@opened] : kind]
- style = @span_for_kind[@last_opened ? [kind, *@opened] : kind]
-
- if @break_lines && (i = text.index("\n")) && (c = @opened.size + (style ? 1 : 0)) > 0
- close = '</span>' * c
- reopen = ''
- @opened.each_with_index do |k, index|
- reopen << (@span_for_kind[index > 0 ? [k, *@opened[0 ... index ]] : k] || '<span>')
- end
- text[i .. -1] = text[i .. -1].gsub("\n", "#{close}\n#{reopen}#{style}")
- end
+ text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] } if text =~ /#{HTML_ESCAPE_PATTERN}/o
+ text = break_lines(text, style) if @break_lines && (style || @opened.size > 0) && text.index("\n")
if style
@out << style << text << '</span>'
@@ -279,24 +232,19 @@ module Encoders
# token groups, eg. strings
def begin_group kind
- @out << (@span_for_kind[@last_opened ? [kind, *@opened] : kind] || '<span>')
+ @out << (@span_for_kinds[@last_opened ? [kind, *@opened] : kind] || '<span>')
@opened << kind
@last_opened = kind if @set_last_opened
end
def end_group kind
- if $CODERAY_DEBUG && (@opened.empty? || @opened.last != kind)
- warn 'Malformed token stream: Trying to close a token group (%p) that is not open. Open are: %p.' % [kind, @opened[1..-1]]
- end
- if @opened.pop
- @out << '</span>'
- @last_opened = @opened.last if @last_opened
- end
+ check_group_nesting 'token group', kind if $CODERAY_DEBUG
+ close_span
end
# whole lines to be highlighted, eg. a deleted line in a diff
def begin_line kind
- if style = @span_for_kind[@last_opened ? [kind, *@opened] : kind]
+ if style = @span_for_kinds[@last_opened ? [kind, *@opened] : kind]
if style['class="']
@out << style.sub('class="', 'class="line ')
else
@@ -310,15 +258,74 @@ module Encoders
end
def end_line kind
- if $CODERAY_DEBUG && (@opened.empty? || @opened.last != kind)
- warn 'Malformed token stream: Trying to close a line (%p) that is not open. Open are: %p.' % [kind, @opened[1..-1]]
+ check_group_nesting 'line', kind if $CODERAY_DEBUG
+ close_span
+ end
+
+ protected
+
+ def check_options! options
+ unless [false, nil, :debug, :info, :info_long].include? options[:hint]
+ raise ArgumentError, "Unknown value %p for :hint; expected :info, :info_long, :debug, false, or nil." % [options[:hint]]
end
+
+ unless [:class, :style].include? options[:css]
+ raise ArgumentError, 'Unknown value %p for :css.' % [options[:css]]
+ end
+
+ options[:break_lines] = true if options[:line_numbers] == :inline
+ end
+
+ def css_class_for_kinds kinds
+ TokenKinds[kinds.is_a?(Symbol) ? kinds : kinds.first]
+ end
+
+ def style_for_kinds kinds
+ css_classes = kinds.is_a?(Array) ? kinds.map { |c| TokenKinds[c] } : [TokenKinds[kinds]]
+ @css.get_style_for_css_classes css_classes
+ end
+
+ def make_span_for_kinds method, hint
+ Hash.new do |h, kinds|
+ begin
+ css_class = css_class_for_kinds(kinds)
+ title = HTML.token_path_to_hint hint, kinds if hint
+
+ if css_class || title
+ if method == :style
+ style = style_for_kinds(kinds)
+ "<span#{title}#{" style=\"#{style}\"" if style}>"
+ else
+ "<span#{title}#{" class=\"#{css_class}\"" if css_class}>"
+ end
+ end
+ end.tap do |span|
+ h.clear if h.size >= 100
+ h[kinds] = span
+ end
+ end
+ end
+
+ def check_group_nesting name, kind
+ if @opened.empty? || @opened.last != kind
+ warn "Malformed token stream: Trying to close a #{name} (%p) that is not open. Open are: %p." % [kind, @opened[1..-1]]
+ end
+ end
+
+ def break_lines text, style
+ reopen = ''
+ @opened.each_with_index do |kind, index|
+ reopen << (@span_for_kinds[index > 0 ? [kind, *@opened[0...index]] : kind] || '<span>')
+ end
+ text.gsub("\n", "#{'</span>' * @opened.size}#{'</span>' if style}\n#{reopen}#{style}")
+ end
+
+ def close_span
if @opened.pop
@out << '</span>'
@last_opened = @opened.last if @last_opened
end
end
-
end
end
diff --git a/lib/coderay/encoders/html/css.rb b/lib/coderay/encoders/html/css.rb
index 6de4b46..164d7f8 100644
--- a/lib/coderay/encoders/html/css.rb
+++ b/lib/coderay/encoders/html/css.rb
@@ -11,7 +11,7 @@ module Encoders
end
def initialize style = :default
- @classes = Hash.new
+ @styles = Hash.new
style = CSS.load_stylesheet style
@stylesheet = [
style::CSS_MAIN_STYLES,
@@ -20,12 +20,12 @@ module Encoders
parse style::TOKEN_COLORS
end
- def get_style styles
- cl = @classes[styles.first]
+ def get_style_for_css_classes css_classes
+ cl = @styles[css_classes.first]
return '' unless cl
style = ''
- 1.upto styles.size do |offset|
- break if style = cl[styles[offset .. -1]]
+ 1.upto css_classes.size do |offset|
+ break if style = cl[css_classes[offset .. -1]]
end
# warn 'Style not found: %p' % [styles] if style.empty?
return style
@@ -52,8 +52,8 @@ module Encoders
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(';')
+ @styles[cl] ||= Hash.new
+ @styles[cl][classes] = style.to_s.strip.delete(' ').chomp(';')
end
end
end
diff --git a/lib/coderay/encoders/html/numbering.rb b/lib/coderay/encoders/html/numbering.rb
index 332145b..a1b9c04 100644
--- a/lib/coderay/encoders/html/numbering.rb
+++ b/lib/coderay/encoders/html/numbering.rb
@@ -26,7 +26,7 @@ module Encoders
"<a href=\"##{anchor}\" name=\"#{anchor}\">#{line}</a>"
end
else
- proc { |line| line.to_s } # :to_s.to_proc in Ruby 1.8.7+
+ :to_s.to_proc
end
bold_every = options[:bold_every]
@@ -75,7 +75,7 @@ module Encoders
line_number = start
output.gsub!(/^.*$\n?/) do |line|
line_number_text = bolding.call line_number
- indent = ' ' * (max_width - line_number.to_s.size) # TODO: Optimize (10^x)
+ indent = ' ' * (max_width - line_number.to_s.size)
line_number += 1
"<span class=\"line-numbers\">#{indent}#{line_number_text}</span>#{line}"
end
diff --git a/lib/coderay/encoders/lint.rb b/lib/coderay/encoders/lint.rb
new file mode 100644
index 0000000..88c8bd1
--- /dev/null
+++ b/lib/coderay/encoders/lint.rb
@@ -0,0 +1,59 @@
+module CodeRay
+module Encoders
+
+ # = Lint Encoder
+ #
+ # Checks for:
+ #
+ # - empty tokens
+ # - incorrect nesting
+ #
+ # It will raise an InvalidTokenStream exception when any of the above occurs.
+ #
+ # See also: Encoders::DebugLint
+ class Lint < Debug
+
+ register_for :lint
+
+ InvalidTokenStream = Class.new StandardError
+ EmptyToken = Class.new InvalidTokenStream
+ UnknownTokenKind = Class.new InvalidTokenStream
+ IncorrectTokenGroupNesting = Class.new InvalidTokenStream
+
+ def text_token text, kind
+ raise EmptyToken, 'empty token for %p' % [kind] if text.empty?
+ raise UnknownTokenKind, 'unknown token kind %p (text was %p)' % [kind, text] unless TokenKinds.has_key? kind
+ end
+
+ def begin_group kind
+ @opened << kind
+ end
+
+ def end_group kind
+ raise IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_group)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind
+ @opened.pop
+ end
+
+ def begin_line kind
+ @opened << kind
+ end
+
+ def end_line kind
+ raise IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_line)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind
+ @opened.pop
+ end
+
+ protected
+
+ def setup options
+ @opened = []
+ end
+
+ def finish options
+ raise 'Some tokens still open at end of token stream: %p' % [@opened] unless @opened.empty?
+ end
+
+ end
+
+end
+end
diff --git a/lib/coderay/encoders/statistic.rb b/lib/coderay/encoders/statistic.rb
index 2315d9e..b2f8b83 100644
--- a/lib/coderay/encoders/statistic.rb
+++ b/lib/coderay/encoders/statistic.rb
@@ -67,7 +67,6 @@ Token Types (%d):
@type_stats['TOTAL'].count += 1
end
- # TODO Hierarchy handling
def begin_group kind
block_token ':begin_group', kind
end
diff --git a/lib/coderay/encoders/terminal.rb b/lib/coderay/encoders/terminal.rb
index a0ceb3c..c7ae014 100644
--- a/lib/coderay/encoders/terminal.rb
+++ b/lib/coderay/encoders/terminal.rb
@@ -19,105 +19,135 @@ module CodeRay
register_for :terminal
TOKEN_COLORS = {
- :annotation => '35',
- :attribute_name => '33',
- :attribute_value => '31',
- :binary => '1;35',
+ :debug => "\e[1;37;44m",
+
+ :annotation => "\e[34m",
+ :attribute_name => "\e[35m",
+ :attribute_value => "\e[31m",
+ :binary => {
+ :self => "\e[31m",
+ :char => "\e[1;31m",
+ :delimiter => "\e[1;31m",
+ },
:char => {
- :self => '36', :delimiter => '1;34'
+ :self => "\e[35m",
+ :delimiter => "\e[1;35m"
+ },
+ :class => "\e[1;35;4m",
+ :class_variable => "\e[36m",
+ :color => "\e[32m",
+ :comment => {
+ :self => "\e[1;30m",
+ :char => "\e[37m",
+ :delimiter => "\e[37m",
},
- :class => '1;35',
- :class_variable => '36',
- :color => '32',
- :comment => '37',
- :complex => '1;34',
- :constant => ['1;34', '4'],
- :decoration => '35',
- :definition => '1;32',
- :directive => ['32', '4'],
- :doc => '46',
- :doctype => '1;30',
- :doc_string => ['31', '4'],
- :entity => '33',
- :error => ['1;33', '41'],
- :exception => '1;31',
- :float => '1;35',
- :function => '1;34',
- :global_variable => '42',
- :hex => '1;36',
- :include => '33',
- :integer => '1;34',
- :key => '35',
- :label => '1;15',
- :local_variable => '33',
- :octal => '1;35',
- :operator_name => '1;29',
- :predefined_constant => '1;36',
- :predefined_type => '1;30',
- :predefined => ['4', '1;34'],
- :preprocessor => '36',
- :pseudo_class => '1;34',
+ :constant => "\e[1;34;4m",
+ :decorator => "\e[35m",
+ :definition => "\e[1;33m",
+ :directive => "\e[33m",
+ :docstring => "\e[31m",
+ :doctype => "\e[1;34m",
+ :done => "\e[1;30;2m",
+ :entity => "\e[31m",
+ :error => "\e[1;37;41m",
+ :exception => "\e[1;31m",
+ :float => "\e[1;35m",
+ :function => "\e[1;34m",
+ :global_variable => "\e[1;32m",
+ :hex => "\e[1;36m",
+ :id => "\e[1;34m",
+ :include => "\e[31m",
+ :integer => "\e[1;34m",
+ :imaginary => "\e[1;34m",
+ :important => "\e[1;31m",
+ :key => {
+ :self => "\e[35m",
+ :char => "\e[1;35m",
+ :delimiter => "\e[1;35m",
+ },
+ :keyword => "\e[32m",
+ :label => "\e[1;33m",
+ :local_variable => "\e[33m",
+ :namespace => "\e[1;35m",
+ :octal => "\e[1;34m",
+ :predefined => "\e[36m",
+ :predefined_constant => "\e[1;36m",
+ :predefined_type => "\e[1;32m",
+ :preprocessor => "\e[1;36m",
+ :pseudo_class => "\e[1;34m",
:regexp => {
- :self => '31',
- :content => '31',
- :delimiter => '1;29',
- :modifier => '35',
+ :self => "\e[35m",
+ :delimiter => "\e[1;35m",
+ :modifier => "\e[35m",
+ :char => "\e[1;35m",
},
- :reserved => '1;31',
+ :reserved => "\e[32m",
:shell => {
- :self => '42',
- :content => '1;29',
- :delimiter => '37',
+ :self => "\e[33m",
+ :char => "\e[1;33m",
+ :delimiter => "\e[1;33m",
+ :escape => "\e[1;33m",
},
:string => {
- :self => '32',
- :modifier => '1;32',
- :escape => '1;36',
- :delimiter => '1;32',
- :char => '1;36',
+ :self => "\e[31m",
+ :modifier => "\e[1;31m",
+ :char => "\e[1;35m",
+ :delimiter => "\e[1;31m",
+ :escape => "\e[1;31m",
+ },
+ :symbol => {
+ :self => "\e[33m",
+ :delimiter => "\e[1;33m",
},
- :symbol => '1;32',
- :tag => '1;34',
- :type => '1;34',
- :value => '36',
- :variable => '1;34',
+ :tag => "\e[32m",
+ :type => "\e[1;34m",
+ :value => "\e[36m",
+ :variable => "\e[34m",
- :insert => '42',
- :delete => '41',
- :change => '44',
- :head => '45'
+ :insert => {
+ :self => "\e[42m",
+ :insert => "\e[1;32;42m",
+ :eyecatcher => "\e[102m",
+ },
+ :delete => {
+ :self => "\e[41m",
+ :delete => "\e[1;31;41m",
+ :eyecatcher => "\e[101m",
+ },
+ :change => {
+ :self => "\e[44m",
+ :change => "\e[37;44m",
+ },
+ :head => {
+ :self => "\e[45m",
+ :filename => "\e[37;45m"
+ },
}
+
TOKEN_COLORS[:keyword] = TOKEN_COLORS[:reserved]
TOKEN_COLORS[:method] = TOKEN_COLORS[:function]
- TOKEN_COLORS[:imaginary] = TOKEN_COLORS[:complex]
- TOKEN_COLORS[:begin_group] = TOKEN_COLORS[:end_group] =
- TOKEN_COLORS[:escape] = TOKEN_COLORS[:delimiter]
+ TOKEN_COLORS[:escape] = TOKEN_COLORS[:delimiter]
protected
def setup(options)
super
@opened = []
- @subcolors = nil
+ @color_scopes = [TOKEN_COLORS]
end
public
def text_token text, kind
- if color = (@subcolors || TOKEN_COLORS)[kind]
- if Hash === color
- if color[:self]
- color = color[:self]
- else
- @out << text
- return
- end
- end
+ if color = @color_scopes.last[kind]
+ color = color[:self] if color.is_a? Hash
- @out << ansi_colorize(color)
- @out << text.gsub("\n", ansi_clear + "\n" + ansi_colorize(color))
- @out << ansi_clear
- @out << ansi_colorize(@subcolors[:self]) if @subcolors && @subcolors[:self]
+ @out << color
+ @out << (text.index("\n") ? text.gsub("\n", "\e[0m\n" + color) : text)
+ @out << "\e[0m"
+ if outer_color = @color_scopes.last[:self]
+ @out << outer_color
+ end
else
@out << text
end
@@ -130,50 +160,36 @@ module CodeRay
alias begin_line begin_group
def end_group kind
- if @opened.empty?
- # nothing to close
- else
- @opened.pop
- @out << ansi_clear
- @out << open_token(@opened.last)
+ if @opened.pop
+ @color_scopes.pop
+ @out << "\e[0m"
+ if outer_color = @color_scopes.last[:self]
+ @out << outer_color
+ end
end
end
def end_line kind
- if @opened.empty?
- # nothing to close
- else
- @opened.pop
- # whole lines to be highlighted,
- # eg. added/modified/deleted lines in a diff
- @out << "\t" * 100 + ansi_clear
- @out << open_token(@opened.last)
- end
+ @out << (@line_filler ||= "\t" * 100)
+ end_group kind
end
private
def open_token kind
- if color = TOKEN_COLORS[kind]
- if Hash === color
- @subcolors = color
- ansi_colorize(color[:self]) if color[:self]
+ if color = @color_scopes.last[kind]
+ if color.is_a? Hash
+ @color_scopes << color
+ color[:self]
else
- @subcolors = {}
- ansi_colorize(color)
+ @color_scopes << @color_scopes.last
+ color
end
else
- @subcolors = nil
+ @color_scopes << @color_scopes.last
''
end
end
-
- def ansi_colorize(color)
- Array(color).map { |c| "\e[#{c}m" }.join
- end
- def ansi_clear
- ansi_colorize(0)
- end
end
end
-end \ No newline at end of file
+end