coderay 0.9.8 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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