11mod format;
22mod html;
33mod injection;
4+ mod macro_rules;
45mod tags;
56#[ cfg( test) ]
67mod tests;
@@ -18,7 +19,10 @@ use syntax::{
1819 SyntaxNode , SyntaxToken , TextRange , WalkEvent , T ,
1920} ;
2021
21- use crate :: { syntax_highlighting:: format:: FormatStringHighlighter , FileId } ;
22+ use crate :: {
23+ syntax_highlighting:: { format:: FormatStringHighlighter , macro_rules:: MacroRulesHighlighter } ,
24+ FileId ,
25+ } ;
2226
2327pub ( crate ) use html:: highlight_as_html;
2428pub use tags:: { Highlight , HighlightModifier , HighlightModifiers , HighlightTag } ;
@@ -68,8 +72,9 @@ pub(crate) fn highlight(
6872 // When we leave a node, the we use it to flatten the highlighted ranges.
6973 let mut stack = HighlightedRangeStack :: new ( ) ;
7074
71- let mut current_macro_call: Option < ( ast:: MacroCall , Option < MacroMatcherParseState > ) > = None ;
75+ let mut current_macro_call: Option < ast:: MacroCall > = None ;
7276 let mut format_string_highlighter = FormatStringHighlighter :: default ( ) ;
77+ let mut macro_rules_highlighter = MacroRulesHighlighter :: new ( ) ;
7378
7479 // Walk all nodes, keeping track of whether we are inside a macro or not.
7580 // If in macro, expand it first and highlight the expanded code.
@@ -99,9 +104,8 @@ pub(crate) fn highlight(
99104 binding_hash : None ,
100105 } ) ;
101106 }
102- let mut is_macro_rules = None ;
103107 if let Some ( name) = mc. is_macro_rules ( ) {
104- is_macro_rules = Some ( MacroMatcherParseState :: new ( ) ) ;
108+ macro_rules_highlighter . init ( ) ;
105109 if let Some ( ( highlight, binding_hash) ) = highlight_element (
106110 & sema,
107111 & mut bindings_shadow_count,
@@ -115,13 +119,14 @@ pub(crate) fn highlight(
115119 } ) ;
116120 }
117121 }
118- current_macro_call = Some ( ( mc. clone ( ) , is_macro_rules ) ) ;
122+ current_macro_call = Some ( mc. clone ( ) ) ;
119123 continue ;
120124 }
121125 WalkEvent :: Leave ( Some ( mc) ) => {
122- assert ! ( current_macro_call. map ( |it| it . 0 ) == Some ( mc) ) ;
126+ assert ! ( current_macro_call == Some ( mc) ) ;
123127 current_macro_call = None ;
124128 format_string_highlighter. reset ( ) ;
129+ macro_rules_highlighter. reset ( ) ;
125130 }
126131 _ => ( ) ,
127132 }
@@ -148,20 +153,6 @@ pub(crate) fn highlight(
148153 WalkEvent :: Leave ( _) => continue ,
149154 } ;
150155
151- // check if in matcher part of a macro_rules rule
152- if let Some ( ( _, Some ( ref mut state) ) ) = current_macro_call {
153- if let Some ( tok) = element. as_token ( ) {
154- if matches ! (
155- update_macro_rules_state( tok, state) ,
156- RuleState :: Matcher | RuleState :: Expander
157- ) {
158- if skip_metavariables ( element. clone ( ) ) {
159- continue ;
160- }
161- }
162- }
163- }
164-
165156 let range = element. text_range ( ) ;
166157
167158 let element_to_highlight = if current_macro_call. is_some ( ) && element. kind ( ) != COMMENT {
@@ -174,6 +165,9 @@ pub(crate) fn highlight(
174165 let parent = token. parent ( ) ;
175166
176167 format_string_highlighter. check_for_format_string ( & parent) ;
168+ if let Some ( tok) = element. as_token ( ) {
169+ macro_rules_highlighter. advance ( tok) ;
170+ }
177171
178172 // We only care Name and Name_ref
179173 match ( token. kind ( ) , parent. kind ( ) ) {
@@ -197,7 +191,10 @@ pub(crate) fn highlight(
197191 syntactic_name_ref_highlighting,
198192 element_to_highlight. clone ( ) ,
199193 ) {
200- stack. add ( HighlightedRange { range, highlight, binding_hash } ) ;
194+ if macro_rules_highlighter. highlight ( element_to_highlight. clone ( ) ) . is_none ( ) {
195+ stack. add ( HighlightedRange { range, highlight, binding_hash } ) ;
196+ }
197+
201198 if let Some ( string) =
202199 element_to_highlight. as_token ( ) . cloned ( ) . and_then ( ast:: String :: cast)
203200 {
@@ -867,99 +864,3 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
867864 _ => default. into ( ) ,
868865 }
869866}
870-
871- struct MacroMatcherParseState {
872- /// Opening and corresponding closing bracket of the matcher or expander of the current rule
873- paren_ty : Option < ( SyntaxKind , SyntaxKind ) > ,
874- paren_level : usize ,
875- rule_state : RuleState ,
876- /// Whether we are inside the outer `{` `}` macro block that holds the rules
877- in_invoc_body : bool ,
878- }
879-
880- impl MacroMatcherParseState {
881- fn new ( ) -> Self {
882- MacroMatcherParseState {
883- paren_ty : None ,
884- paren_level : 0 ,
885- in_invoc_body : false ,
886- rule_state : RuleState :: None ,
887- }
888- }
889- }
890-
891- #[ derive( Copy , Clone , PartialEq ) ]
892- enum RuleState {
893- Matcher ,
894- Expander ,
895- Between ,
896- None ,
897- }
898-
899- impl RuleState {
900- fn transition ( & mut self ) {
901- * self = match self {
902- RuleState :: Matcher => RuleState :: Between ,
903- RuleState :: Expander => RuleState :: None ,
904- RuleState :: Between => RuleState :: Expander ,
905- RuleState :: None => RuleState :: Matcher ,
906- } ;
907- }
908- }
909-
910- fn update_macro_rules_state ( tok : & SyntaxToken , state : & mut MacroMatcherParseState ) -> RuleState {
911- if !state. in_invoc_body {
912- if tok. kind ( ) == T ! [ '{' ] {
913- state. in_invoc_body = true ;
914- }
915- return state. rule_state ;
916- }
917-
918- match state. paren_ty {
919- Some ( ( open, close) ) => {
920- if tok. kind ( ) == open {
921- state. paren_level += 1 ;
922- } else if tok. kind ( ) == close {
923- state. paren_level -= 1 ;
924- if state. paren_level == 0 {
925- let res = state. rule_state ;
926- state. rule_state . transition ( ) ;
927- state. paren_ty = None ;
928- return res;
929- }
930- }
931- }
932- None => {
933- match tok. kind ( ) {
934- T ! [ '(' ] => {
935- state. paren_ty = Some ( ( T ! [ '(' ] , T ! [ ')' ] ) ) ;
936- }
937- T ! [ '{' ] => {
938- state. paren_ty = Some ( ( T ! [ '{' ] , T ! [ '}' ] ) ) ;
939- }
940- T ! [ '[' ] => {
941- state. paren_ty = Some ( ( T ! [ '[' ] , T ! [ ']' ] ) ) ;
942- }
943- _ => ( ) ,
944- }
945- if state. paren_ty . is_some ( ) {
946- state. paren_level = 1 ;
947- state. rule_state . transition ( ) ;
948- }
949- }
950- }
951- state. rule_state
952- }
953-
954- fn skip_metavariables ( element : SyntaxElement ) -> bool {
955- let tok = match element. as_token ( ) {
956- Some ( tok) => tok,
957- None => return false ,
958- } ;
959- let is_fragment = || tok. prev_token ( ) . map ( |tok| tok. kind ( ) ) == Some ( T ! [ $] ) ;
960- match tok. kind ( ) {
961- IDENT if is_fragment ( ) => true ,
962- kind if kind. is_keyword ( ) && is_fragment ( ) => true ,
963- _ => false ,
964- }
965- }
0 commit comments