coderay 0.9.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. data/{lib/README → README_INDEX.rdoc} +10 -21
  2. data/Rakefile +6 -6
  3. data/bin/coderay +193 -64
  4. data/lib/coderay.rb +61 -105
  5. data/lib/coderay/duo.rb +17 -21
  6. data/lib/coderay/encoder.rb +100 -112
  7. data/lib/coderay/encoders/_map.rb +12 -7
  8. data/lib/coderay/encoders/comment_filter.rb +12 -30
  9. data/lib/coderay/encoders/count.rb +29 -11
  10. data/lib/coderay/encoders/debug.rb +32 -20
  11. data/lib/coderay/encoders/div.rb +13 -9
  12. data/lib/coderay/encoders/filter.rb +34 -51
  13. data/lib/coderay/encoders/html.rb +155 -161
  14. data/lib/coderay/encoders/html/css.rb +4 -9
  15. data/lib/coderay/encoders/html/numbering.rb +115 -0
  16. data/lib/coderay/encoders/html/output.rb +22 -70
  17. data/lib/coderay/encoders/json.rb +59 -45
  18. data/lib/coderay/encoders/lines_of_code.rb +12 -57
  19. data/lib/coderay/encoders/null.rb +6 -14
  20. data/lib/coderay/encoders/page.rb +13 -9
  21. data/lib/coderay/encoders/span.rb +13 -9
  22. data/lib/coderay/encoders/statistic.rb +58 -39
  23. data/lib/coderay/encoders/terminal.rb +179 -0
  24. data/lib/coderay/encoders/text.rb +31 -17
  25. data/lib/coderay/encoders/token_kind_filter.rb +111 -0
  26. data/lib/coderay/encoders/xml.rb +19 -18
  27. data/lib/coderay/encoders/yaml.rb +37 -9
  28. data/lib/coderay/for_redcloth.rb +4 -4
  29. data/lib/coderay/helpers/file_type.rb +127 -246
  30. data/lib/coderay/helpers/gzip.rb +41 -0
  31. data/lib/coderay/helpers/plugin.rb +241 -306
  32. data/lib/coderay/helpers/word_list.rb +65 -126
  33. data/lib/coderay/scanner.rb +173 -156
  34. data/lib/coderay/scanners/_map.rb +18 -17
  35. data/lib/coderay/scanners/c.rb +63 -77
  36. data/lib/coderay/scanners/clojure.rb +217 -0
  37. data/lib/coderay/scanners/cpp.rb +71 -84
  38. data/lib/coderay/scanners/css.rb +103 -120
  39. data/lib/coderay/scanners/debug.rb +47 -44
  40. data/lib/coderay/scanners/delphi.rb +70 -76
  41. data/lib/coderay/scanners/diff.rb +141 -50
  42. data/lib/coderay/scanners/erb.rb +81 -0
  43. data/lib/coderay/scanners/groovy.rb +104 -113
  44. data/lib/coderay/scanners/haml.rb +168 -0
  45. data/lib/coderay/scanners/html.rb +181 -110
  46. data/lib/coderay/scanners/java.rb +73 -75
  47. data/lib/coderay/scanners/java/builtin_types.rb +2 -0
  48. data/lib/coderay/scanners/java_script.rb +90 -101
  49. data/lib/coderay/scanners/json.rb +40 -53
  50. data/lib/coderay/scanners/php.rb +123 -147
  51. data/lib/coderay/scanners/python.rb +93 -91
  52. data/lib/coderay/scanners/raydebug.rb +66 -0
  53. data/lib/coderay/scanners/ruby.rb +343 -326
  54. data/lib/coderay/scanners/ruby/patterns.rb +40 -106
  55. data/lib/coderay/scanners/ruby/string_state.rb +71 -0
  56. data/lib/coderay/scanners/sql.rb +80 -66
  57. data/lib/coderay/scanners/text.rb +26 -0
  58. data/lib/coderay/scanners/xml.rb +1 -1
  59. data/lib/coderay/scanners/yaml.rb +74 -73
  60. data/lib/coderay/style.rb +10 -7
  61. data/lib/coderay/styles/_map.rb +3 -3
  62. data/lib/coderay/styles/alpha.rb +143 -0
  63. data/lib/coderay/token_kinds.rb +90 -0
  64. data/lib/coderay/tokens.rb +102 -277
  65. data/lib/coderay/tokens_proxy.rb +55 -0
  66. data/lib/coderay/version.rb +3 -0
  67. data/test/functional/basic.rb +200 -18
  68. data/test/functional/examples.rb +130 -0
  69. data/test/functional/for_redcloth.rb +15 -8
  70. data/test/functional/suite.rb +9 -6
  71. metadata +103 -123
  72. data/FOLDERS +0 -53
  73. data/bin/coderay_stylesheet +0 -4
  74. data/lib/coderay/encoders/html/numerization.rb +0 -133
  75. data/lib/coderay/encoders/term.rb +0 -158
  76. data/lib/coderay/encoders/token_class_filter.rb +0 -84
  77. data/lib/coderay/helpers/gzip_simple.rb +0 -123
  78. data/lib/coderay/scanners/nitro_xhtml.rb +0 -136
  79. data/lib/coderay/scanners/plaintext.rb +0 -20
  80. data/lib/coderay/scanners/rhtml.rb +0 -78
  81. data/lib/coderay/scanners/scheme.rb +0 -145
  82. data/lib/coderay/styles/cycnus.rb +0 -152
  83. data/lib/coderay/styles/murphy.rb +0 -134
  84. data/lib/coderay/token_classes.rb +0 -86
  85. data/test/functional/load_plugin_scanner.rb +0 -11
  86. data/test/functional/vhdl.rb +0 -126
  87. data/test/functional/word_list.rb +0 -79
@@ -0,0 +1,81 @@
1
+ module CodeRay
2
+ module Scanners
3
+
4
+ load :html
5
+ load :ruby
6
+
7
+ # Scanner for HTML ERB templates.
8
+ class ERB < Scanner
9
+
10
+ register_for :erb
11
+ title 'HTML ERB Template'
12
+
13
+ KINDS_NOT_LOC = HTML::KINDS_NOT_LOC
14
+
15
+ ERB_RUBY_BLOCK = /
16
+ (<%(?!%)[-=\#]?)
17
+ ((?>
18
+ [^\-%]* # normal*
19
+ (?> # special
20
+ (?: %(?!>) | -(?!%>) )
21
+ [^\-%]* # normal*
22
+ )*
23
+ ))
24
+ ((?: -?%> )?)
25
+ /x # :nodoc:
26
+
27
+ START_OF_ERB = /
28
+ <%(?!%)
29
+ /x # :nodoc:
30
+
31
+ protected
32
+
33
+ def setup
34
+ @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true
35
+ @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true
36
+ end
37
+
38
+ def reset_instance
39
+ super
40
+ @html_scanner.reset
41
+ end
42
+
43
+ def scan_tokens encoder, options
44
+
45
+ until eos?
46
+
47
+ if (match = scan_until(/(?=#{START_OF_ERB})/o) || scan_rest) and not match.empty?
48
+ @html_scanner.tokenize match, :tokens => encoder
49
+
50
+ elsif match = scan(/#{ERB_RUBY_BLOCK}/o)
51
+ start_tag = self[1]
52
+ code = self[2]
53
+ end_tag = self[3]
54
+
55
+ encoder.begin_group :inline
56
+ encoder.text_token start_tag, :inline_delimiter
57
+
58
+ if start_tag == '<%#'
59
+ encoder.text_token code, :comment
60
+ else
61
+ @ruby_scanner.tokenize code, :tokens => encoder
62
+ end unless code.empty?
63
+
64
+ encoder.text_token end_tag, :inline_delimiter unless end_tag.empty?
65
+ encoder.end_group :inline
66
+
67
+ else
68
+ raise_inspect 'else-case reached!', encoder
69
+
70
+ end
71
+
72
+ end
73
+
74
+ encoder
75
+
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+ end
@@ -1,29 +1,29 @@
1
1
  module CodeRay
2
2
  module Scanners
3
-
3
+
4
4
  load :java
5
-
5
+
6
+ # Scanner for Groovy.
6
7
  class Groovy < Java
7
-
8
- include Streamable
8
+
9
9
  register_for :groovy
10
10
 
11
- # TODO: Check this!
11
+ # TODO: check list of keywords
12
12
  GROOVY_KEYWORDS = %w[
13
13
  as assert def in
14
- ]
14
+ ] # :nodoc:
15
15
  KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[
16
16
  case instanceof new return throw typeof while as assert in
17
- ]
18
- GROOVY_MAGIC_VARIABLES = %w[ it ]
17
+ ] # :nodoc:
18
+ GROOVY_MAGIC_VARIABLES = %w[ it ] # :nodoc:
19
19
 
20
20
  IDENT_KIND = Java::IDENT_KIND.dup.
21
21
  add(GROOVY_KEYWORDS, :keyword).
22
- add(GROOVY_MAGIC_VARIABLES, :local_variable)
22
+ add(GROOVY_MAGIC_VARIABLES, :local_variable) # :nodoc:
23
23
 
24
- ESCAPE = / [bfnrtv$\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
25
- UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # no 4-byte unicode chars? U[a-fA-F0-9]{8}
26
- REGEXP_ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | \d | [bBdDsSwW\/] /x
24
+ ESCAPE = / [bfnrtv$\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc:
25
+ UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # :nodoc: no 4-byte unicode chars? U[a-fA-F0-9]{8}
26
+ REGEXP_ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | \d | [bBdDsSwW\/] /x # :nodoc:
27
27
 
28
28
  # TODO: interpretation inside ', ", /
29
29
  STRING_CONTENT_PATTERN = {
@@ -32,45 +32,44 @@ module Scanners
32
32
  "'''" => /(?>[^\\']+|'(?!''))+/,
33
33
  '"""' => /(?>[^\\$"]+|"(?!""))+/,
34
34
  '/' => /[^\\$\/\n]+/,
35
- }
35
+ } # :nodoc:
36
+
37
+ protected
36
38
 
37
- def scan_tokens tokens, options
38
-
39
+ def scan_tokens encoder, options
40
+
39
41
  state = :initial
40
42
  inline_block_stack = []
41
43
  inline_block_paren_depth = nil
42
44
  string_delimiter = nil
43
45
  import_clause = class_name_follows = last_token = after_def = false
44
46
  value_expected = true
45
-
47
+
46
48
  until eos?
47
-
48
- kind = nil
49
- match = nil
50
49
 
51
50
  case state
52
-
51
+
53
52
  when :initial
54
-
53
+
55
54
  if match = scan(/ \s+ | \\\n /x)
56
- tokens << [match, :space]
55
+ encoder.text_token match, :space
57
56
  if match.index ?\n
58
57
  import_clause = after_def = false
59
58
  value_expected = true unless value_expected
60
59
  end
61
60
  next
62
61
 
63
- elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
62
+ elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
64
63
  value_expected = true
65
64
  after_def = false
66
- kind = :comment
65
+ encoder.text_token match, :comment
67
66
 
68
- elsif bol? && scan(/ \#!.* /x)
69
- kind = :doctype
67
+ elsif bol? && match = scan(/ \#!.* /x)
68
+ encoder.text_token match, :doctype
70
69
 
71
- elsif import_clause && scan(/ (?!as) #{IDENT} (?: \. #{IDENT} )* (?: \.\* )? /ox)
70
+ elsif import_clause && match = scan(/ (?!as) #{IDENT} (?: \. #{IDENT} )* (?: \.\* )? /ox)
72
71
  after_def = value_expected = false
73
- kind = :include
72
+ encoder.text_token match, :include
74
73
 
75
74
  elsif match = scan(/ #{IDENT} | \[\] /ox)
76
75
  kind = IDENT_KIND[match]
@@ -90,16 +89,17 @@ module Scanners
90
89
  import_clause = match == 'import'
91
90
  after_def = true if match == 'def'
92
91
  end
92
+ encoder.text_token match, kind
93
93
 
94
- elsif scan(/;/)
94
+ elsif match = scan(/;/)
95
95
  import_clause = after_def = false
96
96
  value_expected = true
97
- kind = :operator
97
+ encoder.text_token match, :operator
98
98
 
99
- elsif scan(/\{/)
99
+ elsif match = scan(/\{/)
100
100
  class_name_follows = after_def = false
101
101
  value_expected = true
102
- kind = :operator
102
+ encoder.text_token match, :operator
103
103
  if !inline_block_stack.empty?
104
104
  inline_block_paren_depth += 1
105
105
  end
@@ -110,155 +110,146 @@ module Scanners
110
110
  value_expected = true
111
111
  value_expected = :regexp if match == '~'
112
112
  after_def = false
113
- kind = :operator
113
+ encoder.text_token match, :operator
114
114
 
115
115
  elsif match = scan(/ [)\]}] /x)
116
116
  value_expected = after_def = false
117
117
  if !inline_block_stack.empty? && match == '}'
118
118
  inline_block_paren_depth -= 1
119
119
  if inline_block_paren_depth == 0 # closing brace of inline block reached
120
- tokens << [match, :inline_delimiter]
121
- tokens << [:close, :inline]
120
+ encoder.text_token match, :inline_delimiter
121
+ encoder.end_group :inline
122
122
  state, string_delimiter, inline_block_paren_depth = inline_block_stack.pop
123
123
  next
124
124
  end
125
125
  end
126
- kind = :operator
126
+ encoder.text_token match, :operator
127
127
 
128
128
  elsif check(/[\d.]/)
129
129
  after_def = value_expected = false
130
- if scan(/0[xX][0-9A-Fa-f]+/)
131
- kind = :hex
132
- elsif scan(/(?>0[0-7]+)(?![89.eEfF])/)
133
- kind = :oct
134
- elsif scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/)
135
- kind = :float
136
- elsif scan(/\d+[lLgG]?/)
137
- kind = :integer
130
+ if match = scan(/0[xX][0-9A-Fa-f]+/)
131
+ encoder.text_token match, :hex
132
+ elsif match = scan(/(?>0[0-7]+)(?![89.eEfF])/)
133
+ encoder.text_token match, :octal
134
+ elsif match = scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/)
135
+ encoder.text_token match, :float
136
+ elsif match = scan(/\d+[lLgG]?/)
137
+ encoder.text_token match, :integer
138
138
  end
139
-
139
+
140
140
  elsif match = scan(/'''|"""/)
141
141
  after_def = value_expected = false
142
142
  state = :multiline_string
143
- tokens << [:open, :string]
143
+ encoder.begin_group :string
144
144
  string_delimiter = match
145
- kind = :delimiter
146
-
147
- # TODO: record.'name'
145
+ encoder.text_token match, :delimiter
146
+
147
+ # TODO: record.'name' syntax
148
148
  elsif match = scan(/["']/)
149
149
  after_def = value_expected = false
150
150
  state = match == '/' ? :regexp : :string
151
- tokens << [:open, state]
151
+ encoder.begin_group state
152
152
  string_delimiter = match
153
- kind = :delimiter
154
-
155
- elsif value_expected && (match = scan(/\//))
153
+ encoder.text_token match, :delimiter
154
+
155
+ elsif value_expected && match = scan(/\//)
156
156
  after_def = value_expected = false
157
- tokens << [:open, :regexp]
157
+ encoder.begin_group :regexp
158
158
  state = :regexp
159
159
  string_delimiter = '/'
160
- kind = :delimiter
161
-
162
- elsif scan(/ @ #{IDENT} /ox)
160
+ encoder.text_token match, :delimiter
161
+
162
+ elsif match = scan(/ @ #{IDENT} /ox)
163
163
  after_def = value_expected = false
164
- kind = :annotation
165
-
166
- elsif scan(/\//)
164
+ encoder.text_token match, :annotation
165
+
166
+ elsif match = scan(/\//)
167
167
  after_def = false
168
168
  value_expected = true
169
- kind = :operator
170
-
169
+ encoder.text_token match, :operator
170
+
171
171
  else
172
- getch
173
- kind = :error
174
-
172
+ encoder.text_token getch, :error
173
+
175
174
  end
176
-
175
+
177
176
  when :string, :regexp, :multiline_string
178
- if scan(STRING_CONTENT_PATTERN[string_delimiter])
179
- kind = :content
177
+ if match = scan(STRING_CONTENT_PATTERN[string_delimiter])
178
+ encoder.text_token match, :content
180
179
 
181
180
  elsif match = scan(state == :multiline_string ? /'''|"""/ : /["'\/]/)
182
- tokens << [match, :delimiter]
181
+ encoder.text_token match, :delimiter
183
182
  if state == :regexp
184
183
  # TODO: regexp modifiers? s, m, x, i?
185
184
  modifiers = scan(/[ix]+/)
186
- tokens << [modifiers, :modifier] if modifiers && !modifiers.empty?
185
+ encoder.text_token modifiers, :modifier if modifiers && !modifiers.empty?
187
186
  end
188
187
  state = :string if state == :multiline_string
189
- tokens << [:close, state]
188
+ encoder.end_group state
190
189
  string_delimiter = nil
191
190
  after_def = value_expected = false
192
191
  state = :initial
193
192
  next
194
-
193
+
195
194
  elsif (state == :string || state == :multiline_string) &&
196
195
  (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox))
197
196
  if string_delimiter[0] == ?' && !(match == "\\\\" || match == "\\'")
198
- kind = :content
197
+ encoder.text_token match, :content
199
198
  else
200
- kind = :char
199
+ encoder.text_token match, :char
201
200
  end
202
- elsif state == :regexp && scan(/ \\ (?: #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
203
- kind = :char
204
-
201
+ elsif state == :regexp && match = scan(/ \\ (?: #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
202
+ encoder.text_token match, :char
203
+
205
204
  elsif match = scan(/ \$ #{IDENT} /mox)
206
- tokens << [:open, :inline]
207
- tokens << ['$', :inline_delimiter]
205
+ encoder.begin_group :inline
206
+ encoder.text_token '$', :inline_delimiter
208
207
  match = match[1..-1]
209
- tokens << [match, IDENT_KIND[match]]
210
- tokens << [:close, :inline]
208
+ encoder.text_token match, IDENT_KIND[match]
209
+ encoder.end_group :inline
211
210
  next
212
211
  elsif match = scan(/ \$ \{ /x)
213
- tokens << [:open, :inline]
214
- tokens << ['${', :inline_delimiter]
212
+ encoder.begin_group :inline
213
+ encoder.text_token match, :inline_delimiter
215
214
  inline_block_stack << [state, string_delimiter, inline_block_paren_depth]
216
215
  inline_block_paren_depth = 1
217
216
  state = :initial
218
217
  next
219
-
220
- elsif scan(/ \$ /mx)
221
- kind = :content
222
-
223
- elsif scan(/ \\. /mx)
224
- kind = :content
225
-
226
- elsif scan(/ \\ | \n /x)
227
- tokens << [:close, state]
228
- kind = :error
218
+
219
+ elsif match = scan(/ \$ /mx)
220
+ encoder.text_token match, :content
221
+
222
+ elsif match = scan(/ \\. /mx)
223
+ encoder.text_token match, :content # TODO: Shouldn't this be :error?
224
+
225
+ elsif match = scan(/ \\ | \n /x)
226
+ encoder.end_group state
227
+ encoder.text_token match, :error
229
228
  after_def = value_expected = false
230
229
  state = :initial
231
-
230
+
232
231
  else
233
- raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
232
+ raise_inspect "else case \" reached; %p not handled." % peek(1), encoder
233
+
234
234
  end
235
-
235
+
236
236
  else
237
- raise_inspect 'Unknown state', tokens
238
-
239
- end
240
-
241
- match ||= matched
242
- if $CODERAY_DEBUG and not kind
243
- raise_inspect 'Error token %p in line %d' %
244
- [[match, kind], line], tokens
237
+ raise_inspect 'Unknown state', encoder
238
+
245
239
  end
246
- raise_inspect 'Empty token', tokens unless match
247
240
 
248
241
  last_token = match unless [:space, :comment, :doctype].include? kind
249
242
 
250
- tokens << [match, kind]
251
-
252
243
  end
253
-
244
+
254
245
  if [:multiline_string, :string, :regexp].include? state
255
- tokens << [:close, state]
246
+ encoder.end_group state
256
247
  end
257
-
258
- tokens
248
+
249
+ encoder
259
250
  end
260
-
251
+
261
252
  end
262
-
253
+
263
254
  end
264
255
  end
@@ -0,0 +1,168 @@
1
+ module CodeRay
2
+ module Scanners
3
+
4
+ load :ruby
5
+ load :html
6
+ load :java_script
7
+
8
+ class HAML < Scanner
9
+
10
+ register_for :haml
11
+ title 'HAML Template'
12
+
13
+ KINDS_NOT_LOC = HTML::KINDS_NOT_LOC
14
+
15
+ protected
16
+
17
+ def setup
18
+ super
19
+ @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true
20
+ @embedded_ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true, :state => @ruby_scanner.interpreted_string_state
21
+ @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true
22
+ end
23
+
24
+ def scan_tokens encoder, options
25
+
26
+ match = nil
27
+ code = ''
28
+
29
+ until eos?
30
+
31
+ if bol?
32
+ if match = scan(/!!!.*/)
33
+ encoder.text_token match, :doctype
34
+ next
35
+ end
36
+
37
+ if match = scan(/(?>( *)(\/(?!\[if)|-\#|:javascript|:ruby|:\w+) *)(?=\n)/)
38
+ encoder.text_token match, :comment
39
+
40
+ code = self[2]
41
+ if match = scan(/(?:\n+#{self[1]} .*)+/)
42
+ case code
43
+ when '/', '-#'
44
+ encoder.text_token match, :comment
45
+ when ':javascript'
46
+ # TODO: recognize #{...} snippets inside JavaScript
47
+ @java_script_scanner ||= CodeRay.scanner :java_script, :tokens => @tokens, :keep_tokens => true
48
+ @java_script_scanner.tokenize match, :tokens => encoder
49
+ when ':ruby'
50
+ @ruby_scanner.tokenize match, :tokens => encoder
51
+ when /:\w+/
52
+ encoder.text_token match, :comment
53
+ else
54
+ raise 'else-case reached: %p' % [code]
55
+ end
56
+ end
57
+ end
58
+
59
+ if match = scan(/ +/)
60
+ encoder.text_token match, :space
61
+ end
62
+
63
+ if match = scan(/\/.*/)
64
+ encoder.text_token match, :comment
65
+ next
66
+ end
67
+
68
+ if match = scan(/\\/)
69
+ encoder.text_token match, :plain
70
+ if match = scan(/.+/)
71
+ @html_scanner.tokenize match, :tokens => encoder
72
+ end
73
+ next
74
+ end
75
+
76
+ tag = false
77
+
78
+ if match = scan(/%[\w:]+\/?/)
79
+ encoder.text_token match, :tag
80
+ # if match = scan(/( +)(.+)/)
81
+ # encoder.text_token self[1], :space
82
+ # @embedded_ruby_scanner.tokenize self[2], :tokens => encoder
83
+ # end
84
+ tag = true
85
+ end
86
+
87
+ while match = scan(/([.#])[-\w]*\w/)
88
+ encoder.text_token match, self[1] == '#' ? :constant : :class
89
+ tag = true
90
+ end
91
+
92
+ if tag && match = scan(/(\()([^)]+)?(\))?/)
93
+ # TODO: recognize title=@title, class="widget_#{@widget.number}"
94
+ encoder.text_token self[1], :plain
95
+ @html_scanner.tokenize self[2], :tokens => encoder, :state => :attribute if self[2]
96
+ encoder.text_token self[3], :plain if self[3]
97
+ end
98
+
99
+ if tag && match = scan(/\{/)
100
+ encoder.text_token match, :plain
101
+
102
+ code = ''
103
+ level = 1
104
+ while true
105
+ code << scan(/([^\{\},\n]|, *\n?)*/)
106
+ case match = getch
107
+ when '{'
108
+ level += 1
109
+ code << match
110
+ when '}'
111
+ level -= 1
112
+ if level > 0
113
+ code << match
114
+ else
115
+ break
116
+ end
117
+ when "\n", ",", nil
118
+ break
119
+ end
120
+ end
121
+ @ruby_scanner.tokenize code, :tokens => encoder unless code.empty?
122
+
123
+ encoder.text_token match, :plain if match
124
+ end
125
+
126
+ if tag && match = scan(/(\[)([^\]\n]+)?(\])?/)
127
+ encoder.text_token self[1], :plain
128
+ @ruby_scanner.tokenize self[2], :tokens => encoder if self[2]
129
+ encoder.text_token self[3], :plain if self[3]
130
+ end
131
+
132
+ if tag && match = scan(/\//)
133
+ encoder.text_token match, :tag
134
+ end
135
+
136
+ if scan(/(>?<?[-=]|[&!]=|(& |!)|~)( *)([^,\n\|]+(?:(, *|\|(?=.|\n.*\|$))\n?[^,\n\|]*)*)?/)
137
+ encoder.text_token self[1] + self[3], :plain
138
+ if self[4]
139
+ if self[2]
140
+ @embedded_ruby_scanner.tokenize self[4], :tokens => encoder
141
+ else
142
+ @ruby_scanner.tokenize self[4], :tokens => encoder
143
+ end
144
+ end
145
+ elsif match = scan(/((?:<|><?)(?![!?\/\w]))?(.+)?/)
146
+ encoder.text_token self[1], :plain if self[1]
147
+ # TODO: recognize #{...} snippets
148
+ @html_scanner.tokenize self[2], :tokens => encoder if self[2]
149
+ end
150
+
151
+ elsif match = scan(/.+/)
152
+ @html_scanner.tokenize match, :tokens => encoder
153
+
154
+ end
155
+
156
+ if match = scan(/\n/)
157
+ encoder.text_token match, :space
158
+ end
159
+ end
160
+
161
+ encoder
162
+
163
+ end
164
+
165
+ end
166
+
167
+ end
168
+ end