@@ -136,6 +136,16 @@ impl Iterator for TokenIter<'a> {
136
136
}
137
137
}
138
138
139
+ fn get_real_ident_class ( text : & str , edition : Edition ) -> Class {
140
+ match text {
141
+ "ref" | "mut" => Class :: RefKeyWord ,
142
+ "self" | "Self" => Class :: Self_ ,
143
+ "false" | "true" => Class :: Bool ,
144
+ _ if Symbol :: intern ( text) . is_reserved ( || edition) => Class :: KeyWord ,
145
+ _ => Class :: Ident ,
146
+ }
147
+ }
148
+
139
149
/// Processes program tokens, classifying strings of text by highlighting
140
150
/// category (`Class`).
141
151
struct Classifier < ' a > {
@@ -144,6 +154,8 @@ struct Classifier<'a> {
144
154
in_macro : bool ,
145
155
in_macro_nonterminal : bool ,
146
156
edition : Edition ,
157
+ byte_pos : u32 ,
158
+ src : & ' a str ,
147
159
}
148
160
149
161
impl < ' a > Classifier < ' a > {
@@ -155,6 +167,68 @@ impl<'a> Classifier<'a> {
155
167
in_macro : false ,
156
168
in_macro_nonterminal : false ,
157
169
edition,
170
+ byte_pos : 0 ,
171
+ src,
172
+ }
173
+ }
174
+
175
+ /// Concatenate colons and idents as one when possible.
176
+ fn get_full_ident_path ( & mut self ) -> Vec < ( TokenKind , usize , usize ) > {
177
+ let start = self . byte_pos as usize ;
178
+ let mut pos = start;
179
+ let mut has_ident = false ;
180
+ let edition = self . edition ;
181
+
182
+ loop {
183
+ let mut nb = 0 ;
184
+ while let Some ( ( TokenKind :: Colon , _) ) = self . tokens . peek ( ) {
185
+ self . tokens . next ( ) ;
186
+ nb += 1 ;
187
+ }
188
+ // Ident path can start with "::" but if we already have content in the ident path,
189
+ // the "::" is mandatory.
190
+ if has_ident && nb == 0 {
191
+ return vec ! [ ( TokenKind :: Ident , start, pos) ] ;
192
+ } else if nb != 0 && nb != 2 {
193
+ if has_ident {
194
+ return vec ! [ ( TokenKind :: Ident , start, pos) , ( TokenKind :: Colon , pos, pos + nb) ] ;
195
+ } else {
196
+ return vec ! [ ( TokenKind :: Colon , pos, pos + nb) ] ;
197
+ }
198
+ }
199
+
200
+ if let Some ( ( Class :: Ident , text) ) = self . tokens . peek ( ) . map ( |( token, text) | {
201
+ if * token == TokenKind :: Ident {
202
+ let class = get_real_ident_class ( text, edition) ;
203
+ ( class, text)
204
+ } else {
205
+ // Doesn't matter which Class we put in here...
206
+ ( Class :: Comment , text)
207
+ }
208
+ } ) {
209
+ // We only "add" the colon if there is an ident behind.
210
+ pos += text. len ( ) + nb;
211
+ has_ident = true ;
212
+ self . tokens . next ( ) ;
213
+ } else if nb > 0 && has_ident {
214
+ return vec ! [ ( TokenKind :: Ident , start, pos) , ( TokenKind :: Colon , pos, pos + nb) ] ;
215
+ } else if nb > 0 {
216
+ return vec ! [ ( TokenKind :: Colon , pos, pos + nb) ] ;
217
+ } else if has_ident {
218
+ return vec ! [ ( TokenKind :: Ident , start, pos) ] ;
219
+ } else {
220
+ return Vec :: new ( ) ;
221
+ }
222
+ }
223
+ }
224
+
225
+ /// Wraps the tokens iteration to ensure that the byte_pos is always correct.
226
+ fn next ( & mut self ) -> Option < ( TokenKind , & ' a str ) > {
227
+ if let Some ( ( kind, text) ) = self . tokens . next ( ) {
228
+ self . byte_pos += text. len ( ) as u32 ;
229
+ Some ( ( kind, text) )
230
+ } else {
231
+ None
158
232
}
159
233
}
160
234
@@ -165,8 +239,25 @@ impl<'a> Classifier<'a> {
165
239
/// token is used.
166
240
fn highlight ( mut self , sink : & mut dyn FnMut ( Highlight < ' a > ) ) {
167
241
with_default_session_globals ( || {
168
- while let Some ( ( token, text) ) = self . tokens . next ( ) {
169
- self . advance ( token, text, sink) ;
242
+ loop {
243
+ if self
244
+ . tokens
245
+ . peek ( )
246
+ . map ( |t| matches ! ( t. 0 , TokenKind :: Colon | TokenKind :: Ident ) )
247
+ . unwrap_or ( false )
248
+ {
249
+ let tokens = self . get_full_ident_path ( ) ;
250
+ for ( token, start, end) in tokens {
251
+ let text = & self . src [ start..end] ;
252
+ self . advance ( token, text, sink) ;
253
+ self . byte_pos += text. len ( ) as u32 ;
254
+ }
255
+ }
256
+ if let Some ( ( token, text) ) = self . next ( ) {
257
+ self . advance ( token, text, sink) ;
258
+ } else {
259
+ break ;
260
+ }
170
261
}
171
262
} )
172
263
}
@@ -203,12 +294,12 @@ impl<'a> Classifier<'a> {
203
294
} ,
204
295
TokenKind :: And => match lookahead {
205
296
Some ( TokenKind :: And ) => {
206
- let _and = self . tokens . next ( ) ;
297
+ self . next ( ) ;
207
298
sink ( Highlight :: Token { text : "&&" , class : Some ( Class :: Op ) } ) ;
208
299
return ;
209
300
}
210
301
Some ( TokenKind :: Eq ) => {
211
- let _eq = self . tokens . next ( ) ;
302
+ self . next ( ) ;
212
303
sink ( Highlight :: Token { text : "&=" , class : Some ( Class :: Op ) } ) ;
213
304
return ;
214
305
}
@@ -260,7 +351,7 @@ impl<'a> Classifier<'a> {
260
351
match lookahead {
261
352
// Case 1: #![inner_attribute]
262
353
Some ( TokenKind :: Bang ) => {
263
- let _not = self . tokens . next ( ) . unwrap ( ) ;
354
+ self . next ( ) ;
264
355
if let Some ( TokenKind :: OpenBracket ) = self . peek ( ) {
265
356
self . in_attribute = true ;
266
357
sink ( Highlight :: EnterSpan { class : Class :: Attribute } ) ;
@@ -304,19 +395,17 @@ impl<'a> Classifier<'a> {
304
395
sink ( Highlight :: Token { text, class : None } ) ;
305
396
return ;
306
397
}
307
- TokenKind :: Ident => match text {
308
- "ref" | "mut" => Class :: RefKeyWord ,
309
- "self" | "Self" => Class :: Self_ ,
310
- "false" | "true" => Class :: Bool ,
311
- "Option" | "Result" => Class :: PreludeTy ,
312
- "Some" | "None" | "Ok" | "Err" => Class :: PreludeVal ,
313
- // Keywords are also included in the identifier set.
314
- _ if Symbol :: intern ( text) . is_reserved ( || self . edition ) => Class :: KeyWord ,
315
- _ if self . in_macro_nonterminal => {
316
- self . in_macro_nonterminal = false ;
317
- Class :: MacroNonTerminal
318
- }
319
- _ => Class :: Ident ,
398
+ TokenKind :: Ident => match get_real_ident_class ( text, self . edition ) {
399
+ Class :: Ident => match text {
400
+ "Option" | "Result" => Class :: PreludeTy ,
401
+ "Some" | "None" | "Ok" | "Err" => Class :: PreludeVal ,
402
+ _ if self . in_macro_nonterminal => {
403
+ self . in_macro_nonterminal = false ;
404
+ Class :: MacroNonTerminal
405
+ }
406
+ _ => Class :: Ident ,
407
+ } ,
408
+ c => c,
320
409
} ,
321
410
TokenKind :: RawIdent => Class :: Ident ,
322
411
TokenKind :: Lifetime { .. } => Class :: Lifetime ,
0 commit comments