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