Chris@0: module CodeRay Chris@0: module Encoders Chris@0: Chris@0: class HTML Chris@0: Chris@0: module Output Chris@0: Chris@0: def numerize *args Chris@0: clone.numerize!(*args) Chris@0: end Chris@0: Chris@0: =begin NUMERIZABLE_WRAPPINGS = { Chris@0: :table => [:div, :page, nil], Chris@0: :inline => :all, Chris@0: :list => [:div, :page, nil] Chris@0: } Chris@0: NUMERIZABLE_WRAPPINGS.default = :all Chris@0: =end Chris@0: def numerize! mode = :table, options = {} Chris@0: return self unless mode Chris@0: Chris@0: options = DEFAULT_OPTIONS.merge options Chris@0: Chris@0: start = options[:line_number_start] Chris@0: unless start.is_a? Integer Chris@0: raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start Chris@0: end Chris@0: Chris@0: #allowed_wrappings = NUMERIZABLE_WRAPPINGS[mode] Chris@0: #unless allowed_wrappings == :all or allowed_wrappings.include? options[:wrap] Chris@0: # raise ArgumentError, "Can't numerize, :wrap must be in %p, but is %p" % [NUMERIZABLE_WRAPPINGS, options[:wrap]] Chris@0: #end Chris@0: Chris@0: bold_every = options[:bold_every] Chris@0: highlight_lines = options[:highlight_lines] Chris@0: bolding = Chris@0: if bold_every == false && highlight_lines == nil Chris@0: proc { |line| line.to_s } Chris@0: elsif highlight_lines.is_a? Enumerable Chris@0: highlight_lines = highlight_lines.to_set Chris@0: proc do |line| Chris@0: if highlight_lines.include? line Chris@0: "#{line}" # highlighted line numbers in bold Chris@0: else Chris@0: line.to_s Chris@0: end Chris@0: end Chris@0: elsif bold_every.is_a? Integer Chris@0: raise ArgumentError, ":bolding can't be 0." if bold_every == 0 Chris@0: proc do |line| Chris@0: if line % bold_every == 0 Chris@0: "#{line}" # every bold_every-th number in bold Chris@0: else Chris@0: line.to_s Chris@0: end Chris@0: end Chris@0: else Chris@0: raise ArgumentError, 'Invalid value %p for :bolding; false or Integer expected.' % bold_every Chris@0: end Chris@0: Chris@0: case mode Chris@0: when :inline Chris@0: max_width = (start + line_count).to_s.size Chris@0: line_number = start Chris@0: gsub!(/^/) do Chris@0: line_number_text = bolding.call line_number Chris@0: indent = ' ' * (max_width - line_number.to_s.size) # TODO: Optimize (10^x) Chris@0: res = "#{indent}#{line_number_text} " Chris@0: line_number += 1 Chris@0: res Chris@0: end Chris@0: Chris@0: when :table Chris@0: # This is really ugly. Chris@0: # Because even monospace fonts seem to have different heights when bold, Chris@0: # I make the newline bold, both in the code and the line numbers. Chris@0: # FIXME Still not working perfect for Mr. Internet Exploder Chris@0: line_numbers = (start ... start + line_count).to_a.map(&bolding).join("\n") Chris@0: line_numbers << "\n" # also for Mr. MS Internet Exploder :-/ Chris@0: line_numbers.gsub!(/\n/) { "\n" } Chris@0: Chris@0: line_numbers_table_tpl = TABLE.apply('LINE_NUMBERS', line_numbers) Chris@0: gsub!(/<\/div>\n/) { '' } Chris@0: gsub!(/\n/) { "\n" } Chris@0: wrap_in! line_numbers_table_tpl Chris@0: @wrapped_in = :div Chris@0: Chris@0: when :list Chris@0: opened_tags = [] Chris@0: gsub!(/^.*$\n?/) do |line| Chris@0: line.chomp! Chris@0: Chris@0: open = opened_tags.join Chris@0: line.scan(%r!<(/)?span[^>]*>?!) do |close,| Chris@0: if close Chris@0: opened_tags.pop Chris@0: else Chris@0: opened_tags << $& Chris@0: end Chris@0: end Chris@0: close = '' * opened_tags.size Chris@0: Chris@0: "