Skip to content

Commit 7493dcb

Browse files
committed
Merge pull request rubychan#147 from rubychan/go-scanner
Go scanner
2 parents ee72fe9 + 82864ef commit 7493dcb

File tree

4 files changed

+212
-1
lines changed

4 files changed

+212
-1
lines changed

Changes.textile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ h2. Changes in 1.1
66

77
* New scanner: Lua [#21, #22, thanks to Quintus]
88
* New scanner: Sass [#93]
9+
* New scanner: Go [#28, thanks to Eric Guo and Nathan Youngman]
910
* New scanner: Taskpaper [#39, thanks to shimomura]
1011
* Diff scanner: Highlight inline changes in multi-line changes [#99]
1112
* JavaScript scanner: Highlight multi-line comments in diff correctly

lib/coderay/helpers/file_type.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def shebang filename
8686
'dpr' => :delphi,
8787
'erb' => :erb,
8888
'gemspec' => :ruby,
89+
'go' => :go,
8990
'groovy' => :groovy,
9091
'gvy' => :groovy,
9192
'h' => :c,

lib/coderay/scanners/go.rb

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
module CodeRay
2+
module Scanners
3+
4+
# Scanner for Go, copy from c
5+
class Go < Scanner
6+
7+
register_for :go
8+
file_extension 'go'
9+
10+
# http://golang.org/ref/spec#Keywords
11+
KEYWORDS = [
12+
'break', 'default', 'func', 'interface', 'select',
13+
'case', 'defer', 'go', 'map', 'struct',
14+
'chan', 'else', 'goto', 'package', 'switch',
15+
'const', 'fallthrough', 'if', 'range', 'type',
16+
'continue', 'for', 'import', 'return', 'var',
17+
] # :nodoc:
18+
19+
# http://golang.org/ref/spec#Types
20+
PREDEFINED_TYPES = [
21+
'bool',
22+
'uint8', 'uint16', 'uint32', 'uint64',
23+
'int8', 'int16', 'int32', 'int64',
24+
'float32', 'float64',
25+
'complex64', 'complex128',
26+
'byte', 'rune', 'string', 'error',
27+
'uint', 'int', 'uintptr',
28+
] # :nodoc:
29+
30+
PREDEFINED_CONSTANTS = [
31+
'nil', 'iota',
32+
'true', 'false',
33+
] # :nodoc:
34+
35+
PREDEFINED_FUNCTIONS = %w[
36+
append cap close complex copy delete imag len
37+
make new panic print println real recover
38+
] # :nodoc:
39+
40+
IDENT_KIND = WordList.new(:ident).
41+
add(KEYWORDS, :keyword).
42+
add(PREDEFINED_TYPES, :predefined_type).
43+
add(PREDEFINED_CONSTANTS, :predefined_constant).
44+
add(PREDEFINED_FUNCTIONS, :predefined) # :nodoc:
45+
46+
ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc:
47+
UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc:
48+
49+
protected
50+
51+
def scan_tokens encoder, options
52+
53+
state = :initial
54+
label_expected = true
55+
case_expected = false
56+
label_expected_before_preproc_line = nil
57+
in_preproc_line = false
58+
59+
until eos?
60+
61+
case state
62+
63+
when :initial
64+
65+
if match = scan(/ \s+ | \\\n /x)
66+
if in_preproc_line && match != "\\\n" && match.index(?\n)
67+
in_preproc_line = false
68+
case_expected = false
69+
label_expected = label_expected_before_preproc_line
70+
end
71+
encoder.text_token match, :space
72+
73+
elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
74+
encoder.text_token match, :comment
75+
76+
elsif match = scan(/ <?- (?![\d.]) | [+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x)
77+
if case_expected
78+
label_expected = true if match == ':'
79+
case_expected = false
80+
end
81+
encoder.text_token match, :operator
82+
83+
elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x)
84+
kind = IDENT_KIND[match]
85+
if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/)
86+
kind = :label
87+
label_expected = false
88+
match << matched
89+
else
90+
label_expected = false
91+
if kind == :keyword
92+
case match
93+
when 'case', 'default'
94+
case_expected = true
95+
end
96+
end
97+
end
98+
encoder.text_token match, kind
99+
100+
elsif match = scan(/L?"/)
101+
encoder.begin_group :string
102+
if match[0] == ?L
103+
encoder.text_token 'L', :modifier
104+
match = '"'
105+
end
106+
encoder.text_token match, :delimiter
107+
state = :string
108+
109+
elsif match = scan(/ ` ([^`]+)? (`)? /x)
110+
encoder.begin_group :shell
111+
encoder.text_token '`', :delimiter
112+
encoder.text_token self[1], :content if self[1]
113+
encoder.text_token self[2], :delimiter if self[2]
114+
encoder.end_group :shell
115+
116+
elsif match = scan(/ \# \s* if \s* 0 /x)
117+
match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos?
118+
encoder.text_token match, :comment
119+
120+
elsif match = scan(/#[ \t]*(\w*)/)
121+
encoder.text_token match, :preprocessor
122+
in_preproc_line = true
123+
label_expected_before_preproc_line = label_expected
124+
state = :include_expected if self[1] == 'include'
125+
126+
elsif match = scan(/ L?' (?: [^\'\n\\] | \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) )? '? /ox)
127+
label_expected = false
128+
encoder.text_token match, :char
129+
130+
elsif match = scan(/\$/)
131+
encoder.text_token match, :ident
132+
133+
elsif match = scan(/-?\d*(\.\d*)?([eE][+-]?\d+)?i/)
134+
label_expected = false
135+
encoder.text_token match, :imaginary
136+
137+
elsif match = scan(/-?0[xX][0-9A-Fa-f]+/)
138+
label_expected = false
139+
encoder.text_token match, :hex
140+
141+
elsif match = scan(/-?(?:0[0-7]+)(?![89.eEfF])/)
142+
label_expected = false
143+
encoder.text_token match, :octal
144+
145+
elsif match = scan(/-?(?:\d*\.\d+|\d+\.)(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/)
146+
label_expected = false
147+
encoder.text_token match, :float
148+
149+
elsif match = scan(/-?(?:\d+)(?![.eEfF])L?L?/)
150+
label_expected = false
151+
encoder.text_token match, :integer
152+
153+
else
154+
encoder.text_token getch, :error
155+
156+
end
157+
158+
when :string
159+
if match = scan(/[^\\\n"]+/)
160+
encoder.text_token match, :content
161+
elsif match = scan(/"/)
162+
encoder.text_token match, :delimiter
163+
encoder.end_group :string
164+
state = :initial
165+
label_expected = false
166+
elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
167+
encoder.text_token match, :char
168+
elsif match = scan(/ \\ /x)
169+
encoder.text_token match, :error
170+
elsif match = scan(/$/)
171+
encoder.end_group :string
172+
state = :initial
173+
label_expected = false
174+
else
175+
raise_inspect "else case \" reached; %p not handled." % peek(1), encoder
176+
end
177+
178+
when :include_expected
179+
if match = scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/)
180+
encoder.text_token match, :include
181+
state = :initial
182+
183+
elsif match = scan(/\s+/)
184+
encoder.text_token match, :space
185+
state = :initial if match.index ?\n
186+
187+
else
188+
state = :initial
189+
190+
end
191+
192+
else
193+
raise_inspect 'Unknown state', encoder
194+
195+
end
196+
197+
end
198+
199+
if state == :string
200+
encoder.end_group :string
201+
end
202+
203+
encoder
204+
end
205+
206+
end
207+
208+
end
209+
end

lib/coderay/styles/alpha.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class Alpha < Style
107107
.operator { }
108108
.predefined { color:#369; font-weight:bold }
109109
.predefined-constant { color:#069 }
110-
.predefined-type { color:#0a5; font-weight:bold }
110+
.predefined-type { color:#0a8; font-weight:bold }
111111
.preprocessor { color:#579 }
112112
.pseudo-class { color:#00C; font-weight:bold }
113113
.regexp { background-color:hsla(300,100%,50%,0.06); }

0 commit comments

Comments
 (0)