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.
- data/{lib/README → README_INDEX.rdoc} +10 -21
- data/Rakefile +6 -6
- data/bin/coderay +193 -64
- data/lib/coderay.rb +61 -105
- data/lib/coderay/duo.rb +17 -21
- data/lib/coderay/encoder.rb +100 -112
- data/lib/coderay/encoders/_map.rb +12 -7
- data/lib/coderay/encoders/comment_filter.rb +12 -30
- data/lib/coderay/encoders/count.rb +29 -11
- data/lib/coderay/encoders/debug.rb +32 -20
- data/lib/coderay/encoders/div.rb +13 -9
- data/lib/coderay/encoders/filter.rb +34 -51
- data/lib/coderay/encoders/html.rb +155 -161
- data/lib/coderay/encoders/html/css.rb +4 -9
- data/lib/coderay/encoders/html/numbering.rb +115 -0
- data/lib/coderay/encoders/html/output.rb +22 -70
- data/lib/coderay/encoders/json.rb +59 -45
- data/lib/coderay/encoders/lines_of_code.rb +12 -57
- data/lib/coderay/encoders/null.rb +6 -14
- data/lib/coderay/encoders/page.rb +13 -9
- data/lib/coderay/encoders/span.rb +13 -9
- data/lib/coderay/encoders/statistic.rb +58 -39
- data/lib/coderay/encoders/terminal.rb +179 -0
- data/lib/coderay/encoders/text.rb +31 -17
- data/lib/coderay/encoders/token_kind_filter.rb +111 -0
- data/lib/coderay/encoders/xml.rb +19 -18
- data/lib/coderay/encoders/yaml.rb +37 -9
- data/lib/coderay/for_redcloth.rb +4 -4
- data/lib/coderay/helpers/file_type.rb +127 -246
- data/lib/coderay/helpers/gzip.rb +41 -0
- data/lib/coderay/helpers/plugin.rb +241 -306
- data/lib/coderay/helpers/word_list.rb +65 -126
- data/lib/coderay/scanner.rb +173 -156
- data/lib/coderay/scanners/_map.rb +18 -17
- data/lib/coderay/scanners/c.rb +63 -77
- data/lib/coderay/scanners/clojure.rb +217 -0
- data/lib/coderay/scanners/cpp.rb +71 -84
- data/lib/coderay/scanners/css.rb +103 -120
- data/lib/coderay/scanners/debug.rb +47 -44
- data/lib/coderay/scanners/delphi.rb +70 -76
- data/lib/coderay/scanners/diff.rb +141 -50
- data/lib/coderay/scanners/erb.rb +81 -0
- data/lib/coderay/scanners/groovy.rb +104 -113
- data/lib/coderay/scanners/haml.rb +168 -0
- data/lib/coderay/scanners/html.rb +181 -110
- data/lib/coderay/scanners/java.rb +73 -75
- data/lib/coderay/scanners/java/builtin_types.rb +2 -0
- data/lib/coderay/scanners/java_script.rb +90 -101
- data/lib/coderay/scanners/json.rb +40 -53
- data/lib/coderay/scanners/php.rb +123 -147
- data/lib/coderay/scanners/python.rb +93 -91
- data/lib/coderay/scanners/raydebug.rb +66 -0
- data/lib/coderay/scanners/ruby.rb +343 -326
- data/lib/coderay/scanners/ruby/patterns.rb +40 -106
- data/lib/coderay/scanners/ruby/string_state.rb +71 -0
- data/lib/coderay/scanners/sql.rb +80 -66
- data/lib/coderay/scanners/text.rb +26 -0
- data/lib/coderay/scanners/xml.rb +1 -1
- data/lib/coderay/scanners/yaml.rb +74 -73
- data/lib/coderay/style.rb +10 -7
- data/lib/coderay/styles/_map.rb +3 -3
- data/lib/coderay/styles/alpha.rb +143 -0
- data/lib/coderay/token_kinds.rb +90 -0
- data/lib/coderay/tokens.rb +102 -277
- data/lib/coderay/tokens_proxy.rb +55 -0
- data/lib/coderay/version.rb +3 -0
- data/test/functional/basic.rb +200 -18
- data/test/functional/examples.rb +130 -0
- data/test/functional/for_redcloth.rb +15 -8
- data/test/functional/suite.rb +9 -6
- metadata +103 -123
- data/FOLDERS +0 -53
- data/bin/coderay_stylesheet +0 -4
- data/lib/coderay/encoders/html/numerization.rb +0 -133
- data/lib/coderay/encoders/term.rb +0 -158
- data/lib/coderay/encoders/token_class_filter.rb +0 -84
- data/lib/coderay/helpers/gzip_simple.rb +0 -123
- data/lib/coderay/scanners/nitro_xhtml.rb +0 -136
- data/lib/coderay/scanners/plaintext.rb +0 -20
- data/lib/coderay/scanners/rhtml.rb +0 -78
- data/lib/coderay/scanners/scheme.rb +0 -145
- data/lib/coderay/styles/cycnus.rb +0 -152
- data/lib/coderay/styles/murphy.rb +0 -134
- data/lib/coderay/token_classes.rb +0 -86
- data/test/functional/load_plugin_scanner.rb +0 -11
- data/test/functional/vhdl.rb +0 -126
- 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:
|
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
|
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
|
-
|
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
|
-
|
65
|
+
encoder.text_token match, :comment
|
67
66
|
|
68
|
-
elsif bol? && scan(/ \#!.* /x)
|
69
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
121
|
-
|
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
|
-
|
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
|
-
|
132
|
-
elsif scan(/(?>0[0-7]+)(?![89.eEfF])/)
|
133
|
-
|
134
|
-
elsif scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/)
|
135
|
-
|
136
|
-
elsif scan(/\d+[lLgG]?/)
|
137
|
-
|
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
|
-
|
143
|
+
encoder.begin_group :string
|
144
144
|
string_delimiter = match
|
145
|
-
|
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
|
-
|
151
|
+
encoder.begin_group state
|
152
152
|
string_delimiter = match
|
153
|
-
|
154
|
-
|
155
|
-
elsif value_expected &&
|
153
|
+
encoder.text_token match, :delimiter
|
154
|
+
|
155
|
+
elsif value_expected && match = scan(/\//)
|
156
156
|
after_def = value_expected = false
|
157
|
-
|
157
|
+
encoder.begin_group :regexp
|
158
158
|
state = :regexp
|
159
159
|
string_delimiter = '/'
|
160
|
-
|
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
|
-
|
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
|
-
|
170
|
-
|
169
|
+
encoder.text_token match, :operator
|
170
|
+
|
171
171
|
else
|
172
|
-
getch
|
173
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
185
|
+
encoder.text_token modifiers, :modifier if modifiers && !modifiers.empty?
|
187
186
|
end
|
188
187
|
state = :string if state == :multiline_string
|
189
|
-
|
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
|
-
|
197
|
+
encoder.text_token match, :content
|
199
198
|
else
|
200
|
-
|
199
|
+
encoder.text_token match, :char
|
201
200
|
end
|
202
|
-
elsif state == :regexp && scan(/ \\ (?: #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
|
203
|
-
|
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
|
-
|
207
|
-
|
205
|
+
encoder.begin_group :inline
|
206
|
+
encoder.text_token '$', :inline_delimiter
|
208
207
|
match = match[1..-1]
|
209
|
-
|
210
|
-
|
208
|
+
encoder.text_token match, IDENT_KIND[match]
|
209
|
+
encoder.end_group :inline
|
211
210
|
next
|
212
211
|
elsif match = scan(/ \$ \{ /x)
|
213
|
-
|
214
|
-
|
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
|
-
|
222
|
-
|
223
|
-
elsif scan(/ \\. /mx)
|
224
|
-
|
225
|
-
|
226
|
-
elsif scan(/ \\ | \n /x)
|
227
|
-
|
228
|
-
|
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),
|
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',
|
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
|
-
|
246
|
+
encoder.end_group state
|
256
247
|
end
|
257
|
-
|
258
|
-
|
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
|