summaryrefslogtreecommitdiff
path: root/lib/coderay/encoders/html/numerization.rb
blob: 1e1f95267431f19435d54e5860815d9a233ebb7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
module CodeRay
module Encoders

	class HTML
		
		module Output

			def numerize *args
				clone.numerize!(*args)
			end

=begin			NUMERIZABLE_WRAPPINGS = {
				:table => [:div, :page, nil],
				:inline => :all,
				:list => [:div, :page, nil]
			}
			NUMERIZABLE_WRAPPINGS.default = :all
=end			
			def numerize! mode = :table, options = {}
				return self unless mode

				options = DEFAULT_OPTIONS.merge options

				start = options[:line_number_start]
				unless start.is_a? Integer
					raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start
				end
				
				#allowed_wrappings = NUMERIZABLE_WRAPPINGS[mode]
				#unless allowed_wrappings == :all or allowed_wrappings.include? options[:wrap]
				#	raise ArgumentError, "Can't numerize, :wrap must be in %p, but is %p" % [NUMERIZABLE_WRAPPINGS, options[:wrap]]
				#end
				
				bold_every = options[:bold_every]
				bolding = 
					if bold_every == false
						proc { |line| line.to_s }
					elsif bold_every.is_a? Integer
						raise ArgumentError, ":bolding can't be 0." if bold_every == 0
						proc do |line|
							if line % bold_every == 0
								"<strong>#{line}</strong>"  # every bold_every-th number in bold
							else
								line.to_s
							end
						end
					else
						raise ArgumentError, 'Invalid value %p for :bolding; false or Integer expected.' % bold_every
					end
				
				case mode				
				when :inline
					max_width = (start + line_count).to_s.size
					line = start
					gsub!(/^/) do
						line_number = bolding.call line
						indent = ' ' * (max_width - line.to_s.size)
						res = "<span class=\"no\">#{indent}#{line_number}</span> "
						line += 1
						res
					end
					
				when :table
					# This is really ugly.
					# Because even monospace fonts seem to have different heights when bold, 
					# I make the newline bold, both in the code and the line numbers.
					# FIXME Still not working perfect for Mr. Internet Exploder
					# FIXME Firefox struggles with very long codes (> 200 lines)
					line_numbers = (start ... start + line_count).to_a.map(&bolding).join("\n")
					line_numbers << "\n"  # also for Mr. MS Internet Exploder :-/
					line_numbers.gsub!(/\n/) { "<tt>\n</tt>" }
					
					line_numbers_table_tpl = TABLE.apply('LINE_NUMBERS', line_numbers)
					gsub!(/\n/) { "<tt>\n</tt>" }
					wrap_in! line_numbers_table_tpl
					@wrapped_in = :div
					
				when :list
					opened_tags = []
					gsub!(/^.*$\n?/) do |line|
						line.chomp!
						
						open = opened_tags.join
						line.scan(%r!<(/)?span[^>]*>?!) do |close,|
							if close
								opened_tags.pop
							else
								opened_tags << $&
							end
						end
						close = '</span>' * opened_tags.size
						
						"<li>#{open}#{line}#{close}</li>"
					end
					wrap_in! LIST
					@wrapped_in = :div
					
				else
					raise ArgumentError, 'Unknown value %p for mode: expected one of %p' %
						[mode, [:table, :list, :inline]]
				end

				self
			end

			def line_count
				line_count = count("\n")
				position_of_last_newline = rindex(?\n)
				if position_of_last_newline
					after_last_newline = self[position_of_last_newline + 1 .. -1]
					ends_with_newline = after_last_newline[/\A(?:<\/span>)*\z/]
					line_count += 1 if not ends_with_newline
				end
				line_count
			end

		end

	end

end
end