@@ -10,46 +10,57 @@ const MAX_PAREN_HIGHLIGHT_DEPTH = 6
10
10
const RAINBOW_DELIMITERS_ENABLED = Ref (true )
11
11
const UNMATCHED_DELIMITERS_ENABLED = Ref (true )
12
12
13
- const SINGLETON_IDENTIFIERS = (" nothing" , " missing" )
13
+ const SINGLETON_IDENTIFIERS = (:nothing , :missing )
14
+
15
+ const BASE_TYPE_IDENTIFIERS =
16
+ Set ([n for n in names (Base, imported= true ) if getglobal (Base, n) isa Type]) ∪
17
+ Set ([n for n in names (Core, imported= true ) if getglobal (Core, n) isa Type])
18
+
19
+ const BUILTIN_FUNCTIONS =
20
+ Set ([n for n in names (Core) if getglobal (Base, n) isa Core. Builtin])
14
21
15
22
const HIGHLIGHT_FACES = [
16
23
# Julia syntax highlighting faces
17
- :julia_identifier => Face (foreground= :bright_white ),
18
- :julia_singleton_identifier => Face (inherit= :julia_symbol ),
19
24
:julia_macro => Face (foreground= :magenta ),
20
25
:julia_symbol => Face (foreground= :magenta ),
26
+ :julia_singleton_identifier => Face (inherit= :julia_symbol ),
21
27
:julia_type => Face (foreground= :yellow ),
28
+ :julia_typedec => Face (foreground= :bright_blue ),
22
29
:julia_comment => Face (foreground= :grey ),
23
30
:julia_string => Face (foreground= :green ),
31
+ :julia_regex => Face (inherit= :julia_string ),
32
+ :julia_backslash_literal => Face (foreground= :magenta , inherit= :julia_string ),
24
33
:julia_string_delim => Face (foreground= :bright_green ),
25
34
:julia_cmdstring => Face (inherit= :julia_string ),
26
35
:julia_char => Face (inherit= :julia_string ),
27
36
:julia_char_delim => Face (inherit= :julia_string_delim ),
28
- :julia_number => Face (foreground= :bright_red ),
29
- :julia_bool => Face (foreground = :bright_red ),
37
+ :julia_number => Face (foreground= :bright_magenta ),
38
+ :julia_bool => Face (inherit = :julia_number ),
30
39
:julia_funcall => Face (foreground= :cyan ),
31
- :julia_operator => Face (foreground= :cyan ),
32
- :julia_comparator => Face (foreground= :yellow ),
33
- :julia_assignment => Face (foreground= :bright_blue ),
40
+ :julia_broadcast => Face (foreground= :bright_blue , weight= :bold ),
41
+ :julia_builtin => Face (foreground= :bright_blue ),
42
+ :julia_operator => Face (foreground= :blue ),
43
+ :julia_comparator => Face (inherit = :julia_operator ),
44
+ :julia_assignment => Face (foreground= :bright_red ),
34
45
:julia_keyword => Face (foreground= :red ),
35
- :julia_error => Face (background= :red ),
36
46
:julia_parenthetical => Face (),
37
- :julia_unpaired_parenthetical => Face (inherit= :julia_error ),
47
+ :julia_unpaired_parenthetical => Face (inherit= [:julia_error , :julia_parenthetical ]),
48
+ :julia_error => Face (background= :red ),
38
49
# Rainbow delimitors (1-6, (), [], and {})
39
- :julia_rainbow_paren_1 => Face (foreground= :bright_green ),
40
- :julia_rainbow_paren_2 => Face (foreground= :bright_blue ),
41
- :julia_rainbow_paren_3 => Face (foreground= :bright_red ),
50
+ :julia_rainbow_paren_1 => Face (foreground= :bright_green , inherit = :julia_parenthetical ),
51
+ :julia_rainbow_paren_2 => Face (foreground= :bright_blue , inherit = :julia_parenthetical ),
52
+ :julia_rainbow_paren_3 => Face (foreground= :bright_red , inherit = :julia_parenthetical ),
42
53
:julia_rainbow_paren_4 => Face (inherit= :julia_rainbow_paren_1 ),
43
54
:julia_rainbow_paren_5 => Face (inherit= :julia_rainbow_paren_2 ),
44
55
:julia_rainbow_paren_6 => Face (inherit= :julia_rainbow_paren_3 ),
45
- :julia_rainbow_bracket_1 => Face (foreground= :blue ),
46
- :julia_rainbow_bracket_2 => Face (foreground= :bright_magenta ),
56
+ :julia_rainbow_bracket_1 => Face (foreground= :blue , inherit = :julia_parenthetical ),
57
+ :julia_rainbow_bracket_2 => Face (foreground= :bright_magenta , inherit = :julia_parenthetical ),
47
58
:julia_rainbow_bracket_3 => Face (inherit= :julia_rainbow_bracket_1 ),
48
59
:julia_rainbow_bracket_4 => Face (inherit= :julia_rainbow_bracket_2 ),
49
60
:julia_rainbow_bracket_5 => Face (inherit= :julia_rainbow_bracket_1 ),
50
61
:julia_rainbow_bracket_6 => Face (inherit= :julia_rainbow_bracket_2 ),
51
- :julia_rainbow_curly_1 => Face (foreground= :bright_yellow ),
52
- :julia_rainbow_curly_2 => Face (foreground= :yellow ),
62
+ :julia_rainbow_curly_1 => Face (foreground= :bright_yellow , inherit = :julia_parenthetical ),
63
+ :julia_rainbow_curly_2 => Face (foreground= :yellow , inherit = :julia_parenthetical ),
53
64
:julia_rainbow_curly_3 => Face (inherit= :julia_rainbow_curly_1 ),
54
65
:julia_rainbow_curly_4 => Face (inherit= :julia_rainbow_curly_2 ),
55
66
:julia_rainbow_curly_5 => Face (inherit= :julia_rainbow_curly_1 ),
@@ -87,52 +98,75 @@ struct HighlightContext{S <: AbstractString}
87
98
content:: S
88
99
offset:: Int
89
100
lnode:: GreenNode
90
- llnode:: GreenNode
91
101
pdepths:: ParenDepthCounter
92
102
end
93
103
94
104
function _hl_annotations (content:: AbstractString , ast:: GreenNode )
95
105
highlights = Vector {Tuple{UnitRange{Int}, Pair{Symbol, Any}}} ()
96
- ctx = HighlightContext (content, 0 , ast, ast, ParenDepthCounter ())
106
+ ctx = HighlightContext (content, 0 , ast, ParenDepthCounter ())
97
107
_hl_annotations! (highlights, GreenLineage (ast, nothing ), ctx)
98
108
highlights
99
109
end
100
110
101
111
function _hl_annotations! (highlights:: Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}} ,
102
112
lineage:: GreenLineage , ctx:: HighlightContext )
103
113
(; node, parent) = lineage
104
- (; content, offset, lnode, llnode, pdepths) = ctx
114
+ (; content, offset, lnode, pdepths) = ctx
105
115
region = firstindex (content)+ offset: node. span+ offset
106
116
nkind = node. head. kind
107
117
pnode = if ! isnothing (parent) parent. node end
108
118
pkind = if ! isnothing (parent) kind (parent. node) end
119
+ ppkind = if ! isnothing (parent) && ! isnothing (parent. parent)
120
+ kind (parent. parent. node) end
121
+ # We need to check for infix binary operators
122
+ # of the form [lhs] [ws] [op] [ws]? [rhs]
123
+ isbinaryinfix (node) = 3 <= length (node. args) <= 5 &&
124
+ (JuliaSyntax. is_operator (kind (node. args[2 ])) ||
125
+ (kind (node. args[2 ]) == K " Whitespace" &&
126
+ JuliaSyntax. is_operator (kind (node. args[3 ]))))
127
+ isplainoperator (node) =
128
+ JuliaSyntax. is_operator (node) &&
129
+ ! JuliaSyntax. is_trivia (node) &&
130
+ ! JuliaSyntax. is_prec_assignment (node) &&
131
+ ! JuliaSyntax. is_word_operator (node) &&
132
+ nkind != K " ." && nkind != K " ..." &&
133
+ (JuliaSyntax. is_trivia (node) ||
134
+ iszero (flags (node)) && ! isbinaryinfix (node))
109
135
face = if nkind == K " Identifier"
110
- if pkind == K ":: " && JuliaSyntax . is_trivia (pnode)
136
+ if pkind == K "curly "
111
137
:julia_type
112
- elseif pkind == K " curly" && kind (lnode) == K " curly" && ! isnothing (parent. parent) && kind (parent. parent. node) == K " call"
113
- :julia_identifier
114
- elseif pkind == K " curly"
115
- :julia_type
116
- elseif pkind == K " braces" && lnode != pnode
117
- :julia_type
118
- elseif kind (lnode) == K " ::" && JuliaSyntax. is_trivia (lnode)
119
- :julia_type
120
- elseif kind (lnode) == K " :" && ! JuliaSyntax. is_number (llnode) &&
121
- kind (llnode) ∉ (K " Identifier" , K " )" , K " ]" , K " end" , K " '" )
122
- highlights[end ] = (highlights[end ][1 ], :face => :julia_symbol )
123
- :julia_symbol
124
- elseif view (content, region) in SINGLETON_IDENTIFIERS
125
- :julia_singleton_identifier
126
- elseif view (content, region) == " NaN"
127
- :julia_number
128
138
else
129
- :julia_identifier
139
+ name = Symbol (view (content, region))
140
+ if name in SINGLETON_IDENTIFIERS
141
+ :julia_singleton_identifier
142
+ elseif name == :NaN
143
+ :julia_number
144
+ elseif name in BASE_TYPE_IDENTIFIERS
145
+ :julia_type
146
+ end
130
147
end
131
- elseif nkind == K " @" ; :julia_macro
132
- elseif nkind == K " MacroName" ; :julia_macro
148
+ elseif nkind == K " macrocall" && length (node. args) >= 2 &&
149
+ kind (node. args[1 ]) == K " @" && kind (node. args[2 ]) == K " MacroName"
150
+ region = first (region): first (region)+ node. args[2 ]. span
151
+ :julia_macro
133
152
elseif nkind == K " StringMacroName" ; :julia_macro
134
153
elseif nkind == K " CmdMacroName" ; :julia_macro
135
- elseif nkind == K " ::" ; :julia_type
154
+ elseif nkind == K " ::" ;
155
+ if JuliaSyntax. is_trivia (node)
156
+ :julia_typedec
157
+ else
158
+ literal_typedecl = findfirst (
159
+ c -> kind (c) == K " ::" && JuliaSyntax. is_trivia (c),
160
+ node. args)
161
+ if ! isnothing (literal_typedecl)
162
+ shift = sum (c -> Int (c. span), node. args[1 : literal_typedecl])
163
+ region = first (region)+ shift: last (region)
164
+ :julia_type
165
+ end
166
+ end
167
+ elseif nkind == K " quote" && length (node. args) == 2 &&
168
+ kind (node. args[1 ]) == K " :" && kind (node. args[2 ]) == K " Identifier"
169
+ :julia_symbol
136
170
elseif nkind == K " Comment" ; :julia_comment
137
171
elseif nkind == K " String" ; :julia_string
138
172
elseif JuliaSyntax. is_string_delim (node); :julia_string_delim
@@ -146,22 +180,65 @@ function _hl_annotations!(highlights::Vector{Tuple{UnitRange{Int}, Pair{Symbol,
146
180
elseif nkind == K " true" || nkind == K " false" ; :julia_bool
147
181
elseif JuliaSyntax. is_number (nkind); :julia_number
148
182
elseif JuliaSyntax. is_prec_assignment (nkind) && JuliaSyntax. is_trivia (node);
149
- :julia_assignment
150
- elseif JuliaSyntax. is_word_operator (nkind) && JuliaSyntax. is_trivia (node);
151
- :julia_assignment
183
+ if nkind == K " ="
184
+ ifelse (ppkind == K " for" , :julia_keyword , :julia_assignment )
185
+ else # updating for <op>=
186
+ push! (highlights, (firstindex (content)+ offset: node. span+ offset- 1 , :face => :julia_operator ))
187
+ push! (highlights, (node. span+ offset: node. span+ offset, :face => :julia_assignment ))
188
+ nothing
189
+ end
152
190
elseif nkind == K " ;" && pkind == K " parameters" && pnode == lnode
153
191
:julia_assignment
154
- elseif JuliaSyntax. is_prec_comparison (nkind); :julia_comparator
155
- elseif JuliaSyntax. is_operator (nkind) && ! JuliaSyntax. is_prec_assignment (nkind) &&
156
- ! JuliaSyntax. is_word_operator (nkind) && nkind != K " ." &&
157
- (JuliaSyntax. is_trivia (node) || iszero (flags (node)));
158
- :julia_operator
159
- elseif JuliaSyntax. is_keyword (nkind) && JuliaSyntax. is_trivia (node); :julia_keyword
192
+ elseif (JuliaSyntax. is_keyword (nkind) || nkind == K " ->" ) && JuliaSyntax. is_trivia (node)
193
+ :julia_keyword
194
+ elseif nkind == K " where"
195
+ if JuliaSyntax. is_trivia (node)
196
+ :julia_keyword
197
+ else
198
+ literal_where = findfirst (
199
+ c -> kind (c) == K " where" && JuliaSyntax. is_trivia (c),
200
+ node. args)
201
+ if ! isnothing (literal_where)
202
+ shift = sum (c -> Int (c. span), node. args[1 : literal_where])
203
+ region = first (region)+ shift: last (region)
204
+ :julia_type
205
+ end
206
+ end
207
+ elseif nkind == K " in"
208
+ ifelse (ppkind == K " for" , :julia_keyword , :julia_comparator )
209
+ elseif nkind == K " isa" ; :julia_builtin
210
+ elseif nkind in (K " &&" , K " ||" , K " <:" , K " ===" ) && JuliaSyntax. is_trivia (node)
211
+ :julia_builtin
212
+ elseif JuliaSyntax. is_prec_comparison (nkind) && JuliaSyntax. is_trivia (node);
213
+ :julia_comparator
214
+ elseif isplainoperator (node); :julia_operator
215
+ elseif nkind == K " ..." && JuliaSyntax. is_trivia (node); :julia_operator
216
+ elseif nkind == K " ." && JuliaSyntax. is_trivia (node) && kind (pnode) == K " dotcall" ;
217
+ :julia_broadcast
218
+ elseif nkind in (K " call" , K " dotcall" ) && JuliaSyntax. is_prefix_call (node)
219
+ argoffset, arg1 = 0 , nothing
220
+ for arg in node. args
221
+ argoffset += arg. span
222
+ if ! JuliaSyntax. is_trivia (arg)
223
+ arg1 = arg
224
+ break
225
+ end
226
+ end
227
+ if isnothing (arg1)
228
+ elseif kind (arg1) == K " Identifier"
229
+ region = first (region): first (region)+ argoffset- 1
230
+ name = Symbol (view (content, region))
231
+ ifelse (name in BUILTIN_FUNCTIONS, :julia_builtin , :julia_funcall )
232
+ elseif kind (arg1) == K " ." && length (arg1. args) == 3 &&
233
+ kind (arg1. args[end ]) == K " quote" &&
234
+ length (arg1. args[end ]. args) == 1 &&
235
+ kind (arg1. args[end ]. args[1 ]) == K " Identifier"
236
+ region = first (region)+ argoffset- arg1. args[end ]. args[1 ]. span: first (region)+ argoffset- 1
237
+ name = Symbol (view (content, region))
238
+ ifelse (name in BUILTIN_FUNCTIONS, :julia_builtin , :julia_funcall )
239
+ end
160
240
elseif JuliaSyntax. is_error (nkind); :julia_error
161
241
elseif ((depthchange, ptype) = paren_type (nkind)) |> last != :none
162
- if nkind == K " (" && ! isempty (highlights) && kind (lnode) == K " Identifier" && last (last (highlights[end ])) == :julia_identifier
163
- highlights[end ] = (highlights[end ][1 ], :face => :julia_funcall )
164
- end
165
242
depthref = getfield (pdepths, ptype)[]
166
243
pdepth = if depthchange > 0
167
244
getfield (pdepths, ptype)[] += depthchange
@@ -181,12 +258,26 @@ function _hl_annotations!(highlights::Vector{Tuple{UnitRange{Int}, Pair{Symbol,
181
258
end
182
259
! isnothing (face) &&
183
260
push! (highlights, (region, :face => face))
261
+ if nkind == K " Comment"
262
+ for match in eachmatch (
263
+ r" (?:^|[(\[ {[:space:]-])`([^[:space:]](?:.*?[^[:space:]])?)`(?:$|[!,\- .:;?\[\] [:space:]])" ,
264
+ view (content, region))
265
+ code = first (match. captures)
266
+ push! (highlights, (firstindex (content)+ offset+ code. offset: firstindex (content)+ offset+ code. offset+ code. ncodeunits- 1 ,
267
+ :face => :code ))
268
+ end
269
+ elseif nkind == K " String"
270
+ for match in eachmatch (r" \\ ." , view (content, region))
271
+ push! (highlights, (firstindex (content)+ offset+ match. offset- 1 : firstindex (content)+ offset+ match. offset+ ncodeunits (match. match)- 2 ,
272
+ :face => :julia_backslash_literal ))
273
+ end
274
+ end
184
275
isempty (node. args) && return
185
- llnode, lnode = node, node
276
+ lnode = node
186
277
for child in node. args
187
- cctx = HighlightContext (content, offset, lnode, llnode, pdepths)
278
+ cctx = HighlightContext (content, offset, lnode, pdepths)
188
279
_hl_annotations! (highlights, GreenLineage (child, lineage), cctx)
189
- llnode, lnode = lnode, child
280
+ lnode = child
190
281
offset += child. span
191
282
end
192
283
end
0 commit comments