Skip to content

Commit 1416413

Browse files
committed
Skip macro matcher fragment name semantic highlighting
1 parent cde189c commit 1416413

File tree

4 files changed

+124
-4
lines changed

4 files changed

+124
-4
lines changed

crates/ide/src/syntax_highlighting.rs

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub(crate) fn highlight(
6868
// When we leave a node, the we use it to flatten the highlighted ranges.
6969
let mut stack = HighlightedRangeStack::new();
7070

71-
let mut current_macro_call: Option<ast::MacroCall> = None;
71+
let mut current_macro_call: Option<(ast::MacroCall, Option<MacroMatcherParseState>)> = None;
7272
let mut format_string: Option<SyntaxElement> = None;
7373

7474
// Walk all nodes, keeping track of whether we are inside a macro or not.
@@ -92,15 +92,16 @@ pub(crate) fn highlight(
9292
// Track "inside macro" state
9393
match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) {
9494
WalkEvent::Enter(Some(mc)) => {
95-
current_macro_call = Some(mc.clone());
9695
if let Some(range) = macro_call_range(&mc) {
9796
stack.add(HighlightedRange {
9897
range,
9998
highlight: HighlightTag::Macro.into(),
10099
binding_hash: None,
101100
});
102101
}
102+
let mut is_macro_rules = None;
103103
if let Some(name) = mc.is_macro_rules() {
104+
is_macro_rules = Some(MacroMatcherParseState::new());
104105
if let Some((highlight, binding_hash)) = highlight_element(
105106
&sema,
106107
&mut bindings_shadow_count,
@@ -114,10 +115,11 @@ pub(crate) fn highlight(
114115
});
115116
}
116117
}
118+
current_macro_call = Some((mc.clone(), is_macro_rules));
117119
continue;
118120
}
119121
WalkEvent::Leave(Some(mc)) => {
120-
assert!(current_macro_call == Some(mc));
122+
assert!(current_macro_call.map(|it| it.0) == Some(mc));
121123
current_macro_call = None;
122124
format_string = None;
123125
}
@@ -146,6 +148,20 @@ pub(crate) fn highlight(
146148
WalkEvent::Leave(_) => continue,
147149
};
148150

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+
149165
let range = element.text_range();
150166

151167
let element_to_highlight = if current_macro_call.is_some() && element.kind() != COMMENT {
@@ -918,3 +934,99 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
918934
_ => default.into(),
919935
}
920936
}
937+
938+
struct MacroMatcherParseState {
939+
/// Opening and corresponding closing bracket of the matcher or expander of the current rule
940+
paren_ty: Option<(SyntaxKind, SyntaxKind)>,
941+
paren_level: usize,
942+
rule_state: RuleState,
943+
/// Whether we are inside the outer `{` `}` macro block that holds the rules
944+
in_invoc_body: bool,
945+
}
946+
947+
impl MacroMatcherParseState {
948+
fn new() -> Self {
949+
MacroMatcherParseState {
950+
paren_ty: None,
951+
paren_level: 0,
952+
in_invoc_body: false,
953+
rule_state: RuleState::None,
954+
}
955+
}
956+
}
957+
958+
#[derive(Copy, Clone, PartialEq)]
959+
enum RuleState {
960+
Matcher,
961+
Expander,
962+
Between,
963+
None,
964+
}
965+
966+
impl RuleState {
967+
fn transition(&mut self) {
968+
*self = match self {
969+
RuleState::Matcher => RuleState::Between,
970+
RuleState::Expander => RuleState::None,
971+
RuleState::Between => RuleState::Expander,
972+
RuleState::None => RuleState::Matcher,
973+
};
974+
}
975+
}
976+
977+
fn update_macro_rules_state(tok: &SyntaxToken, state: &mut MacroMatcherParseState) -> RuleState {
978+
if !state.in_invoc_body {
979+
if tok.kind() == T!['{'] {
980+
state.in_invoc_body = true;
981+
}
982+
return state.rule_state;
983+
}
984+
985+
match state.paren_ty {
986+
Some((open, close)) => {
987+
if tok.kind() == open {
988+
state.paren_level += 1;
989+
} else if tok.kind() == close {
990+
state.paren_level -= 1;
991+
if state.paren_level == 0 {
992+
let res = state.rule_state;
993+
state.rule_state.transition();
994+
state.paren_ty = None;
995+
return res;
996+
}
997+
}
998+
}
999+
None => {
1000+
match tok.kind() {
1001+
T!['('] => {
1002+
state.paren_ty = Some((T!['('], T![')']));
1003+
}
1004+
T!['{'] => {
1005+
state.paren_ty = Some((T!['{'], T!['}']));
1006+
}
1007+
T!['['] => {
1008+
state.paren_ty = Some((T!['['], T![']']));
1009+
}
1010+
_ => (),
1011+
}
1012+
if state.paren_ty.is_some() {
1013+
state.paren_level = 1;
1014+
state.rule_state.transition();
1015+
}
1016+
}
1017+
}
1018+
state.rule_state
1019+
}
1020+
1021+
fn skip_metavariables(element: SyntaxElement) -> bool {
1022+
let tok = match element.as_token() {
1023+
Some(tok) => tok,
1024+
None => return false,
1025+
};
1026+
let is_fragment = || tok.prev_token().map(|tok| tok.kind()) == Some(T![$]);
1027+
match tok.kind() {
1028+
IDENT if is_fragment() => true,
1029+
kind if kind.is_keyword() && is_fragment() => true,
1030+
_ => false,
1031+
}
1032+
}

crates/ide/src/syntax_highlighting/test_data/highlight_strings.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
</style>
3838
<pre><code><span class="macro">macro_rules!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span>
3939
<span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">{</span>
40-
<span class="punctuation">$</span><span class="keyword">crate</span><span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span><span class="keyword">crate</span><span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span>
40+
<span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span>
4141
<span class="punctuation">}</span><span class="punctuation">)</span>
4242
<span class="punctuation">}</span>
4343
#[rustc_builtin_macro]

crates/ide/src/syntax_highlighting/test_data/highlighting.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@
115115
<span class="punctuation">}</span>
116116
<span class="punctuation">}</span>
117117

118+
<span class="macro">macro_rules!</span> <span class="macro declaration">keyword_frag</span> <span class="punctuation">{</span>
119+
<span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">:</span>ty<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">)</span>
120+
<span class="punctuation">}</span>
121+
118122
<span class="comment">// comment</span>
119123
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
120124
<span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, {}!"</span><span class="punctuation">,</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span>

crates/ide/src/syntax_highlighting/tests.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ macro_rules! noop {
8989
}
9090
}
9191
92+
macro_rules! keyword_frag {
93+
($type:ty) => ($type)
94+
}
95+
9296
// comment
9397
fn main() {
9498
println!("Hello, {}!", 92);

0 commit comments

Comments
 (0)