@@ -136,6 +136,16 @@ impl Iterator for TokenIter<'a> {
136136    } 
137137} 
138138
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+ 
139149/// Processes program tokens, classifying strings of text by highlighting 
140150/// category (`Class`). 
141151struct  Classifier < ' a >  { 
@@ -144,6 +154,8 @@ struct Classifier<'a> {
144154    in_macro :  bool , 
145155    in_macro_nonterminal :  bool , 
146156    edition :  Edition , 
157+     byte_pos :  u32 , 
158+     src :  & ' a  str , 
147159} 
148160
149161impl < ' a >  Classifier < ' a >  { 
@@ -155,6 +167,68 @@ impl<'a> Classifier<'a> {
155167            in_macro :  false , 
156168            in_macro_nonterminal :  false , 
157169            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 
158232        } 
159233    } 
160234
@@ -165,8 +239,25 @@ impl<'a> Classifier<'a> {
165239     /// token is used. 
166240     fn  highlight ( mut  self ,  sink :  & mut  dyn  FnMut ( Highlight < ' a > ) )  { 
167241        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+                 } 
170261            } 
171262        } ) 
172263    } 
@@ -203,12 +294,12 @@ impl<'a> Classifier<'a> {
203294            } , 
204295            TokenKind :: And  => match  lookahead { 
205296                Some ( TokenKind :: And )  => { 
206-                     let  _and =  self . tokens . next ( ) ; 
297+                     self . next ( ) ; 
207298                    sink ( Highlight :: Token  {  text :  "&&" ,  class :  Some ( Class :: Op )  } ) ; 
208299                    return ; 
209300                } 
210301                Some ( TokenKind :: Eq )  => { 
211-                     let  _eq =  self . tokens . next ( ) ; 
302+                     self . next ( ) ; 
212303                    sink ( Highlight :: Token  {  text :  "&=" ,  class :  Some ( Class :: Op )  } ) ; 
213304                    return ; 
214305                } 
@@ -260,7 +351,7 @@ impl<'a> Classifier<'a> {
260351                match  lookahead { 
261352                    // Case 1: #![inner_attribute] 
262353                    Some ( TokenKind :: Bang )  => { 
263-                         let  _not =  self . tokens . next ( ) . unwrap ( ) ; 
354+                         self . next ( ) ; 
264355                        if  let  Some ( TokenKind :: OpenBracket )  = self . peek ( )  { 
265356                            self . in_attribute  = true ; 
266357                            sink ( Highlight :: EnterSpan  {  class :  Class :: Attribute  } ) ; 
@@ -304,19 +395,17 @@ impl<'a> Classifier<'a> {
304395                sink ( Highlight :: Token  {  text,  class :  None  } ) ; 
305396                return ; 
306397            } 
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, 
320409            } , 
321410            TokenKind :: RawIdent  => Class :: Ident , 
322411            TokenKind :: Lifetime  {  .. }  => Class :: Lifetime , 
0 commit comments