coderay 0.8.357 → 0.9.1

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 (52) hide show
  1. data/lib/README +4 -3
  2. data/lib/coderay.rb +2 -1
  3. data/lib/coderay/encoder.rb +41 -15
  4. data/lib/coderay/encoders/_map.rb +3 -1
  5. data/lib/coderay/encoders/comment_filter.rb +43 -0
  6. data/lib/coderay/encoders/div.rb +2 -3
  7. data/lib/coderay/encoders/filter.rb +75 -0
  8. data/lib/coderay/encoders/html.rb +20 -3
  9. data/lib/coderay/encoders/html/css.rb +1 -1
  10. data/lib/coderay/encoders/html/numerization.rb +11 -2
  11. data/lib/coderay/encoders/html/output.rb +10 -1
  12. data/lib/coderay/encoders/json.rb +69 -0
  13. data/lib/coderay/encoders/lines_of_code.rb +90 -0
  14. data/lib/coderay/encoders/page.rb +1 -2
  15. data/lib/coderay/encoders/span.rb +2 -3
  16. data/lib/coderay/encoders/term.rb +137 -0
  17. data/lib/coderay/encoders/text.rb +4 -4
  18. data/lib/coderay/encoders/token_class_filter.rb +84 -0
  19. data/lib/coderay/encoders/xml.rb +1 -0
  20. data/lib/coderay/for_redcloth.rb +9 -4
  21. data/lib/coderay/helpers/file_type.rb +54 -15
  22. data/lib/coderay/helpers/plugin.rb +21 -3
  23. data/lib/coderay/helpers/word_list.rb +19 -4
  24. data/lib/coderay/scanner.rb +33 -2
  25. data/lib/coderay/scanners/_map.rb +10 -4
  26. data/lib/coderay/scanners/c.rb +61 -23
  27. data/lib/coderay/scanners/cpp.rb +228 -0
  28. data/lib/coderay/scanners/css.rb +9 -1
  29. data/lib/coderay/scanners/debug.rb +1 -0
  30. data/lib/coderay/scanners/delphi.rb +2 -2
  31. data/lib/coderay/scanners/diff.rb +1 -0
  32. data/lib/coderay/scanners/groovy.rb +263 -0
  33. data/lib/coderay/scanners/html.rb +9 -2
  34. data/lib/coderay/scanners/java.rb +18 -14
  35. data/lib/coderay/scanners/java_script.rb +42 -13
  36. data/lib/coderay/scanners/json.rb +7 -1
  37. data/lib/coderay/scanners/nitro_xhtml.rb +4 -0
  38. data/lib/coderay/scanners/php.rb +526 -0
  39. data/lib/coderay/scanners/plaintext.rb +4 -1
  40. data/lib/coderay/scanners/python.rb +285 -0
  41. data/lib/coderay/scanners/rhtml.rb +3 -0
  42. data/lib/coderay/scanners/ruby.rb +29 -11
  43. data/lib/coderay/scanners/ruby/patterns.rb +26 -20
  44. data/lib/coderay/scanners/scheme.rb +3 -0
  45. data/lib/coderay/scanners/sql.rb +162 -0
  46. data/lib/coderay/scanners/xml.rb +1 -1
  47. data/lib/coderay/scanners/yaml.rb +4 -1
  48. data/lib/coderay/styles/cycnus.rb +11 -7
  49. data/lib/coderay/token_classes.rb +4 -1
  50. data/lib/coderay/tokens.rb +50 -46
  51. metadata +14 -4
  52. data/lib/coderay/encoders/tokens.rb +0 -44
@@ -5,6 +5,14 @@ module Scanners
5
5
 
6
6
  register_for :css
7
7
 
8
+ KINDS_NOT_LOC = [
9
+ :comment,
10
+ :class, :pseudo_class, :type,
11
+ :constant, :directive,
12
+ :key, :value, :operator, :color, :float,
13
+ :error, :important,
14
+ ]
15
+
8
16
  module RE
9
17
  NonASCII = /[\x80-\xFF]/
10
18
  Hex = /[0-9a-fA-F]/
@@ -58,7 +66,7 @@ module Scanners
58
66
  elsif case states.last
59
67
  when :initial, :media
60
68
  if scan(/(?>#{RE::Ident})(?!\()|\*/ox)
61
- kind = :keyword
69
+ kind = :type
62
70
  elsif scan RE::Class
63
71
  kind = :class
64
72
  elsif scan RE::Id
@@ -7,6 +7,7 @@ module Scanners
7
7
  include Streamable
8
8
  register_for :debug
9
9
  file_extension 'raydebug'
10
+ title 'CodeRay Token Dump'
10
11
 
11
12
  protected
12
13
  def scan_tokens tokens, options
@@ -30,11 +30,11 @@ module Scanners
30
30
  'virtual', 'write', 'writeonly'
31
31
  ]
32
32
 
33
- IDENT_KIND = CaseIgnoringWordList.new(:ident, caching=true).
33
+ IDENT_KIND = CaseIgnoringWordList.new(:ident).
34
34
  add(RESERVED_WORDS, :reserved).
35
35
  add(DIRECTIVES, :directive)
36
36
 
37
- NAME_FOLLOWS = CaseIgnoringWordList.new(false, caching=true).
37
+ NAME_FOLLOWS = CaseIgnoringWordList.new(false).
38
38
  add(%w(procedure function .))
39
39
 
40
40
  private
@@ -4,6 +4,7 @@ module Scanners
4
4
  class Diff < Scanner
5
5
 
6
6
  register_for :diff
7
+ title 'diff output'
7
8
 
8
9
  def scan_tokens tokens, options
9
10
 
@@ -0,0 +1,263 @@
1
+ module CodeRay
2
+ module Scanners
3
+
4
+ load :java
5
+
6
+ class Groovy < Java
7
+
8
+ include Streamable
9
+ register_for :groovy
10
+
11
+ # TODO: Check this!
12
+ GROOVY_KEYWORDS = %w[
13
+ as assert def in
14
+ ]
15
+ KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[
16
+ case instanceof new return throw typeof while as assert in
17
+ ]
18
+ GROOVY_MAGIC_VARIABLES = %w[ it ]
19
+
20
+ IDENT_KIND = Java::IDENT_KIND.dup.
21
+ add(GROOVY_KEYWORDS, :keyword).
22
+ add(GROOVY_MAGIC_VARIABLES, :local_variable)
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
27
+
28
+ # TODO: interpretation inside ', ", /
29
+ STRING_CONTENT_PATTERN = {
30
+ "'" => /(?>\\[^\\'\n]+|[^\\'\n]+)+/,
31
+ '"' => /[^\\$"\n]+/,
32
+ "'''" => /(?>[^\\']+|'(?!''))+/,
33
+ '"""' => /(?>[^\\$"]+|"(?!""))+/,
34
+ '/' => /[^\\$\/\n]+/,
35
+ }
36
+
37
+ def scan_tokens tokens, options
38
+
39
+ state = :initial
40
+ inline_block_stack = []
41
+ inline_block_paren_depth = nil
42
+ string_delimiter = nil
43
+ import_clause = class_name_follows = last_token = after_def = false
44
+ value_expected = true
45
+
46
+ until eos?
47
+
48
+ kind = nil
49
+ match = nil
50
+
51
+ case state
52
+
53
+ when :initial
54
+
55
+ if match = scan(/ \s+ | \\\n /x)
56
+ tokens << [match, :space]
57
+ if match.index ?\n
58
+ import_clause = after_def = false
59
+ value_expected = true unless value_expected
60
+ end
61
+ next
62
+
63
+ elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
64
+ value_expected = true
65
+ after_def = false
66
+ kind = :comment
67
+
68
+ elsif bol? && scan(/ \#!.* /x)
69
+ kind = :doctype
70
+
71
+ elsif import_clause && scan(/ (?!as) #{IDENT} (?: \. #{IDENT} )* (?: \.\* )? /ox)
72
+ after_def = value_expected = false
73
+ kind = :include
74
+
75
+ elsif match = scan(/ #{IDENT} | \[\] /ox)
76
+ kind = IDENT_KIND[match]
77
+ value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match]
78
+ if last_token == '.'
79
+ kind = :ident
80
+ elsif class_name_follows
81
+ kind = :class
82
+ class_name_follows = false
83
+ elsif after_def && check(/\s*[({]/)
84
+ kind = :method
85
+ after_def = false
86
+ elsif kind == :ident && last_token != '?' && check(/:/)
87
+ kind = :key
88
+ else
89
+ class_name_follows = true if match == 'class' || (import_clause && match == 'as')
90
+ import_clause = match == 'import'
91
+ after_def = true if match == 'def'
92
+ end
93
+
94
+ elsif scan(/;/)
95
+ import_clause = after_def = false
96
+ value_expected = true
97
+ kind = :operator
98
+
99
+ elsif scan(/\{/)
100
+ class_name_follows = after_def = false
101
+ value_expected = true
102
+ kind = :operator
103
+ if !inline_block_stack.empty?
104
+ inline_block_paren_depth += 1
105
+ end
106
+
107
+ # TODO: ~'...', ~"..." and ~/.../ style regexps
108
+ elsif match = scan(/ \.\.<? | \*?\.(?!\d)@? | \.& | \?:? | [,?:(\[] | -[->] | \+\+ |
109
+ && | \|\| | \*\*=? | ==?~ | <=?>? | [-+*%^~&|>=!]=? | <<<?=? | >>>?=? /x)
110
+ value_expected = true
111
+ value_expected = :regexp if match == '~'
112
+ after_def = false
113
+ kind = :operator
114
+
115
+ elsif match = scan(/ [)\]}] /x)
116
+ value_expected = after_def = false
117
+ if !inline_block_stack.empty? && match == '}'
118
+ inline_block_paren_depth -= 1
119
+ if inline_block_paren_depth == 0 # closing brace of inline block reached
120
+ tokens << [match, :inline_delimiter]
121
+ tokens << [:close, :inline]
122
+ state, string_delimiter, inline_block_paren_depth = inline_block_stack.pop
123
+ next
124
+ end
125
+ end
126
+
127
+ elsif check(/[\d.]/)
128
+ after_def = value_expected = false
129
+ if scan(/0[xX][0-9A-Fa-f]+/)
130
+ kind = :hex
131
+ elsif scan(/(?>0[0-7]+)(?![89.eEfF])/)
132
+ kind = :oct
133
+ elsif scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/)
134
+ kind = :float
135
+ elsif scan(/\d+[lLgG]?/)
136
+ kind = :integer
137
+ end
138
+
139
+ elsif match = scan(/'''|"""/)
140
+ after_def = value_expected = false
141
+ state = :multiline_string
142
+ tokens << [:open, :string]
143
+ string_delimiter = match
144
+ kind = :delimiter
145
+
146
+ # TODO: record.'name'
147
+ elsif match = scan(/["']/)
148
+ after_def = value_expected = false
149
+ state = match == '/' ? :regexp : :string
150
+ tokens << [:open, state]
151
+ string_delimiter = match
152
+ kind = :delimiter
153
+
154
+ elsif value_expected && (match = scan(/\//))
155
+ after_def = value_expected = false
156
+ tokens << [:open, :regexp]
157
+ state = :regexp
158
+ string_delimiter = '/'
159
+ kind = :delimiter
160
+
161
+ elsif scan(/ @ #{IDENT} /ox)
162
+ after_def = value_expected = false
163
+ kind = :annotation
164
+
165
+ elsif scan(/\//)
166
+ after_def = false
167
+ value_expected = true
168
+ kind = :operator
169
+
170
+ else
171
+ getch
172
+ kind = :error
173
+
174
+ end
175
+
176
+ when :string, :regexp, :multiline_string
177
+ if scan(STRING_CONTENT_PATTERN[string_delimiter])
178
+ kind = :content
179
+
180
+ elsif match = scan(state == :multiline_string ? /'''|"""/ : /["'\/]/)
181
+ tokens << [match, :delimiter]
182
+ if state == :regexp
183
+ # TODO: regexp modifiers? s, m, x, i?
184
+ modifiers = scan(/[ix]+/)
185
+ tokens << [modifiers, :modifier] if modifiers && !modifiers.empty?
186
+ end
187
+ state = :string if state == :multiline_string
188
+ tokens << [:close, state]
189
+ string_delimiter = nil
190
+ after_def = value_expected = false
191
+ state = :initial
192
+ next
193
+
194
+ elsif (state == :string || state == :multiline_string) &&
195
+ (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox))
196
+ if string_delimiter[0] == ?' && !(match == "\\\\" || match == "\\'")
197
+ kind = :content
198
+ else
199
+ kind = :char
200
+ end
201
+ elsif state == :regexp && scan(/ \\ (?: #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
202
+ kind = :char
203
+
204
+ elsif match = scan(/ \$ #{IDENT} /mox)
205
+ tokens << [:open, :inline]
206
+ tokens << ['$', :inline_delimiter]
207
+ match = match[1..-1]
208
+ tokens << [match, IDENT_KIND[match]]
209
+ tokens << [:close, :inline]
210
+ next
211
+ elsif match = scan(/ \$ \{ /x)
212
+ tokens << [:open, :inline]
213
+ tokens << ['${', :inline_delimiter]
214
+ inline_block_stack << [state, string_delimiter, inline_block_paren_depth]
215
+ inline_block_paren_depth = 1
216
+ state = :initial
217
+ next
218
+
219
+ elsif scan(/ \$ /mx)
220
+ kind = :content
221
+
222
+ elsif scan(/ \\. /mx)
223
+ kind = :content
224
+
225
+ elsif scan(/ \\ | \n /x)
226
+ tokens << [:close, state]
227
+ kind = :error
228
+ after_def = value_expected = false
229
+ state = :initial
230
+
231
+ else
232
+ raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
233
+ end
234
+
235
+ else
236
+ raise_inspect 'Unknown state', tokens
237
+
238
+ end
239
+
240
+ match ||= matched
241
+ if $DEBUG and not kind
242
+ raise_inspect 'Error token %p in line %d' %
243
+ [[match, kind], line], tokens
244
+ end
245
+ raise_inspect 'Empty token', tokens unless match
246
+
247
+ last_token = match unless [:space, :comment, :doctype].include? kind
248
+
249
+ tokens << [match, kind]
250
+
251
+ end
252
+
253
+ if [:multiline_string, :string, :regexp].include? state
254
+ tokens << [:close, state]
255
+ end
256
+
257
+ tokens
258
+ end
259
+
260
+ end
261
+
262
+ end
263
+ end
@@ -6,6 +6,13 @@ module Scanners
6
6
 
7
7
  include Streamable
8
8
  register_for :html
9
+
10
+ KINDS_NOT_LOC = [
11
+ :comment, :doctype, :preprocessor,
12
+ :tag, :attribute_name, :operator,
13
+ :attribute_value, :delimiter, :content,
14
+ :plain, :entity, :error
15
+ ]
9
16
 
10
17
  ATTR_NAME = /[\w.:-]+/
11
18
  ATTR_VALUE_UNQUOTED = ATTR_NAME
@@ -68,9 +75,9 @@ module Scanners
68
75
  kind = :preprocessor
69
76
  elsif scan(/<\?.*?\?>|<%.*?%>/m)
70
77
  kind = :comment
71
- elsif scan(/<\/[-\w_.:]*>/m)
78
+ elsif scan(/<\/[-\w.:]*>/m)
72
79
  kind = :tag
73
- elsif match = scan(/<[-\w_.:]+>?/m)
80
+ elsif match = scan(/<[-\w.:]+>?/m)
74
81
  kind = :tag
75
82
  state = :attribute unless match[-1] == ?>
76
83
  elsif scan(/[^<>&]+/)
@@ -7,30 +7,33 @@ module Scanners
7
7
  register_for :java
8
8
  helper :builtin_types
9
9
 
10
- # TODO: Check this!
10
+ # http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html
11
11
  KEYWORDS = %w[
12
- break case catch continue default do else
13
- false finally for if instanceof new null
14
- return switch throw true try typeof while
15
- debugger export import package
12
+ assert break case catch continue default do else
13
+ finally for if instanceof import new package
14
+ return switch throw try typeof while
15
+ debugger export
16
16
  ]
17
-
17
+ RESERVED = %w[ const goto ]
18
+ CONSTANTS = %w[ false null true ]
18
19
  MAGIC_VARIABLES = %w[ this super ]
19
20
  TYPES = %w[
20
- boolean byte char class interface double enum float String int long short void
21
- ] << '[]'
21
+ boolean byte char class double enum float int interface long
22
+ short void
23
+ ] << '[]' # because int[] should be highlighted as a type
22
24
  DIRECTIVES = %w[
23
25
  abstract extends final implements native private protected public
24
- static strictfp synchronized threadsafe throws transient volatile
26
+ static strictfp synchronized throws transient volatile
25
27
  ]
26
28
 
27
- # Reserved for future use.
28
-
29
29
  IDENT_KIND = WordList.new(:ident).
30
30
  add(KEYWORDS, :keyword).
31
+ add(RESERVED, :reserved).
32
+ add(CONSTANTS, :pre_constant).
31
33
  add(MAGIC_VARIABLES, :local_variable).
32
34
  add(TYPES, :type).
33
35
  add(BuiltinTypes::List, :pre_type).
36
+ add(BuiltinTypes::List.select { |builtin| builtin[/(Error|Exception)$/] }, :exception).
34
37
  add(DIRECTIVES, :directive)
35
38
 
36
39
  ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
@@ -61,8 +64,9 @@ module Scanners
61
64
  tokens << [match, :space]
62
65
  next
63
66
 
64
- elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
65
- kind = :comment
67
+ elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
68
+ tokens << [match, :comment]
69
+ next
66
70
 
67
71
  elsif import_clause && scan(/ #{IDENT} (?: \. #{IDENT} )* /ox)
68
72
  kind = :include
@@ -79,7 +83,7 @@ module Scanners
79
83
  class_name_follows = true if match == 'class' || match == 'interface'
80
84
  end
81
85
 
82
- elsif scan(/ \.(?!\d) | [,?:(\[)\]}] | -- | \+\+ | && | \|\| | \*\*=? | [-+*\/%^~&|<>=!]=? | <<<?=? | >>>?=? /x)
86
+ elsif scan(/ \.(?!\d) | [,?:()\[\]}] | -- | \+\+ | && | \|\| | \*\*=? | [-+*\/%^~&|<>=!]=? | <<<?=? | >>>?=? /x)
83
87
  kind = :operator
84
88
 
85
89
  elsif scan(/;/)
@@ -11,14 +11,17 @@ module Scanners
11
11
  # The actual JavaScript keywords.
12
12
  KEYWORDS = %w[
13
13
  break case catch continue default delete do else
14
- false finally for function if in instanceof new null
15
- return switch throw true try typeof var void while with
14
+ finally for function if in instanceof new
15
+ return switch throw try typeof var void while with
16
+ ]
17
+ PREDEFINED_CONSTANTS = %w[
18
+ false null true undefined
16
19
  ]
17
20
 
18
21
  MAGIC_VARIABLES = %w[ this arguments ] # arguments was introduced in JavaScript 1.4
19
22
 
20
23
  KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[
21
- case delete in instanceof new return throw typeof while with
24
+ case delete in instanceof new return throw typeof with
22
25
  ]
23
26
 
24
27
  # Reserved for future use.
@@ -31,6 +34,7 @@ module Scanners
31
34
 
32
35
  IDENT_KIND = WordList.new(:ident).
33
36
  add(RESERVED_WORDS, :reserved).
37
+ add(PREDEFINED_CONSTANTS, :pre_constant).
34
38
  add(MAGIC_VARIABLES, :local_variable).
35
39
  add(KEYWORDS, :keyword)
36
40
 
@@ -53,6 +57,7 @@ module Scanners
53
57
  string_delimiter = nil
54
58
  value_expected = true
55
59
  key_expected = false
60
+ function_expected = false
56
61
 
57
62
  until eos?
58
63
 
@@ -72,7 +77,7 @@ module Scanners
72
77
  value_expected = true
73
78
  kind = :comment
74
79
 
75
- elsif check(/\d/)
80
+ elsif check(/\.?\d/)
76
81
  key_expected = value_expected = false
77
82
  if scan(/0[xX][0-9A-Fa-f]+/)
78
83
  kind = :hex
@@ -83,29 +88,42 @@ module Scanners
83
88
  elsif scan(/\d+/)
84
89
  kind = :integer
85
90
  end
91
+
92
+ elsif value_expected && match = scan(/<([[:alpha:]]\w*) (?: [^\/>]*\/> | .*?<\/\1>)/xim)
93
+ # FIXME: scan over nested tags
94
+ xml_scanner.tokenize match
95
+ value_expected = false
96
+ next
86
97
 
87
98
  elsif match = scan(/ [-+*=<>?:;,!&^|(\[{~%]+ | \.(?!\d) /x)
88
99
  value_expected = true
89
100
  last_operator = match[-1]
90
101
  key_expected = (last_operator == ?{) || (last_operator == ?,)
102
+ function_expected = false
91
103
  kind = :operator
92
104
 
93
105
  elsif scan(/ [)\]}]+ /x)
94
- key_expected = value_expected = false
106
+ function_expected = key_expected = value_expected = false
95
107
  kind = :operator
96
108
 
97
109
  elsif match = scan(/ [$a-zA-Z_][A-Za-z_0-9$]* /x)
98
110
  kind = IDENT_KIND[match]
99
111
  value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match]
112
+ # TODO: labels
100
113
  if kind == :ident
101
- if match.index(?$)
114
+ if match.index(?$) # $ allowed inside an identifier
102
115
  kind = :predefined
116
+ elsif function_expected
117
+ kind = :function
118
+ elsif check(/\s*[=:]\s*function\b/)
119
+ kind = :function
103
120
  elsif key_expected && check(/\s*:/)
104
121
  kind = :key
105
122
  end
106
123
  end
124
+ function_expected = (kind == :keyword) && (match == 'function')
107
125
  key_expected = false
108
-
126
+
109
127
  elsif match = scan(/["']/)
110
128
  if key_expected && check(KEY_CHECK_PATTERN[match])
111
129
  state = :key
@@ -158,25 +176,25 @@ module Scanners
158
176
  elsif scan(/\\./m)
159
177
  kind = :content
160
178
  elsif scan(/ \\ | $ /x)
161
- tokens << [:close, :delimiter]
179
+ tokens << [:close, state]
162
180
  kind = :error
163
181
  key_expected = value_expected = false
164
182
  state = :initial
165
183
  else
166
- raise_inspect "else case \" reached; %p not handled." % peek(1), tokens, state
184
+ raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
167
185
  end
168
186
 
169
187
  else
170
- raise_inspect 'Unknown state', tokens, state
188
+ raise_inspect 'Unknown state', tokens
171
189
 
172
190
  end
173
191
 
174
192
  match ||= matched
175
193
  if $DEBUG and not kind
176
194
  raise_inspect 'Error token %p in line %d' %
177
- [[match, kind], line], tokens, state
195
+ [[match, kind], line], tokens
178
196
  end
179
- raise_inspect 'Empty token', tokens, state unless match
197
+ raise_inspect 'Empty token', tokens unless match
180
198
 
181
199
  tokens << [match, kind]
182
200
 
@@ -189,7 +207,18 @@ module Scanners
189
207
  tokens
190
208
  end
191
209
 
192
- end
210
+ protected
193
211
 
212
+ def reset_instance
213
+ super
214
+ @xml_scanner.reset if defined? @xml_scanner
215
+ end
216
+
217
+ def xml_scanner
218
+ @xml_scanner ||= CodeRay.scanner :xml, :tokens => @tokens, :keep_tokens => true, :keep_state => true
219
+ end
220
+
221
+ end
222
+
194
223
  end
195
224
  end