coderay 1.0.9 → 1.1.0.rc1
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.
- 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
@@ -1,13 +1,13 @@
|
|
1
1
|
module CodeRay
|
2
2
|
module Scanners
|
3
|
-
|
3
|
+
|
4
4
|
# HTML Scanner
|
5
5
|
#
|
6
6
|
# Alias: +xhtml+
|
7
7
|
#
|
8
8
|
# See also: Scanners::XML
|
9
9
|
class HTML < Scanner
|
10
|
-
|
10
|
+
|
11
11
|
register_for :html
|
12
12
|
|
13
13
|
KINDS_NOT_LOC = [
|
@@ -33,7 +33,8 @@ module Scanners
|
|
33
33
|
)
|
34
34
|
|
35
35
|
IN_ATTRIBUTE = WordList::CaseIgnoring.new(nil).
|
36
|
-
add(EVENT_ATTRIBUTES, :script)
|
36
|
+
add(EVENT_ATTRIBUTES, :script).
|
37
|
+
add(['style'], :style)
|
37
38
|
|
38
39
|
ATTR_NAME = /[\w.:-]+/ # :nodoc:
|
39
40
|
TAG_END = /\/?>/ # :nodoc:
|
@@ -75,9 +76,14 @@ module Scanners
|
|
75
76
|
def scan_java_script encoder, code
|
76
77
|
if code && !code.empty?
|
77
78
|
@java_script_scanner ||= Scanners::JavaScript.new '', :keep_tokens => true
|
78
|
-
# encoder.begin_group :inline
|
79
79
|
@java_script_scanner.tokenize code, :tokens => encoder
|
80
|
-
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def scan_css encoder, code, state = [:initial]
|
84
|
+
if code && !code.empty?
|
85
|
+
@css_scanner ||= Scanners::CSS.new '', :keep_tokens => true
|
86
|
+
@css_scanner.tokenize code, :tokens => encoder, :state => state
|
81
87
|
end
|
82
88
|
end
|
83
89
|
|
@@ -99,7 +105,15 @@ module Scanners
|
|
99
105
|
case state
|
100
106
|
|
101
107
|
when :initial
|
102
|
-
if match = scan(
|
108
|
+
if match = scan(/<!\[CDATA\[/)
|
109
|
+
encoder.text_token match, :inline_delimiter
|
110
|
+
if match = scan(/.*?\]\]>/m)
|
111
|
+
encoder.text_token match[0..-4], :plain
|
112
|
+
encoder.text_token ']]>', :inline_delimiter
|
113
|
+
elsif match = scan(/.+/)
|
114
|
+
encoder.text_token match, :error
|
115
|
+
end
|
116
|
+
elsif match = scan(/<!--(?:.*?-->|.*)/m)
|
103
117
|
encoder.text_token match, :comment
|
104
118
|
elsif match = scan(/<!(\w+)(?:.*?>|.*)|\]>/m)
|
105
119
|
encoder.text_token match, :doctype
|
@@ -110,7 +124,7 @@ module Scanners
|
|
110
124
|
elsif match = scan(/<\/[-\w.:]*>?/m)
|
111
125
|
in_tag = nil
|
112
126
|
encoder.text_token match, :tag
|
113
|
-
elsif match = scan(/<(?:(script)|[-\w.:]+)(>)?/m)
|
127
|
+
elsif match = scan(/<(?:(script|style)|[-\w.:]+)(>)?/m)
|
114
128
|
encoder.text_token match, :tag
|
115
129
|
in_tag = self[1]
|
116
130
|
if self[2]
|
@@ -161,17 +175,21 @@ module Scanners
|
|
161
175
|
encoder.text_token match, :attribute_value
|
162
176
|
state = :attribute
|
163
177
|
elsif match = scan(/["']/)
|
164
|
-
if in_attribute == :script
|
165
|
-
encoder.begin_group :
|
166
|
-
encoder.text_token match, :
|
178
|
+
if in_attribute == :script || in_attribute == :style
|
179
|
+
encoder.begin_group :string
|
180
|
+
encoder.text_token match, :delimiter
|
167
181
|
if scan(/javascript:[ \t]*/)
|
168
182
|
encoder.text_token matched, :comment
|
169
183
|
end
|
170
184
|
code = scan_until(match == '"' ? /(?="|\z)/ : /(?='|\z)/)
|
171
|
-
|
185
|
+
if in_attribute == :script
|
186
|
+
scan_java_script encoder, code
|
187
|
+
else
|
188
|
+
scan_css encoder, code, [:block]
|
189
|
+
end
|
172
190
|
match = scan(/["']/)
|
173
|
-
encoder.text_token match, :
|
174
|
-
encoder.end_group :
|
191
|
+
encoder.text_token match, :delimiter if match
|
192
|
+
encoder.end_group :string
|
175
193
|
state = :attribute
|
176
194
|
in_attribute = nil
|
177
195
|
else
|
@@ -206,19 +224,23 @@ module Scanners
|
|
206
224
|
|
207
225
|
when :in_special_tag
|
208
226
|
case in_tag
|
209
|
-
when 'script'
|
227
|
+
when 'script', 'style'
|
210
228
|
encoder.text_token match, :space if match = scan(/[ \t]*\n/)
|
211
229
|
if scan(/(\s*<!--)(?:(.*?)(-->)|(.*))/m)
|
212
230
|
code = self[2] || self[4]
|
213
231
|
closing = self[3]
|
214
232
|
encoder.text_token self[1], :comment
|
215
233
|
else
|
216
|
-
code = scan_until(/(?=(?:\n\s*)
|
234
|
+
code = scan_until(/(?=(?:\n\s*)?<\/#{in_tag}>)|\z/)
|
217
235
|
closing = false
|
218
236
|
end
|
219
237
|
unless code.empty?
|
220
238
|
encoder.begin_group :inline
|
221
|
-
|
239
|
+
if in_tag == 'script'
|
240
|
+
scan_java_script encoder, code
|
241
|
+
else
|
242
|
+
scan_css encoder, code
|
243
|
+
end
|
222
244
|
encoder.end_group :inline
|
223
245
|
end
|
224
246
|
encoder.text_token closing, :comment if closing
|
@@ -147,7 +147,7 @@ module Scanners
|
|
147
147
|
elsif match = scan(/ \\ | $ /x)
|
148
148
|
encoder.end_group state
|
149
149
|
state = :initial
|
150
|
-
encoder.text_token match, :error
|
150
|
+
encoder.text_token match, :error unless match.empty?
|
151
151
|
else
|
152
152
|
raise_inspect "else case \" reached; %p not handled." % peek(1), encoder
|
153
153
|
end
|
@@ -54,10 +54,17 @@ module Scanners
|
|
54
54
|
|
55
55
|
protected
|
56
56
|
|
57
|
+
def setup
|
58
|
+
@state = :initial
|
59
|
+
end
|
60
|
+
|
57
61
|
def scan_tokens encoder, options
|
58
62
|
|
59
|
-
state = :
|
60
|
-
string_delimiter
|
63
|
+
state, string_delimiter = options[:state] || @state
|
64
|
+
if string_delimiter
|
65
|
+
encoder.begin_group state
|
66
|
+
end
|
67
|
+
|
61
68
|
value_expected = true
|
62
69
|
key_expected = false
|
63
70
|
function_expected = false
|
@@ -72,9 +79,10 @@ module Scanners
|
|
72
79
|
value_expected = true if !value_expected && match.index(?\n)
|
73
80
|
encoder.text_token match, :space
|
74
81
|
|
75
|
-
elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
|
82
|
+
elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .*() ) !mx)
|
76
83
|
value_expected = true
|
77
84
|
encoder.text_token match, :comment
|
85
|
+
state = :open_multi_line_comment if self[1]
|
78
86
|
|
79
87
|
elsif check(/\.?\d/)
|
80
88
|
key_expected = value_expected = false
|
@@ -175,20 +183,36 @@ module Scanners
|
|
175
183
|
encoder.text_token match, :content
|
176
184
|
elsif match = scan(/ \\ | $ /x)
|
177
185
|
encoder.end_group state
|
178
|
-
encoder.text_token match, :error
|
186
|
+
encoder.text_token match, :error unless match.empty?
|
187
|
+
string_delimiter = nil
|
179
188
|
key_expected = value_expected = false
|
180
189
|
state = :initial
|
181
190
|
else
|
182
|
-
raise_inspect "else case
|
191
|
+
raise_inspect "else case #{string_delimiter} reached; %p not handled." % peek(1), encoder
|
183
192
|
end
|
184
193
|
|
194
|
+
when :open_multi_line_comment
|
195
|
+
if match = scan(%r! .*? \*/ !mx)
|
196
|
+
state = :initial
|
197
|
+
else
|
198
|
+
match = scan(%r! .+ !mx)
|
199
|
+
end
|
200
|
+
value_expected = true
|
201
|
+
encoder.text_token match, :comment if match
|
202
|
+
|
185
203
|
else
|
186
|
-
|
204
|
+
#:nocov:
|
205
|
+
raise_inspect 'Unknown state: %p' % [state], encoder
|
206
|
+
#:nocov:
|
187
207
|
|
188
208
|
end
|
189
209
|
|
190
210
|
end
|
191
211
|
|
212
|
+
if options[:keep_state]
|
213
|
+
@state = state, string_delimiter
|
214
|
+
end
|
215
|
+
|
192
216
|
if [:string, :regexp].include? state
|
193
217
|
encoder.end_group state
|
194
218
|
end
|
@@ -14,15 +14,21 @@ module Scanners
|
|
14
14
|
|
15
15
|
ESCAPE = / [bfnrt\\"\/] /x # :nodoc:
|
16
16
|
UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # :nodoc:
|
17
|
+
KEY = / (?> (?: [^\\"]+ | \\. )* ) " \s* : /x
|
17
18
|
|
18
19
|
protected
|
19
20
|
|
21
|
+
def setup
|
22
|
+
@state = :initial
|
23
|
+
end
|
24
|
+
|
20
25
|
# See http://json.org/ for a definition of the JSON lexic/grammar.
|
21
26
|
def scan_tokens encoder, options
|
27
|
+
state = options[:state] || @state
|
22
28
|
|
23
|
-
|
24
|
-
|
25
|
-
|
29
|
+
if [:string, :key].include? state
|
30
|
+
encoder.begin_group state
|
31
|
+
end
|
26
32
|
|
27
33
|
until eos?
|
28
34
|
|
@@ -32,18 +38,11 @@ module Scanners
|
|
32
38
|
if match = scan(/ \s+ /x)
|
33
39
|
encoder.text_token match, :space
|
34
40
|
elsif match = scan(/"/)
|
35
|
-
state =
|
41
|
+
state = check(/#{KEY}/o) ? :key : :string
|
36
42
|
encoder.begin_group state
|
37
43
|
encoder.text_token match, :delimiter
|
38
44
|
elsif match = scan(/ [:,\[{\]}] /x)
|
39
45
|
encoder.text_token match, :operator
|
40
|
-
case match
|
41
|
-
when ':' then key_expected = false
|
42
|
-
when ',' then key_expected = true if stack.last == :object
|
43
|
-
when '{' then stack << :object; key_expected = true
|
44
|
-
when '[' then stack << :array
|
45
|
-
when '}', ']' then stack.pop # no error recovery, but works for valid JSON
|
46
|
-
end
|
47
46
|
elsif match = scan(/ true | false | null /x)
|
48
47
|
encoder.text_token match, :value
|
49
48
|
elsif match = scan(/ -? (?: 0 | [1-9]\d* ) /x)
|
@@ -70,7 +69,7 @@ module Scanners
|
|
70
69
|
encoder.text_token match, :content
|
71
70
|
elsif match = scan(/ \\ | $ /x)
|
72
71
|
encoder.end_group state
|
73
|
-
encoder.text_token match, :error
|
72
|
+
encoder.text_token match, :error unless match.empty?
|
74
73
|
state = :initial
|
75
74
|
else
|
76
75
|
raise_inspect "else case \" reached; %p not handled." % peek(1), encoder
|
@@ -82,6 +81,10 @@ module Scanners
|
|
82
81
|
end
|
83
82
|
end
|
84
83
|
|
84
|
+
if options[:keep_state]
|
85
|
+
@state = state
|
86
|
+
end
|
87
|
+
|
85
88
|
if [:string, :key].include? state
|
86
89
|
encoder.end_group state
|
87
90
|
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module CodeRay
|
4
|
+
module Scanners
|
5
|
+
|
6
|
+
# Scanner for the Lua[http://lua.org] programming lanuage.
|
7
|
+
#
|
8
|
+
# The language’s complete syntax is defined in
|
9
|
+
# {the Lua manual}[http://www.lua.org/manual/5.2/manual.html],
|
10
|
+
# which is what this scanner tries to conform to.
|
11
|
+
class Lua < Scanner
|
12
|
+
|
13
|
+
register_for :lua
|
14
|
+
file_extension 'lua'
|
15
|
+
title 'Lua'
|
16
|
+
|
17
|
+
# Keywords used in Lua.
|
18
|
+
KEYWORDS = %w[and break do else elseif end
|
19
|
+
for function goto if in
|
20
|
+
local not or repeat return
|
21
|
+
then until while
|
22
|
+
]
|
23
|
+
|
24
|
+
# Constants set by the Lua core.
|
25
|
+
PREDEFINED_CONSTANTS = %w[false true nil]
|
26
|
+
|
27
|
+
# The expressions contained in this array are parts of Lua’s `basic'
|
28
|
+
# library. Although it’s not entirely necessary to load that library,
|
29
|
+
# it is highly recommended and one would have to provide own implementations
|
30
|
+
# of some of these expressions if one does not do so. They however aren’t
|
31
|
+
# keywords, neither are they constants, but nearly predefined, so they
|
32
|
+
# get tagged as `predefined' rather than anything else.
|
33
|
+
#
|
34
|
+
# This list excludes values of form `_UPPERCASE' because the Lua manual
|
35
|
+
# requires such identifiers to be reserved by Lua anyway and they are
|
36
|
+
# highlighted directly accordingly, without the need for specific
|
37
|
+
# identifiers to be listed here.
|
38
|
+
PREDEFINED_EXPRESSIONS = %w[
|
39
|
+
assert collectgarbage dofile error getmetatable
|
40
|
+
ipairs load loadfile next pairs pcall print
|
41
|
+
rawequal rawget rawlen rawset select setmetatable
|
42
|
+
tonumber tostring type xpcall
|
43
|
+
]
|
44
|
+
|
45
|
+
# Automatic token kind selection for normal words.
|
46
|
+
IDENT_KIND = CodeRay::WordList.new(:ident).
|
47
|
+
add(KEYWORDS, :keyword).
|
48
|
+
add(PREDEFINED_CONSTANTS, :predefined_constant).
|
49
|
+
add(PREDEFINED_EXPRESSIONS, :predefined)
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
# Scanner initialization.
|
54
|
+
def setup
|
55
|
+
@state = :initial
|
56
|
+
@brace_depth = 0
|
57
|
+
end
|
58
|
+
|
59
|
+
# CodeRay entry hook. Starts parsing.
|
60
|
+
def scan_tokens(encoder, options)
|
61
|
+
state = options[:state] || @state
|
62
|
+
brace_depth = @brace_depth
|
63
|
+
num_equals = nil
|
64
|
+
|
65
|
+
until eos?
|
66
|
+
case state
|
67
|
+
|
68
|
+
when :initial
|
69
|
+
if match = scan(/\-\-\[\=*\[/) #--[[ long (possibly multiline) comment ]]
|
70
|
+
num_equals = match.count("=") # Number must match for comment end
|
71
|
+
encoder.begin_group(:comment)
|
72
|
+
encoder.text_token(match, :delimiter)
|
73
|
+
state = :long_comment
|
74
|
+
|
75
|
+
elsif match = scan(/--.*$/) # --Lua comment
|
76
|
+
encoder.text_token(match, :comment)
|
77
|
+
|
78
|
+
elsif match = scan(/\[=*\[/) # [[ long (possibly multiline) string ]]
|
79
|
+
num_equals = match.count("=") # Number must match for comment end
|
80
|
+
encoder.begin_group(:string)
|
81
|
+
encoder.text_token(match, :delimiter)
|
82
|
+
state = :long_string
|
83
|
+
|
84
|
+
elsif match = scan(/::\s*[a-zA-Z_][a-zA-Z0-9_]+\s*::/) # ::goto_label::
|
85
|
+
encoder.text_token(match, :label)
|
86
|
+
|
87
|
+
elsif match = scan(/_[A-Z]+/) # _UPPERCASE are names reserved for Lua
|
88
|
+
encoder.text_token(match, :predefined)
|
89
|
+
|
90
|
+
elsif match = scan(/[a-zA-Z_][a-zA-Z0-9_]*/) # Normal letters (or letters followed by digits)
|
91
|
+
kind = IDENT_KIND[match]
|
92
|
+
|
93
|
+
# Extra highlighting for entities following certain keywords
|
94
|
+
if kind == :keyword and match == "function"
|
95
|
+
state = :function_expected
|
96
|
+
elsif kind == :keyword and match == "goto"
|
97
|
+
state = :goto_label_expected
|
98
|
+
elsif kind == :keyword and match == "local"
|
99
|
+
state = :local_var_expected
|
100
|
+
end
|
101
|
+
|
102
|
+
encoder.text_token(match, kind)
|
103
|
+
|
104
|
+
elsif match = scan(/\{/) # Opening table brace {
|
105
|
+
encoder.begin_group(:map)
|
106
|
+
encoder.text_token(match, brace_depth >= 1 ? :inline_delimiter : :delimiter)
|
107
|
+
brace_depth += 1
|
108
|
+
state = :map
|
109
|
+
|
110
|
+
elsif match = scan(/\}/) # Closing table brace }
|
111
|
+
if brace_depth == 1
|
112
|
+
brace_depth = 0
|
113
|
+
encoder.text_token(match, :delimiter)
|
114
|
+
encoder.end_group(:map)
|
115
|
+
elsif brace_depth == 0 # Mismatched brace
|
116
|
+
encoder.text_token(match, :error)
|
117
|
+
else
|
118
|
+
brace_depth -= 1
|
119
|
+
encoder.text_token(match, :inline_delimiter)
|
120
|
+
encoder.end_group(:map)
|
121
|
+
state = :map
|
122
|
+
end
|
123
|
+
|
124
|
+
elsif match = scan(/["']/) # String delimiters " and '
|
125
|
+
encoder.begin_group(:string)
|
126
|
+
encoder.text_token(match, :delimiter)
|
127
|
+
start_delim = match
|
128
|
+
state = :string
|
129
|
+
|
130
|
+
# ↓Prefix hex number ←|→ decimal number
|
131
|
+
elsif match = scan(/-? (?:0x\h* \. \h+ (?:p[+\-]?\d+)? | \d*\.\d+ (?:e[+\-]?\d+)?)/ix) # hexadecimal constants have no E power, decimal ones no P power
|
132
|
+
encoder.text_token(match, :float)
|
133
|
+
|
134
|
+
# ↓Prefix hex number ←|→ decimal number
|
135
|
+
elsif match = scan(/-? (?:0x\h+ (?:p[+\-]?\d+)? | \d+ (?:e[+\-]?\d+)?)/ix) # hexadecimal constants have no E power, decimal ones no P power
|
136
|
+
encoder.text_token(match, :integer)
|
137
|
+
|
138
|
+
elsif match = scan(/[\+\-\*\/%^\#=~<>\(\)\[\]:;,] | \.(?!\d)/x) # Operators
|
139
|
+
encoder.text_token(match, :operator)
|
140
|
+
|
141
|
+
elsif match = scan(/\s+/) # Space
|
142
|
+
encoder.text_token(match, :space)
|
143
|
+
|
144
|
+
else # Invalid stuff. Note that Lua doesn’t accept multibyte chars outside of strings, hence these are also errors.
|
145
|
+
encoder.text_token(getch, :error)
|
146
|
+
end
|
147
|
+
|
148
|
+
# It may be that we’re scanning a full-blown subexpression of a table
|
149
|
+
# (tables can contain full expressions in parts).
|
150
|
+
# If this is the case, return to :map scanning state.
|
151
|
+
state = :map if state == :initial && brace_depth >= 1
|
152
|
+
|
153
|
+
when :function_expected
|
154
|
+
if match = scan(/\(.*?\)/m) # x = function() # "Anonymous" function without explicit name
|
155
|
+
encoder.text_token(match, :operator)
|
156
|
+
state = :initial
|
157
|
+
elsif match = scan(/[a-zA-Z_] (?:[a-zA-Z0-9_\.] (?!\.\d))* [\.\:]/x) # function tbl.subtbl.foo() | function tbl:foo() # Colon only allowed as last separator
|
158
|
+
encoder.text_token(match, :ident)
|
159
|
+
elsif match = scan(/[a-zA-Z_][a-zA-Z0-9_]*/) # function foo()
|
160
|
+
encoder.text_token(match, :function)
|
161
|
+
state = :initial
|
162
|
+
elsif match = scan(/\s+/) # Between the `function' keyword and the ident may be any amount of whitespace
|
163
|
+
encoder.text_token(match, :space)
|
164
|
+
else
|
165
|
+
encoder.text_token(getch, :error)
|
166
|
+
state = :initial
|
167
|
+
end
|
168
|
+
|
169
|
+
when :goto_label_expected
|
170
|
+
if match = scan(/[a-zA-Z_][a-zA-Z0-9_]*/)
|
171
|
+
encoder.text_token(match, :label)
|
172
|
+
state = :initial
|
173
|
+
elsif match = scan(/\s+/) # Between the `goto' keyword and the label may be any amount of whitespace
|
174
|
+
encoder.text_token(match, :space)
|
175
|
+
else
|
176
|
+
encoder.text_token(getch, :error)
|
177
|
+
end
|
178
|
+
|
179
|
+
when :local_var_expected
|
180
|
+
if match = scan(/function/) # local function ...
|
181
|
+
encoder.text_token(match, :keyword)
|
182
|
+
state = :function_expected
|
183
|
+
elsif match = scan(/[a-zA-Z_][a-zA-Z0-9_]*/)
|
184
|
+
encoder.text_token(match, :local_variable)
|
185
|
+
elsif match = scan(/,/)
|
186
|
+
encoder.text_token(match, :operator)
|
187
|
+
elsif match = scan(/\=/)
|
188
|
+
encoder.text_token(match, :operator)
|
189
|
+
# After encountering the equal sign, arbitrary expressions are
|
190
|
+
# allowed again, so just return to the main state for further
|
191
|
+
# parsing.
|
192
|
+
state = :initial
|
193
|
+
elsif match = scan(/\n/)
|
194
|
+
encoder.text_token(match, :space)
|
195
|
+
state = :initial
|
196
|
+
elsif match = scan(/\s+/)
|
197
|
+
encoder.text_token(match, :space)
|
198
|
+
else
|
199
|
+
encoder.text_token(getch, :error)
|
200
|
+
end
|
201
|
+
|
202
|
+
when :long_comment
|
203
|
+
if match = scan(/.*?(?=\]={#{num_equals}}\])/m)
|
204
|
+
encoder.text_token(match, :content)
|
205
|
+
|
206
|
+
delim = scan(/\]={#{num_equals}}\]/)
|
207
|
+
encoder.text_token(delim, :delimiter)
|
208
|
+
else # No terminator found till EOF
|
209
|
+
encoder.text_token(rest, :error)
|
210
|
+
terminate
|
211
|
+
end
|
212
|
+
encoder.end_group(:comment)
|
213
|
+
state = :initial
|
214
|
+
|
215
|
+
when :long_string
|
216
|
+
if match = scan(/.*?(?=\]={#{num_equals}}\])/m) # Long strings do not interpret any escape sequences
|
217
|
+
encoder.text_token(match, :content)
|
218
|
+
|
219
|
+
delim = scan(/\]={#{num_equals}}\]/)
|
220
|
+
encoder.text_token(delim, :delimiter)
|
221
|
+
else # No terminator found till EOF
|
222
|
+
encoder.text_token(rest, :error)
|
223
|
+
terminate
|
224
|
+
end
|
225
|
+
encoder.end_group(:string)
|
226
|
+
state = :initial
|
227
|
+
|
228
|
+
when :string
|
229
|
+
if match = scan(/[^\\#{start_delim}\n]+/) # Everything except \ and the start delimiter character is string content (newlines are only allowed if preceeded by \ or \z)
|
230
|
+
encoder.text_token(match, :content)
|
231
|
+
elsif match = scan(/\\(?:['"abfnrtv\\]|z\s*|x\h\h|\d{1,3}|\n)/m)
|
232
|
+
encoder.text_token(match, :char)
|
233
|
+
elsif match = scan(Regexp.compile(start_delim))
|
234
|
+
encoder.text_token(match, :delimiter)
|
235
|
+
encoder.end_group(:string)
|
236
|
+
state = :initial
|
237
|
+
elsif match = scan(/\n/) # Lua forbids unescaped newlines in normal non-long strings
|
238
|
+
encoder.text_token("\\n\n", :error) # Visually appealing error indicator--otherwise users may wonder whether the highlighter cannot highlight multine strings
|
239
|
+
encoder.end_group(:string)
|
240
|
+
state = :initial
|
241
|
+
else
|
242
|
+
encoder.text_token(getch, :error)
|
243
|
+
end
|
244
|
+
|
245
|
+
when :map
|
246
|
+
if match = scan(/[,;]/)
|
247
|
+
encoder.text_token(match, :operator)
|
248
|
+
elsif match = scan(/[a-zA-Z_][a-zA-Z0-9_]* (?=\s*=)/x)
|
249
|
+
encoder.text_token(match, :key)
|
250
|
+
encoder.text_token(scan(/\s+/), :space) if check(/\s+/)
|
251
|
+
encoder.text_token(scan(/\=/), :operator)
|
252
|
+
state = :initial
|
253
|
+
elsif match = scan(/\s+/m)
|
254
|
+
encoder.text_token(match, :space)
|
255
|
+
else
|
256
|
+
# Note this clause doesn’t advance the scan pointer, it’s a kind of
|
257
|
+
# "retry with other options" (the :initial state then of course
|
258
|
+
# advances the pointer).
|
259
|
+
state = :initial
|
260
|
+
end
|
261
|
+
else
|
262
|
+
raise
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
266
|
+
|
267
|
+
if options[:keep_state]
|
268
|
+
@state = state
|
269
|
+
end
|
270
|
+
|
271
|
+
encoder.end_group :string if [:string].include? state
|
272
|
+
brace_depth.times { encoder.end_group :map }
|
273
|
+
|
274
|
+
encoder
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
|
279
|
+
end
|
280
|
+
end
|