Mercurial > hg > soundsoftware-site
comparison vendor/gems/coderay-0.9.7/lib/coderay/encoders/.svn/text-base/html.rb.svn-base @ 210:0579821a129a
Update to Redmine trunk rev 4802
author | Chris Cannam |
---|---|
date | Tue, 08 Feb 2011 13:51:46 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
128:07fa8a8b56a8 | 210:0579821a129a |
---|---|
1 require 'set' | |
2 | |
3 module CodeRay | |
4 module Encoders | |
5 | |
6 # = HTML Encoder | |
7 # | |
8 # This is CodeRay's most important highlighter: | |
9 # It provides save, fast XHTML generation and CSS support. | |
10 # | |
11 # == Usage | |
12 # | |
13 # require 'coderay' | |
14 # puts CodeRay.scan('Some /code/', :ruby).html #-> a HTML page | |
15 # puts CodeRay.scan('Some /code/', :ruby).html(:wrap => :span) | |
16 # #-> <span class="CodeRay"><span class="co">Some</span> /code/</span> | |
17 # puts CodeRay.scan('Some /code/', :ruby).span #-> the same | |
18 # | |
19 # puts CodeRay.scan('Some code', :ruby).html( | |
20 # :wrap => nil, | |
21 # :line_numbers => :inline, | |
22 # :css => :style | |
23 # ) | |
24 # #-> <span class="no">1</span> <span style="color:#036; font-weight:bold;">Some</span> code | |
25 # | |
26 # == Options | |
27 # | |
28 # === :tab_width | |
29 # Convert \t characters to +n+ spaces (a number.) | |
30 # Default: 8 | |
31 # | |
32 # === :css | |
33 # How to include the styles; can be :class or :style. | |
34 # | |
35 # Default: :class | |
36 # | |
37 # === :wrap | |
38 # Wrap in :page, :div, :span or nil. | |
39 # | |
40 # You can also use Encoders::Div and Encoders::Span. | |
41 # | |
42 # Default: nil | |
43 # | |
44 # === :title | |
45 # | |
46 # The title of the HTML page (works only when :wrap is set to :page.) | |
47 # | |
48 # Default: 'CodeRay output' | |
49 # | |
50 # === :line_numbers | |
51 # Include line numbers in :table, :inline, :list or nil (no line numbers) | |
52 # | |
53 # Default: nil | |
54 # | |
55 # === :line_number_start | |
56 # Where to start with line number counting. | |
57 # | |
58 # Default: 1 | |
59 # | |
60 # === :bold_every | |
61 # Make every +n+-th number appear bold. | |
62 # | |
63 # Default: 10 | |
64 # | |
65 # === :highlight_lines | |
66 # | |
67 # Highlights certain line numbers. | |
68 # Can be any Enumerable, typically just an Array or Range, of numbers. | |
69 # | |
70 # Bolding is deactivated when :highlight_lines is set. It only makes sense | |
71 # in combination with :line_numbers. | |
72 # | |
73 # Default: nil | |
74 # | |
75 # === :hint | |
76 # Include some information into the output using the title attribute. | |
77 # Can be :info (show token type on mouse-over), :info_long (with full path) | |
78 # or :debug (via inspect). | |
79 # | |
80 # Default: false | |
81 class HTML < Encoder | |
82 | |
83 include Streamable | |
84 register_for :html | |
85 | |
86 FILE_EXTENSION = 'html' | |
87 | |
88 DEFAULT_OPTIONS = { | |
89 :tab_width => 8, | |
90 | |
91 :css => :class, | |
92 | |
93 :style => :cycnus, | |
94 :wrap => nil, | |
95 :title => 'CodeRay output', | |
96 | |
97 :line_numbers => nil, | |
98 :line_number_start => 1, | |
99 :bold_every => 10, | |
100 :highlight_lines => nil, | |
101 | |
102 :hint => false, | |
103 } | |
104 | |
105 helper :output, :css | |
106 | |
107 attr_reader :css | |
108 | |
109 protected | |
110 | |
111 HTML_ESCAPE = { #:nodoc: | |
112 '&' => '&', | |
113 '"' => '"', | |
114 '>' => '>', | |
115 '<' => '<', | |
116 } | |
117 | |
118 # This was to prevent illegal HTML. | |
119 # Strange chars should still be avoided in codes. | |
120 evil_chars = Array(0x00...0x20) - [?\n, ?\t, ?\s] | |
121 evil_chars.each { |i| HTML_ESCAPE[i.chr] = ' ' } | |
122 #ansi_chars = Array(0x7f..0xff) | |
123 #ansi_chars.each { |i| HTML_ESCAPE[i.chr] = '&#%d;' % i } | |
124 # \x9 (\t) and \xA (\n) not included | |
125 #HTML_ESCAPE_PATTERN = /[\t&"><\0-\x8\xB-\x1f\x7f-\xff]/ | |
126 HTML_ESCAPE_PATTERN = /[\t"&><\0-\x8\xB-\x1f]/ | |
127 | |
128 TOKEN_KIND_TO_INFO = Hash.new { |h, kind| | |
129 h[kind] = | |
130 case kind | |
131 when :pre_constant | |
132 'Predefined constant' | |
133 else | |
134 kind.to_s.gsub(/_/, ' ').gsub(/\b\w/) { $&.capitalize } | |
135 end | |
136 } | |
137 | |
138 TRANSPARENT_TOKEN_KINDS = [ | |
139 :delimiter, :modifier, :content, :escape, :inline_delimiter, | |
140 ].to_set | |
141 | |
142 # Generate a hint about the given +classes+ in a +hint+ style. | |
143 # | |
144 # +hint+ may be :info, :info_long or :debug. | |
145 def self.token_path_to_hint hint, classes | |
146 title = | |
147 case hint | |
148 when :info | |
149 TOKEN_KIND_TO_INFO[classes.first] | |
150 when :info_long | |
151 classes.reverse.map { |kind| TOKEN_KIND_TO_INFO[kind] }.join('/') | |
152 when :debug | |
153 classes.inspect | |
154 end | |
155 title ? " title=\"#{title}\"" : '' | |
156 end | |
157 | |
158 def setup options | |
159 super | |
160 | |
161 @HTML_ESCAPE = HTML_ESCAPE.dup | |
162 @HTML_ESCAPE["\t"] = ' ' * options[:tab_width] | |
163 | |
164 @opened = [nil] | |
165 @css = CSS.new options[:style] | |
166 | |
167 hint = options[:hint] | |
168 if hint and not [:debug, :info, :info_long].include? hint | |
169 raise ArgumentError, "Unknown value %p for :hint; \ | |
170 expected :info, :debug, false, or nil." % hint | |
171 end | |
172 | |
173 case options[:css] | |
174 | |
175 when :class | |
176 @css_style = Hash.new do |h, k| | |
177 c = CodeRay::Tokens::ClassOfKind[k.first] | |
178 if c == :NO_HIGHLIGHT and not hint | |
179 h[k.dup] = false | |
180 else | |
181 title = if hint | |
182 HTML.token_path_to_hint(hint, k[1..-1] << k.first) | |
183 else | |
184 '' | |
185 end | |
186 if c == :NO_HIGHLIGHT | |
187 h[k.dup] = '<span%s>' % [title] | |
188 else | |
189 h[k.dup] = '<span%s class="%s">' % [title, c] | |
190 end | |
191 end | |
192 end | |
193 | |
194 when :style | |
195 @css_style = Hash.new do |h, k| | |
196 if k.is_a? ::Array | |
197 styles = k.dup | |
198 else | |
199 styles = [k] | |
200 end | |
201 type = styles.first | |
202 classes = styles.map { |c| Tokens::ClassOfKind[c] } | |
203 if classes.first == :NO_HIGHLIGHT and not hint | |
204 h[k] = false | |
205 else | |
206 styles.shift if TRANSPARENT_TOKEN_KINDS.include? styles.first | |
207 title = HTML.token_path_to_hint hint, styles | |
208 style = @css[*classes] | |
209 h[k] = | |
210 if style | |
211 '<span%s style="%s">' % [title, style] | |
212 else | |
213 false | |
214 end | |
215 end | |
216 end | |
217 | |
218 else | |
219 raise ArgumentError, "Unknown value %p for :css." % options[:css] | |
220 | |
221 end | |
222 end | |
223 | |
224 def finish options | |
225 not_needed = @opened.shift | |
226 @out << '</span>' * @opened.size | |
227 unless @opened.empty? | |
228 warn '%d tokens still open: %p' % [@opened.size, @opened] | |
229 end | |
230 | |
231 @out.extend Output | |
232 @out.css = @css | |
233 @out.numerize! options[:line_numbers], options | |
234 @out.wrap! options[:wrap] | |
235 @out.apply_title! options[:title] | |
236 | |
237 super | |
238 end | |
239 | |
240 def token text, type = :plain | |
241 case text | |
242 | |
243 when nil | |
244 # raise 'Token with nil as text was given: %p' % [[text, type]] | |
245 | |
246 when String | |
247 if text =~ /#{HTML_ESCAPE_PATTERN}/o | |
248 text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] } | |
249 end | |
250 @opened[0] = type | |
251 if text != "\n" && style = @css_style[@opened] | |
252 @out << style << text << '</span>' | |
253 else | |
254 @out << text | |
255 end | |
256 | |
257 | |
258 # token groups, eg. strings | |
259 when :open | |
260 @opened[0] = type | |
261 @out << (@css_style[@opened] || '<span>') | |
262 @opened << type | |
263 when :close | |
264 if @opened.empty? | |
265 # nothing to close | |
266 else | |
267 if $CODERAY_DEBUG and (@opened.size == 1 or @opened.last != type) | |
268 raise 'Malformed token stream: Trying to close a token (%p) \ | |
269 that is not open. Open are: %p.' % [type, @opened[1..-1]] | |
270 end | |
271 @out << '</span>' | |
272 @opened.pop | |
273 end | |
274 | |
275 # whole lines to be highlighted, eg. a deleted line in a diff | |
276 when :begin_line | |
277 @opened[0] = type | |
278 if style = @css_style[@opened] | |
279 if style['class="'] | |
280 @out << style.sub('class="', 'class="line ') | |
281 else | |
282 @out << style.sub('>', ' class="line">') | |
283 end | |
284 else | |
285 @out << '<span class="line">' | |
286 end | |
287 @opened << type | |
288 when :end_line | |
289 if @opened.empty? | |
290 # nothing to close | |
291 else | |
292 if $CODERAY_DEBUG and (@opened.size == 1 or @opened.last != type) | |
293 raise 'Malformed token stream: Trying to close a line (%p) \ | |
294 that is not open. Open are: %p.' % [type, @opened[1..-1]] | |
295 end | |
296 @out << '</span>' | |
297 @opened.pop | |
298 end | |
299 | |
300 else | |
301 raise 'unknown token kind: %p' % [text] | |
302 | |
303 end | |
304 end | |
305 | |
306 end | |
307 | |
308 end | |
309 end |