Chris@0
|
1 module CodeRay
|
Chris@0
|
2 module Encoders
|
Chris@0
|
3
|
Chris@0
|
4 class HTML
|
Chris@0
|
5
|
Chris@0
|
6 module Output
|
Chris@0
|
7
|
Chris@0
|
8 def numerize *args
|
Chris@0
|
9 clone.numerize!(*args)
|
Chris@0
|
10 end
|
Chris@0
|
11
|
Chris@0
|
12 =begin NUMERIZABLE_WRAPPINGS = {
|
Chris@0
|
13 :table => [:div, :page, nil],
|
Chris@0
|
14 :inline => :all,
|
Chris@0
|
15 :list => [:div, :page, nil]
|
Chris@0
|
16 }
|
Chris@0
|
17 NUMERIZABLE_WRAPPINGS.default = :all
|
Chris@0
|
18 =end
|
Chris@0
|
19 def numerize! mode = :table, options = {}
|
Chris@0
|
20 return self unless mode
|
Chris@0
|
21
|
Chris@0
|
22 options = DEFAULT_OPTIONS.merge options
|
Chris@0
|
23
|
Chris@0
|
24 start = options[:line_number_start]
|
Chris@0
|
25 unless start.is_a? Integer
|
Chris@0
|
26 raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start
|
Chris@0
|
27 end
|
Chris@0
|
28
|
Chris@0
|
29 #allowed_wrappings = NUMERIZABLE_WRAPPINGS[mode]
|
Chris@0
|
30 #unless allowed_wrappings == :all or allowed_wrappings.include? options[:wrap]
|
Chris@0
|
31 # raise ArgumentError, "Can't numerize, :wrap must be in %p, but is %p" % [NUMERIZABLE_WRAPPINGS, options[:wrap]]
|
Chris@0
|
32 #end
|
Chris@0
|
33
|
Chris@0
|
34 bold_every = options[:bold_every]
|
Chris@0
|
35 highlight_lines = options[:highlight_lines]
|
Chris@0
|
36 bolding =
|
Chris@0
|
37 if bold_every == false && highlight_lines == nil
|
Chris@0
|
38 proc { |line| line.to_s }
|
Chris@0
|
39 elsif highlight_lines.is_a? Enumerable
|
Chris@0
|
40 highlight_lines = highlight_lines.to_set
|
Chris@0
|
41 proc do |line|
|
Chris@0
|
42 if highlight_lines.include? line
|
Chris@0
|
43 "<strong class=\"highlighted\">#{line}</strong>" # highlighted line numbers in bold
|
Chris@0
|
44 else
|
Chris@0
|
45 line.to_s
|
Chris@0
|
46 end
|
Chris@0
|
47 end
|
Chris@0
|
48 elsif bold_every.is_a? Integer
|
Chris@0
|
49 raise ArgumentError, ":bolding can't be 0." if bold_every == 0
|
Chris@0
|
50 proc do |line|
|
Chris@0
|
51 if line % bold_every == 0
|
Chris@0
|
52 "<strong>#{line}</strong>" # every bold_every-th number in bold
|
Chris@0
|
53 else
|
Chris@0
|
54 line.to_s
|
Chris@0
|
55 end
|
Chris@0
|
56 end
|
Chris@0
|
57 else
|
Chris@0
|
58 raise ArgumentError, 'Invalid value %p for :bolding; false or Integer expected.' % bold_every
|
Chris@0
|
59 end
|
Chris@0
|
60
|
Chris@0
|
61 case mode
|
Chris@0
|
62 when :inline
|
Chris@0
|
63 max_width = (start + line_count).to_s.size
|
Chris@0
|
64 line_number = start
|
Chris@0
|
65 gsub!(/^/) do
|
Chris@0
|
66 line_number_text = bolding.call line_number
|
Chris@0
|
67 indent = ' ' * (max_width - line_number.to_s.size) # TODO: Optimize (10^x)
|
Chris@0
|
68 res = "<span class=\"no\">#{indent}#{line_number_text}</span> "
|
Chris@0
|
69 line_number += 1
|
Chris@0
|
70 res
|
Chris@0
|
71 end
|
Chris@0
|
72
|
Chris@0
|
73 when :table
|
Chris@0
|
74 # This is really ugly.
|
Chris@0
|
75 # Because even monospace fonts seem to have different heights when bold,
|
Chris@0
|
76 # I make the newline bold, both in the code and the line numbers.
|
Chris@0
|
77 # FIXME Still not working perfect for Mr. Internet Exploder
|
Chris@0
|
78 line_numbers = (start ... start + line_count).to_a.map(&bolding).join("\n")
|
Chris@0
|
79 line_numbers << "\n" # also for Mr. MS Internet Exploder :-/
|
Chris@0
|
80 line_numbers.gsub!(/\n/) { "<tt>\n</tt>" }
|
Chris@0
|
81
|
Chris@0
|
82 line_numbers_table_tpl = TABLE.apply('LINE_NUMBERS', line_numbers)
|
Chris@0
|
83 gsub!(/<\/div>\n/) { '</div>' }
|
Chris@0
|
84 gsub!(/\n/) { "<tt>\n</tt>" }
|
Chris@0
|
85 wrap_in! line_numbers_table_tpl
|
Chris@0
|
86 @wrapped_in = :div
|
Chris@0
|
87
|
Chris@0
|
88 when :list
|
Chris@0
|
89 opened_tags = []
|
Chris@0
|
90 gsub!(/^.*$\n?/) do |line|
|
Chris@0
|
91 line.chomp!
|
Chris@0
|
92
|
Chris@0
|
93 open = opened_tags.join
|
Chris@0
|
94 line.scan(%r!<(/)?span[^>]*>?!) do |close,|
|
Chris@0
|
95 if close
|
Chris@0
|
96 opened_tags.pop
|
Chris@0
|
97 else
|
Chris@0
|
98 opened_tags << $&
|
Chris@0
|
99 end
|
Chris@0
|
100 end
|
Chris@0
|
101 close = '</span>' * opened_tags.size
|
Chris@0
|
102
|
Chris@0
|
103 "<li>#{open}#{line}#{close}</li>\n"
|
Chris@0
|
104 end
|
Chris@0
|
105 chomp!("\n")
|
Chris@0
|
106 wrap_in! LIST
|
Chris@0
|
107 @wrapped_in = :div
|
Chris@0
|
108
|
Chris@0
|
109 else
|
Chris@0
|
110 raise ArgumentError, 'Unknown value %p for mode: expected one of %p' %
|
Chris@0
|
111 [mode, [:table, :list, :inline]]
|
Chris@0
|
112 end
|
Chris@0
|
113
|
Chris@0
|
114 self
|
Chris@0
|
115 end
|
Chris@0
|
116
|
Chris@0
|
117 def line_count
|
Chris@0
|
118 line_count = count("\n")
|
Chris@0
|
119 position_of_last_newline = rindex(?\n)
|
Chris@0
|
120 if position_of_last_newline
|
Chris@0
|
121 after_last_newline = self[position_of_last_newline + 1 .. -1]
|
Chris@0
|
122 ends_with_newline = after_last_newline[/\A(?:<\/span>)*\z/]
|
Chris@0
|
123 line_count += 1 if not ends_with_newline
|
Chris@0
|
124 end
|
Chris@0
|
125 line_count
|
Chris@0
|
126 end
|
Chris@0
|
127
|
Chris@0
|
128 end
|
Chris@0
|
129
|
Chris@0
|
130 end
|
Chris@0
|
131
|
Chris@0
|
132 end
|
Chris@0
|
133 end
|