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