Chris@909
|
1 module CodeRay
|
Chris@909
|
2 module Encoders
|
Chris@909
|
3
|
Chris@909
|
4 class HTML
|
Chris@909
|
5
|
Chris@909
|
6 module Numbering # :nodoc:
|
Chris@909
|
7
|
Chris@909
|
8 def self.number! output, mode = :table, options = {}
|
Chris@909
|
9 return self unless mode
|
Chris@909
|
10
|
Chris@909
|
11 options = DEFAULT_OPTIONS.merge options
|
Chris@909
|
12
|
Chris@909
|
13 start = options[:line_number_start]
|
Chris@909
|
14 unless start.is_a? Integer
|
Chris@909
|
15 raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start
|
Chris@909
|
16 end
|
Chris@909
|
17
|
Chris@909
|
18 anchor_prefix = options[:line_number_anchors]
|
Chris@909
|
19 anchor_prefix = 'line' if anchor_prefix == true
|
Chris@909
|
20 anchor_prefix = anchor_prefix.to_s[/\w+/] if anchor_prefix
|
Chris@909
|
21 anchoring =
|
Chris@909
|
22 if anchor_prefix
|
Chris@909
|
23 proc do |line|
|
Chris@909
|
24 line = line.to_s
|
Chris@909
|
25 anchor = anchor_prefix + line
|
Chris@909
|
26 "<a href=\"##{anchor}\" name=\"#{anchor}\">#{line}</a>"
|
Chris@909
|
27 end
|
Chris@909
|
28 else
|
Chris@909
|
29 proc { |line| line.to_s } # :to_s.to_proc in Ruby 1.8.7+
|
Chris@909
|
30 end
|
Chris@909
|
31
|
Chris@909
|
32 bold_every = options[:bold_every]
|
Chris@909
|
33 highlight_lines = options[:highlight_lines]
|
Chris@909
|
34 bolding =
|
Chris@909
|
35 if bold_every == false && highlight_lines == nil
|
Chris@909
|
36 anchoring
|
Chris@909
|
37 elsif highlight_lines.is_a? Enumerable
|
Chris@909
|
38 highlight_lines = highlight_lines.to_set
|
Chris@909
|
39 proc do |line|
|
Chris@909
|
40 if highlight_lines.include? line
|
Chris@909
|
41 "<strong class=\"highlighted\">#{anchoring[line]}</strong>" # highlighted line numbers in bold
|
Chris@909
|
42 else
|
Chris@909
|
43 anchoring[line]
|
Chris@909
|
44 end
|
Chris@909
|
45 end
|
Chris@909
|
46 elsif bold_every.is_a? Integer
|
Chris@909
|
47 raise ArgumentError, ":bolding can't be 0." if bold_every == 0
|
Chris@909
|
48 proc do |line|
|
Chris@909
|
49 if line % bold_every == 0
|
Chris@909
|
50 "<strong>#{anchoring[line]}</strong>" # every bold_every-th number in bold
|
Chris@909
|
51 else
|
Chris@909
|
52 anchoring[line]
|
Chris@909
|
53 end
|
Chris@909
|
54 end
|
Chris@909
|
55 else
|
Chris@909
|
56 raise ArgumentError, 'Invalid value %p for :bolding; false or Integer expected.' % bold_every
|
Chris@909
|
57 end
|
Chris@909
|
58
|
Chris@909
|
59 line_count = output.count("\n")
|
Chris@909
|
60 position_of_last_newline = output.rindex(RUBY_VERSION >= '1.9' ? /\n/ : ?\n)
|
Chris@909
|
61 if position_of_last_newline
|
Chris@909
|
62 after_last_newline = output[position_of_last_newline + 1 .. -1]
|
Chris@909
|
63 ends_with_newline = after_last_newline[/\A(?:<\/span>)*\z/]
|
Chris@909
|
64 line_count += 1 if not ends_with_newline
|
Chris@909
|
65 end
|
Chris@909
|
66
|
Chris@909
|
67 case mode
|
Chris@909
|
68 when :inline
|
Chris@909
|
69 max_width = (start + line_count).to_s.size
|
Chris@909
|
70 line_number = start
|
Chris@909
|
71 nesting = []
|
Chris@909
|
72 output.gsub!(/^.*$\n?/) do |line|
|
Chris@909
|
73 line.chomp!
|
Chris@909
|
74 open = nesting.join
|
Chris@909
|
75 line.scan(%r!<(/)?span[^>]*>?!) do |close,|
|
Chris@909
|
76 if close
|
Chris@909
|
77 nesting.pop
|
Chris@909
|
78 else
|
Chris@909
|
79 nesting << $&
|
Chris@909
|
80 end
|
Chris@909
|
81 end
|
Chris@909
|
82 close = '</span>' * nesting.size
|
Chris@909
|
83
|
Chris@909
|
84 line_number_text = bolding.call line_number
|
Chris@909
|
85 indent = ' ' * (max_width - line_number.to_s.size) # TODO: Optimize (10^x)
|
Chris@909
|
86 line_number += 1
|
Chris@909
|
87 "<span class=\"line-numbers\">#{indent}#{line_number_text}</span>#{open}#{line}#{close}\n"
|
Chris@909
|
88 end
|
Chris@909
|
89
|
Chris@909
|
90 when :table
|
Chris@909
|
91 line_numbers = (start ... start + line_count).map(&bolding).join("\n")
|
Chris@909
|
92 line_numbers << "\n"
|
Chris@909
|
93 line_numbers_table_template = Output::TABLE.apply('LINE_NUMBERS', line_numbers)
|
Chris@909
|
94
|
Chris@909
|
95 output.gsub!(/<\/div>\n/, '</div>')
|
Chris@909
|
96 output.wrap_in! line_numbers_table_template
|
Chris@909
|
97 output.wrapped_in = :div
|
Chris@909
|
98
|
Chris@909
|
99 when :list
|
Chris@909
|
100 raise NotImplementedError, 'The :list option is no longer available. Use :table.'
|
Chris@909
|
101
|
Chris@909
|
102 else
|
Chris@909
|
103 raise ArgumentError, 'Unknown value %p for mode: expected one of %p' %
|
Chris@909
|
104 [mode, [:table, :inline]]
|
Chris@909
|
105 end
|
Chris@909
|
106
|
Chris@909
|
107 output
|
Chris@909
|
108 end
|
Chris@909
|
109
|
Chris@909
|
110 end
|
Chris@909
|
111
|
Chris@909
|
112 end
|
Chris@909
|
113
|
Chris@909
|
114 end
|
Chris@909
|
115 end
|