coderay 1.0.9 → 1.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +2 -0
- data/bin/coderay +4 -4
- data/lib/coderay.rb +2 -3
- data/lib/coderay/encoders/debug.rb +5 -17
- data/lib/coderay/encoders/debug_lint.rb +62 -0
- data/lib/coderay/encoders/html.rb +84 -84
- data/lib/coderay/encoders/html/css.rb +7 -7
- data/lib/coderay/encoders/html/numbering.rb +24 -19
- data/lib/coderay/encoders/html/output.rb +1 -1
- data/lib/coderay/encoders/lint.rb +57 -0
- data/lib/coderay/encoders/statistic.rb +0 -1
- data/lib/coderay/encoders/terminal.rb +121 -105
- data/lib/coderay/helpers/file_type.rb +54 -47
- data/lib/coderay/helpers/plugin.rb +4 -13
- data/lib/coderay/scanner.rb +58 -26
- data/lib/coderay/scanners/c.rb +1 -1
- data/lib/coderay/scanners/cpp.rb +1 -1
- data/lib/coderay/scanners/css.rb +22 -25
- data/lib/coderay/scanners/diff.rb +53 -31
- data/lib/coderay/scanners/groovy.rb +17 -4
- data/lib/coderay/scanners/html.rb +38 -16
- data/lib/coderay/scanners/java.rb +1 -1
- data/lib/coderay/scanners/java_script.rb +30 -6
- data/lib/coderay/scanners/json.rb +15 -12
- data/lib/coderay/scanners/lua.rb +280 -0
- data/lib/coderay/scanners/php.rb +22 -4
- data/lib/coderay/scanners/python.rb +3 -3
- data/lib/coderay/scanners/raydebug.rb +8 -8
- data/lib/coderay/scanners/ruby.rb +2 -2
- data/lib/coderay/scanners/sass.rb +232 -0
- data/lib/coderay/scanners/sql.rb +7 -4
- data/lib/coderay/scanners/taskpaper.rb +36 -0
- data/lib/coderay/scanners/yaml.rb +2 -2
- data/lib/coderay/styles/alpha.rb +31 -21
- data/lib/coderay/token_kinds.rb +68 -71
- data/lib/coderay/tokens.rb +23 -77
- data/lib/coderay/version.rb +1 -1
- data/test/functional/examples.rb +3 -3
- data/test/functional/for_redcloth.rb +4 -10
- metadata +13 -14
- data/lib/coderay/helpers/gzip.rb +0 -41
@@ -131,7 +131,7 @@ module CodeRay
|
|
131
131
|
|
132
132
|
# A Hash of plugion_id => Plugin pairs.
|
133
133
|
def plugin_hash
|
134
|
-
@plugin_hash ||= make_plugin_hash
|
134
|
+
@plugin_hash ||= (@plugin_hash = make_plugin_hash).tap { load_plugin_map }
|
135
135
|
end
|
136
136
|
|
137
137
|
# Returns an array of all .rb files in the plugin path.
|
@@ -158,7 +158,6 @@ module CodeRay
|
|
158
158
|
# This is done automatically when plugin_path is called.
|
159
159
|
def load_plugin_map
|
160
160
|
mapfile = path_to '_map'
|
161
|
-
@plugin_map_loaded = true
|
162
161
|
if File.exist? mapfile
|
163
162
|
require mapfile
|
164
163
|
true
|
@@ -171,23 +170,16 @@ module CodeRay
|
|
171
170
|
|
172
171
|
# Return a plugin hash that automatically loads plugins.
|
173
172
|
def make_plugin_hash
|
174
|
-
@plugin_map_loaded ||= false
|
175
173
|
Hash.new do |h, plugin_id|
|
176
174
|
id = validate_id(plugin_id)
|
177
175
|
path = path_to id
|
178
176
|
begin
|
179
177
|
require path
|
180
178
|
rescue LoadError => boom
|
181
|
-
if
|
182
|
-
|
183
|
-
warn '%p could not load plugin %p; falling back to %p' % [self, id, h[:default]]
|
184
|
-
h[:default]
|
185
|
-
else
|
186
|
-
raise PluginNotFound, '%p could not load plugin %p: %s' % [self, id, boom]
|
187
|
-
end
|
179
|
+
if h.has_key?(:default)
|
180
|
+
h[:default]
|
188
181
|
else
|
189
|
-
|
190
|
-
h[plugin_id]
|
182
|
+
raise PluginNotFound, '%p could not load plugin %p: %s' % [self, id, boom]
|
191
183
|
end
|
192
184
|
else
|
193
185
|
# Plugin should have registered by now
|
@@ -271,7 +263,6 @@ module CodeRay
|
|
271
263
|
end
|
272
264
|
|
273
265
|
def aliases
|
274
|
-
plugin_host.load_plugin_map
|
275
266
|
plugin_host.plugin_hash.inject [] do |aliases, (key, _)|
|
276
267
|
aliases << key if plugin_host[key] == self
|
277
268
|
aliases
|
data/lib/coderay/scanner.rb
CHANGED
@@ -182,16 +182,9 @@ module CodeRay
|
|
182
182
|
# Scan the code and returns all tokens in a Tokens object.
|
183
183
|
def tokenize source = nil, options = {}
|
184
184
|
options = @options.merge(options)
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
when Array
|
189
|
-
self.string = self.class.normalize(source.join)
|
190
|
-
when nil
|
191
|
-
reset
|
192
|
-
else
|
193
|
-
self.string = self.class.normalize(source)
|
194
|
-
end
|
185
|
+
|
186
|
+
set_tokens_from_options options
|
187
|
+
set_string_from_source source
|
195
188
|
|
196
189
|
begin
|
197
190
|
scan_tokens @tokens, options
|
@@ -261,6 +254,22 @@ module CodeRay
|
|
261
254
|
def setup # :doc:
|
262
255
|
end
|
263
256
|
|
257
|
+
def set_string_from_source source
|
258
|
+
case source
|
259
|
+
when Array
|
260
|
+
self.string = self.class.normalize(source.join)
|
261
|
+
when nil
|
262
|
+
reset
|
263
|
+
else
|
264
|
+
self.string = self.class.normalize(source)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def set_tokens_from_options options
|
269
|
+
@tokens = options[:tokens] || @tokens || Tokens.new
|
270
|
+
@tokens.scanner = self if @tokens.respond_to? :scanner=
|
271
|
+
end
|
272
|
+
|
264
273
|
# This is the central method, and commonly the only one a
|
265
274
|
# subclass implements.
|
266
275
|
#
|
@@ -277,19 +286,15 @@ module CodeRay
|
|
277
286
|
@binary_string = nil if defined? @binary_string
|
278
287
|
end
|
279
288
|
|
280
|
-
|
281
|
-
def raise_inspect msg, tokens, state = self.state || 'No state given!', ambit = 30, backtrace = caller
|
282
|
-
raise ScanError, <<-EOE % [
|
289
|
+
SCAN_ERROR_MESSAGE = <<-MESSAGE
|
283
290
|
|
284
291
|
|
285
|
-
***ERROR in %s: %s (after %
|
292
|
+
***ERROR in %s: %s (after %s tokens)
|
286
293
|
|
287
294
|
tokens:
|
288
295
|
%s
|
289
296
|
|
290
|
-
|
291
|
-
matched: %p state: %p
|
292
|
-
bol? = %p, eos? = %p
|
297
|
+
%s
|
293
298
|
|
294
299
|
surrounding code:
|
295
300
|
%p ~~ %p
|
@@ -297,16 +302,43 @@ surrounding code:
|
|
297
302
|
|
298
303
|
***ERROR***
|
299
304
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
305
|
+
MESSAGE
|
306
|
+
|
307
|
+
def raise_inspect_arguments message, tokens, state, ambit
|
308
|
+
return File.basename(caller[0]),
|
309
|
+
message,
|
310
|
+
tokens_size(tokens),
|
311
|
+
tokens_last(tokens, 10).map(&:inspect).join("\n"),
|
312
|
+
scanner_state_info(state),
|
307
313
|
binary_string[pos - ambit, ambit],
|
308
|
-
binary_string[pos, ambit]
|
309
|
-
|
314
|
+
binary_string[pos, ambit]
|
315
|
+
end
|
316
|
+
|
317
|
+
SCANNER_STATE_INFO = <<-INFO
|
318
|
+
current line: %d column: %d pos: %d
|
319
|
+
matched: %p state: %p
|
320
|
+
bol?: %p, eos?: %p
|
321
|
+
INFO
|
322
|
+
|
323
|
+
def scanner_state_info state
|
324
|
+
SCANNER_STATE_INFO % [
|
325
|
+
line, column, pos,
|
326
|
+
matched, state || 'No state given!',
|
327
|
+
bol?, eos?,
|
328
|
+
]
|
329
|
+
end
|
330
|
+
|
331
|
+
# Scanner error with additional status information
|
332
|
+
def raise_inspect message, tokens, state = self.state, ambit = 30, backtrace = caller
|
333
|
+
raise ScanError, SCAN_ERROR_MESSAGE % raise_inspect_arguments(message, tokens, state, ambit), backtrace
|
334
|
+
end
|
335
|
+
|
336
|
+
def tokens_size tokens
|
337
|
+
tokens.size if tokens.respond_to?(:size)
|
338
|
+
end
|
339
|
+
|
340
|
+
def tokens_last tokens, n
|
341
|
+
tokens.respond_to?(:last) ? tokens.last(n) : []
|
310
342
|
end
|
311
343
|
|
312
344
|
# Shorthand for scan_until(/\z/).
|
data/lib/coderay/scanners/c.rb
CHANGED
@@ -148,7 +148,7 @@ module Scanners
|
|
148
148
|
encoder.text_token match, :char
|
149
149
|
elsif match = scan(/ \\ | $ /x)
|
150
150
|
encoder.end_group :string
|
151
|
-
encoder.text_token match, :error
|
151
|
+
encoder.text_token match, :error unless match.empty?
|
152
152
|
state = :initial
|
153
153
|
label_expected = false
|
154
154
|
else
|
data/lib/coderay/scanners/cpp.rb
CHANGED
@@ -160,7 +160,7 @@ module Scanners
|
|
160
160
|
encoder.text_token match, :char
|
161
161
|
elsif match = scan(/ \\ | $ /x)
|
162
162
|
encoder.end_group :string
|
163
|
-
encoder.text_token match, :error
|
163
|
+
encoder.text_token match, :error unless match.empty?
|
164
164
|
state = :initial
|
165
165
|
label_expected = false
|
166
166
|
else
|
data/lib/coderay/scanners/css.rb
CHANGED
@@ -7,27 +7,25 @@ module Scanners
|
|
7
7
|
|
8
8
|
KINDS_NOT_LOC = [
|
9
9
|
:comment,
|
10
|
-
:class, :pseudo_class, :
|
11
|
-
:
|
10
|
+
:class, :pseudo_class, :tag,
|
11
|
+
:id, :directive,
|
12
12
|
:key, :value, :operator, :color, :float, :string,
|
13
|
-
:error, :important,
|
13
|
+
:error, :important, :type,
|
14
14
|
] # :nodoc:
|
15
15
|
|
16
16
|
module RE # :nodoc:
|
17
17
|
Hex = /[0-9a-fA-F]/
|
18
|
-
Unicode = /\\#{Hex}{1,6}
|
19
|
-
Escape = /#{Unicode}|\\[^\
|
20
|
-
NMChar = /[-_a-zA-Z0-9]
|
21
|
-
NMStart = /[_a-zA-Z]
|
22
|
-
|
23
|
-
|
24
|
-
String2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*'?/ # TODO: buggy regexp
|
18
|
+
Unicode = /\\#{Hex}{1,6}\b/ # differs from standard because it allows uppercase hex too
|
19
|
+
Escape = /#{Unicode}|\\[^\n0-9a-fA-F]/
|
20
|
+
NMChar = /[-_a-zA-Z0-9]/
|
21
|
+
NMStart = /[_a-zA-Z]/
|
22
|
+
String1 = /"(?:[^\n\\"]+|\\\n|#{Escape})*"?/ # TODO: buggy regexp
|
23
|
+
String2 = /'(?:[^\n\\']+|\\\n|#{Escape})*'?/ # TODO: buggy regexp
|
25
24
|
String = /#{String1}|#{String2}/
|
26
25
|
|
27
26
|
HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/
|
28
|
-
Color = /#{HexColor}/
|
29
27
|
|
30
|
-
Num = /-?(?:[0-9]
|
28
|
+
Num = /-?(?:[0-9]*\.[0-9]+|[0-9]+)n?/
|
31
29
|
Name = /#{NMChar}+/
|
32
30
|
Ident = /-?#{NMStart}#{NMChar}*/
|
33
31
|
AtKeyword = /@#{Ident}/
|
@@ -35,16 +33,15 @@ module Scanners
|
|
35
33
|
|
36
34
|
reldimensions = %w[em ex px]
|
37
35
|
absdimensions = %w[in cm mm pt pc]
|
38
|
-
Unit = Regexp.union(*(reldimensions + absdimensions + %w[s]))
|
36
|
+
Unit = Regexp.union(*(reldimensions + absdimensions + %w[s dpi dppx deg]))
|
39
37
|
|
40
38
|
Dimension = /#{Num}#{Unit}/
|
41
39
|
|
42
|
-
|
43
|
-
Function = /(?:url|alpha|attr|counters?)\((?:[^)\n\r\f]|\\\))*\)?/
|
40
|
+
Function = /(?:url|alpha|attr|counters?)\((?:[^)\n]|\\\))*\)?/
|
44
41
|
|
45
|
-
Id =
|
42
|
+
Id = /(?!#{HexColor}\b(?!-))##{Name}/
|
46
43
|
Class = /\.#{Name}/
|
47
|
-
PseudoClass =
|
44
|
+
PseudoClass = /::?#{Ident}/
|
48
45
|
AttributeSelector = /\[[^\]]*\]?/
|
49
46
|
end
|
50
47
|
|
@@ -52,11 +49,11 @@ module Scanners
|
|
52
49
|
|
53
50
|
def setup
|
54
51
|
@state = :initial
|
55
|
-
@value_expected =
|
52
|
+
@value_expected = false
|
56
53
|
end
|
57
54
|
|
58
55
|
def scan_tokens encoder, options
|
59
|
-
states = Array(options[:state] || @state)
|
56
|
+
states = Array(options[:state] || @state).dup
|
60
57
|
value_expected = @value_expected
|
61
58
|
|
62
59
|
until eos?
|
@@ -67,13 +64,13 @@ module Scanners
|
|
67
64
|
elsif case states.last
|
68
65
|
when :initial, :media
|
69
66
|
if match = scan(/(?>#{RE::Ident})(?!\()|\*/ox)
|
70
|
-
encoder.text_token match, :
|
67
|
+
encoder.text_token match, :tag
|
71
68
|
next
|
72
69
|
elsif match = scan(RE::Class)
|
73
70
|
encoder.text_token match, :class
|
74
71
|
next
|
75
72
|
elsif match = scan(RE::Id)
|
76
|
-
encoder.text_token match, :
|
73
|
+
encoder.text_token match, :id
|
77
74
|
next
|
78
75
|
elsif match = scan(RE::PseudoClass)
|
79
76
|
encoder.text_token match, :pseudo_class
|
@@ -148,17 +145,17 @@ module Scanners
|
|
148
145
|
start = match[/^\w+\(/]
|
149
146
|
encoder.text_token start, :delimiter
|
150
147
|
if match[-1] == ?)
|
151
|
-
encoder.text_token match[start.size..-2], :content
|
148
|
+
encoder.text_token match[start.size..-2], :content if match.size > start.size + 1
|
152
149
|
encoder.text_token ')', :delimiter
|
153
150
|
else
|
154
|
-
encoder.text_token match[start.size..-1], :content
|
151
|
+
encoder.text_token match[start.size..-1], :content if match.size > start.size
|
155
152
|
end
|
156
153
|
encoder.end_group :function
|
157
154
|
|
158
155
|
elsif match = scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox)
|
159
156
|
encoder.text_token match, :float
|
160
157
|
|
161
|
-
elsif match = scan(/#{RE::
|
158
|
+
elsif match = scan(/#{RE::HexColor}/o)
|
162
159
|
encoder.text_token match, :color
|
163
160
|
|
164
161
|
elsif match = scan(/! *important/)
|
@@ -170,7 +167,7 @@ module Scanners
|
|
170
167
|
elsif match = scan(RE::AtKeyword)
|
171
168
|
encoder.text_token match, :directive
|
172
169
|
|
173
|
-
elsif match = scan(/ [
|
170
|
+
elsif match = scan(/ [+>~:;,.=()\/] /x)
|
174
171
|
if match == ':'
|
175
172
|
value_expected = true
|
176
173
|
elsif match == ';'
|
@@ -20,7 +20,7 @@ module Scanners
|
|
20
20
|
|
21
21
|
line_kind = nil
|
22
22
|
state = :initial
|
23
|
-
|
23
|
+
deleted_lines_count = 0
|
24
24
|
scanners = Hash.new do |h, lang|
|
25
25
|
h[lang] = Scanners[lang].new '', :keep_tokens => true, :keep_state => true
|
26
26
|
end
|
@@ -30,7 +30,7 @@ module Scanners
|
|
30
30
|
until eos?
|
31
31
|
|
32
32
|
if match = scan(/\n/)
|
33
|
-
|
33
|
+
deleted_lines_count = 0 unless line_kind == :delete
|
34
34
|
if line_kind
|
35
35
|
encoder.end_line line_kind
|
36
36
|
line_kind = nil
|
@@ -45,7 +45,7 @@ module Scanners
|
|
45
45
|
if match = scan(/--- |\+\+\+ |=+|_+/)
|
46
46
|
encoder.begin_line line_kind = :head
|
47
47
|
encoder.text_token match, :head
|
48
|
-
if match = scan(
|
48
|
+
if match = scan(/[^\x00\n]+?(?=$|[\t\n]| \(revision)/)
|
49
49
|
encoder.text_token match, :filename
|
50
50
|
if options[:highlight_code] && match != '/dev/null'
|
51
51
|
file_type = CodeRay::FileType.fetch(match, :text)
|
@@ -69,7 +69,7 @@ module Scanners
|
|
69
69
|
state = :added
|
70
70
|
elsif match = scan(/\\ .*/)
|
71
71
|
encoder.text_token match, :comment
|
72
|
-
elsif match = scan(/@@(?>[^@\n]
|
72
|
+
elsif match = scan(/@@(?>[^@\n]+)@@/)
|
73
73
|
content_scanner.state = :initial unless match?(/\n\+/)
|
74
74
|
content_scanner_entry_state = nil
|
75
75
|
if check(/\n|$/)
|
@@ -99,37 +99,59 @@ module Scanners
|
|
99
99
|
end
|
100
100
|
next
|
101
101
|
elsif match = scan(/-/)
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
102
|
+
deleted_lines_count += 1
|
103
|
+
if options[:inline_diff] && deleted_lines_count == 1 && (changed_lines_count = 1 + check(/.*(?:\n\-.*)*/).count("\n")) && match?(/(?>.*(?:\n\-.*){#{changed_lines_count - 1}}(?:\n\+.*){#{changed_lines_count}})$(?!\n\+)/)
|
104
|
+
deleted_lines = Array.new(changed_lines_count) { |i| skip(/\n\-/) if i > 0; scan(/.*/) }
|
105
|
+
inserted_lines = Array.new(changed_lines_count) { |i| skip(/\n\+/) ; scan(/.*/) }
|
106
|
+
|
107
|
+
deleted_lines_tokenized = []
|
108
|
+
inserted_lines_tokenized = []
|
109
|
+
for deleted_line, inserted_line in deleted_lines.zip(inserted_lines)
|
110
|
+
pre, deleted_part, inserted_part, post = diff deleted_line, inserted_line
|
111
|
+
content_scanner_entry_state = content_scanner.state
|
112
|
+
deleted_lines_tokenized << content_scanner.tokenize([pre, deleted_part, post], :tokens => Tokens.new)
|
113
|
+
content_scanner.state = content_scanner_entry_state || :initial
|
114
|
+
inserted_lines_tokenized << content_scanner.tokenize([pre, inserted_part, post], :tokens => Tokens.new)
|
115
115
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
encoder.tokens
|
127
|
-
encoder.
|
116
|
+
|
117
|
+
for pre, deleted_part, post in deleted_lines_tokenized
|
118
|
+
encoder.begin_line :delete
|
119
|
+
encoder.text_token '-', :delete
|
120
|
+
encoder.tokens pre
|
121
|
+
unless deleted_part.empty?
|
122
|
+
encoder.begin_group :eyecatcher
|
123
|
+
encoder.tokens deleted_part
|
124
|
+
encoder.end_group :eyecatcher
|
125
|
+
end
|
126
|
+
encoder.tokens post
|
127
|
+
encoder.end_line :delete
|
128
|
+
encoder.text_token "\n", :space
|
129
|
+
end
|
130
|
+
|
131
|
+
for pre, inserted_part, post in inserted_lines_tokenized
|
132
|
+
encoder.begin_line :insert
|
133
|
+
encoder.text_token '+', :insert
|
134
|
+
encoder.tokens pre
|
135
|
+
unless inserted_part.empty?
|
136
|
+
encoder.begin_group :eyecatcher
|
137
|
+
encoder.tokens inserted_part
|
138
|
+
encoder.end_group :eyecatcher
|
139
|
+
end
|
140
|
+
encoder.tokens post
|
141
|
+
changed_lines_count -= 1
|
142
|
+
if changed_lines_count > 0
|
143
|
+
encoder.end_line :insert
|
144
|
+
encoder.text_token "\n", :space
|
145
|
+
end
|
128
146
|
end
|
129
|
-
|
147
|
+
|
148
|
+
line_kind = :insert
|
149
|
+
|
130
150
|
elsif match = scan(/.*/)
|
151
|
+
encoder.begin_line line_kind = :delete
|
152
|
+
encoder.text_token '-', :delete
|
131
153
|
if options[:highlight_code]
|
132
|
-
if
|
154
|
+
if deleted_lines_count == 1
|
133
155
|
content_scanner_entry_state = content_scanner.state
|
134
156
|
end
|
135
157
|
content_scanner.tokenize match, :tokens => encoder unless match.empty?
|
@@ -36,9 +36,12 @@ module Scanners
|
|
36
36
|
|
37
37
|
protected
|
38
38
|
|
39
|
+
def setup
|
40
|
+
@state = :initial
|
41
|
+
end
|
42
|
+
|
39
43
|
def scan_tokens encoder, options
|
40
|
-
|
41
|
-
state = :initial
|
44
|
+
state = options[:state] || @state
|
42
45
|
inline_block_stack = []
|
43
46
|
inline_block_paren_depth = nil
|
44
47
|
string_delimiter = nil
|
@@ -223,7 +226,7 @@ module Scanners
|
|
223
226
|
encoder.text_token match, :content # TODO: Shouldn't this be :error?
|
224
227
|
|
225
228
|
elsif match = scan(/ \\ | \n /x)
|
226
|
-
encoder.end_group state
|
229
|
+
encoder.end_group state == :regexp ? :regexp : :string
|
227
230
|
encoder.text_token match, :error
|
228
231
|
after_def = value_expected = false
|
229
232
|
state = :initial
|
@@ -243,7 +246,17 @@ module Scanners
|
|
243
246
|
end
|
244
247
|
|
245
248
|
if [:multiline_string, :string, :regexp].include? state
|
246
|
-
encoder.end_group state
|
249
|
+
encoder.end_group state == :regexp ? :regexp : :string
|
250
|
+
end
|
251
|
+
|
252
|
+
if options[:keep_state]
|
253
|
+
@state = state
|
254
|
+
end
|
255
|
+
|
256
|
+
until inline_block_stack.empty?
|
257
|
+
state, = *inline_block_stack.pop
|
258
|
+
encoder.end_group :inline
|
259
|
+
encoder.end_group state == :regexp ? :regexp : :string
|
247
260
|
end
|
248
261
|
|
249
262
|
encoder
|