From 4520002b63b5a27e7676822aecfb2d435bf36e5a Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 27 Mar 2021 13:48:15 +0800 Subject: Unleash macro 2.0 in hightlight and more --- crates/ide/src/doc_links.rs | 2 +- crates/ide/src/file_structure.rs | 2 +- crates/ide/src/move_item.rs | 1 + crates/ide/src/syntax_highlighting.rs | 28 ++--- crates/ide/src/syntax_highlighting/inject.rs | 3 +- crates/ide/src/syntax_highlighting/macro_.rs | 129 +++++++++++++++++++++ crates/ide/src/syntax_highlighting/macro_rules.rs | 129 --------------------- .../test_data/highlighting.html | 12 +- crates/ide/src/syntax_highlighting/tests.rs | 10 ++ 9 files changed, 168 insertions(+), 148 deletions(-) create mode 100644 crates/ide/src/syntax_highlighting/macro_.rs delete mode 100644 crates/ide/src/syntax_highlighting/macro_rules.rs (limited to 'crates/ide') diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 0cee741ac..9301cdeff 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -161,7 +161,7 @@ pub(crate) fn doc_owner_to_def( ast::Variant(it) => sema.to_def(&it)?.into(), ast::Trait(it) => sema.to_def(&it)?.into(), ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType), - ast::MacroRules(it) => return sema.to_def(&it).map(Definition::Macro), + ast::Macro(it) => return sema.to_def(&it).map(Definition::Macro), ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field), ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field), _ => return None, diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs index 9f879a66e..2c898eae8 100644 --- a/crates/ide/src/file_structure.rs +++ b/crates/ide/src/file_structure.rs @@ -172,7 +172,7 @@ fn structure_node(node: &SyntaxNode) -> Option { }; Some(node) }, - ast::MacroRules(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), + ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), _ => None, } } diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs index 48690b073..05fa8fc13 100644 --- a/crates/ide/src/move_item.rs +++ b/crates/ide/src/move_item.rs @@ -66,6 +66,7 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) - SyntaxKind::STATIC, SyntaxKind::CONST, SyntaxKind::MACRO_RULES, + SyntaxKind::MACRO_DEF, ]; let ancestor = once(root.clone()) diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index e25b698e0..67a10766b 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -5,7 +5,7 @@ mod injector; mod highlight; mod format; -mod macro_rules; +mod macro_; mod inject; mod html; @@ -24,8 +24,8 @@ use syntax::{ use crate::{ syntax_highlighting::{ - format::highlight_format_string, highlights::Highlights, - macro_rules::MacroRulesHighlighter, tags::Highlight, + format::highlight_format_string, highlights::Highlights, macro_::MacroHighlighter, + tags::Highlight, }, FileId, HlMod, HlTag, }; @@ -93,8 +93,8 @@ fn traverse( let mut bindings_shadow_count: FxHashMap = FxHashMap::default(); let mut current_macro_call: Option = None; - let mut current_macro_rules: Option = None; - let mut macro_rules_highlighter = MacroRulesHighlighter::default(); + let mut current_macro: Option = None; + let mut macro_highlighter = MacroHighlighter::default(); let mut inside_attribute = false; // Walk all nodes, keeping track of whether we are inside a macro or not. @@ -129,16 +129,16 @@ fn traverse( _ => (), } - match event.clone().map(|it| it.into_node().and_then(ast::MacroRules::cast)) { + match event.clone().map(|it| it.into_node().and_then(ast::Macro::cast)) { WalkEvent::Enter(Some(mac)) => { - macro_rules_highlighter.init(); - current_macro_rules = Some(mac); + macro_highlighter.init(); + current_macro = Some(mac); continue; } WalkEvent::Leave(Some(mac)) => { - assert_eq!(current_macro_rules, Some(mac)); - current_macro_rules = None; - macro_rules_highlighter = MacroRulesHighlighter::default(); + assert_eq!(current_macro, Some(mac)); + current_macro = None; + macro_highlighter = MacroHighlighter::default(); } _ => (), } @@ -164,9 +164,9 @@ fn traverse( let range = element.text_range(); - if current_macro_rules.is_some() { + if current_macro.is_some() { if let Some(tok) = element.as_token() { - macro_rules_highlighter.advance(tok); + macro_highlighter.advance(tok); } } @@ -200,7 +200,7 @@ fn traverse( } } - if let Some(_) = macro_rules_highlighter.highlight(element_to_highlight.clone()) { + if let Some(_) = macro_highlighter.highlight(element_to_highlight.clone()) { continue; } diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 38bf49348..963c3fb59 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs @@ -109,8 +109,7 @@ fn doc_attributes<'node>( ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))), ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), - ast::MacroRules(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))), - // ast::MacroDef(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), + ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))), // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), _ => return None } diff --git a/crates/ide/src/syntax_highlighting/macro_.rs b/crates/ide/src/syntax_highlighting/macro_.rs new file mode 100644 index 000000000..819704294 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/macro_.rs @@ -0,0 +1,129 @@ +//! Syntax highlighting for macro_rules!. +use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T}; + +use crate::{HlRange, HlTag}; + +#[derive(Default)] +pub(super) struct MacroHighlighter { + state: Option, +} + +impl MacroHighlighter { + pub(super) fn init(&mut self) { + self.state = Some(MacroMatcherParseState::default()); + } + + pub(super) fn advance(&mut self, token: &SyntaxToken) { + if let Some(state) = self.state.as_mut() { + update_macro_state(state, token); + } + } + + pub(super) fn highlight(&self, element: SyntaxElement) -> Option { + if let Some(state) = self.state.as_ref() { + if matches!(state.rule_state, RuleState::Matcher | RuleState::Expander) { + if let Some(range) = is_metavariable(element) { + return Some(HlRange { + range, + highlight: HlTag::UnresolvedReference.into(), + binding_hash: None, + }); + } + } + } + None + } +} + +struct MacroMatcherParseState { + /// Opening and corresponding closing bracket of the matcher or expander of the current rule + paren_ty: Option<(SyntaxKind, SyntaxKind)>, + paren_level: usize, + rule_state: RuleState, + /// Whether we are inside the outer `{` `}` macro block that holds the rules + in_invoc_body: bool, +} + +impl Default for MacroMatcherParseState { + fn default() -> Self { + MacroMatcherParseState { + paren_ty: None, + paren_level: 0, + in_invoc_body: false, + rule_state: RuleState::None, + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +enum RuleState { + Matcher, + Expander, + Between, + None, +} + +impl RuleState { + fn transition(&mut self) { + *self = match self { + RuleState::Matcher => RuleState::Between, + RuleState::Expander => RuleState::None, + RuleState::Between => RuleState::Expander, + RuleState::None => RuleState::Matcher, + }; + } +} + +fn update_macro_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) { + if !state.in_invoc_body { + if tok.kind() == T!['{'] || tok.kind() == T!['('] { + state.in_invoc_body = true; + } + return; + } + + match state.paren_ty { + Some((open, close)) => { + if tok.kind() == open { + state.paren_level += 1; + } else if tok.kind() == close { + state.paren_level -= 1; + if state.paren_level == 0 { + state.rule_state.transition(); + state.paren_ty = None; + } + } + } + None => { + match tok.kind() { + T!['('] => { + state.paren_ty = Some((T!['('], T![')'])); + } + T!['{'] => { + state.paren_ty = Some((T!['{'], T!['}'])); + } + T!['['] => { + state.paren_ty = Some((T!['['], T![']'])); + } + _ => (), + } + if state.paren_ty.is_some() { + state.paren_level = 1; + state.rule_state.transition(); + } + } + } +} + +fn is_metavariable(element: SyntaxElement) -> Option { + let tok = element.as_token()?; + match tok.kind() { + kind if kind == SyntaxKind::IDENT || kind.is_keyword() => { + if let Some(_dollar) = tok.prev_token().filter(|t| t.kind() == T![$]) { + return Some(tok.text_range()); + } + } + _ => (), + }; + None +} diff --git a/crates/ide/src/syntax_highlighting/macro_rules.rs b/crates/ide/src/syntax_highlighting/macro_rules.rs deleted file mode 100644 index 44620e912..000000000 --- a/crates/ide/src/syntax_highlighting/macro_rules.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! Syntax highlighting for macro_rules!. -use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T}; - -use crate::{HlRange, HlTag}; - -#[derive(Default)] -pub(super) struct MacroRulesHighlighter { - state: Option, -} - -impl MacroRulesHighlighter { - pub(super) fn init(&mut self) { - self.state = Some(MacroMatcherParseState::default()); - } - - pub(super) fn advance(&mut self, token: &SyntaxToken) { - if let Some(state) = self.state.as_mut() { - update_macro_rules_state(state, token); - } - } - - pub(super) fn highlight(&self, element: SyntaxElement) -> Option { - if let Some(state) = self.state.as_ref() { - if matches!(state.rule_state, RuleState::Matcher | RuleState::Expander) { - if let Some(range) = is_metavariable(element) { - return Some(HlRange { - range, - highlight: HlTag::UnresolvedReference.into(), - binding_hash: None, - }); - } - } - } - None - } -} - -struct MacroMatcherParseState { - /// Opening and corresponding closing bracket of the matcher or expander of the current rule - paren_ty: Option<(SyntaxKind, SyntaxKind)>, - paren_level: usize, - rule_state: RuleState, - /// Whether we are inside the outer `{` `}` macro block that holds the rules - in_invoc_body: bool, -} - -impl Default for MacroMatcherParseState { - fn default() -> Self { - MacroMatcherParseState { - paren_ty: None, - paren_level: 0, - in_invoc_body: false, - rule_state: RuleState::None, - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -enum RuleState { - Matcher, - Expander, - Between, - None, -} - -impl RuleState { - fn transition(&mut self) { - *self = match self { - RuleState::Matcher => RuleState::Between, - RuleState::Expander => RuleState::None, - RuleState::Between => RuleState::Expander, - RuleState::None => RuleState::Matcher, - }; - } -} - -fn update_macro_rules_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) { - if !state.in_invoc_body { - if tok.kind() == T!['{'] { - state.in_invoc_body = true; - } - return; - } - - match state.paren_ty { - Some((open, close)) => { - if tok.kind() == open { - state.paren_level += 1; - } else if tok.kind() == close { - state.paren_level -= 1; - if state.paren_level == 0 { - state.rule_state.transition(); - state.paren_ty = None; - } - } - } - None => { - match tok.kind() { - T!['('] => { - state.paren_ty = Some((T!['('], T![')'])); - } - T!['{'] => { - state.paren_ty = Some((T!['{'], T!['}'])); - } - T!['['] => { - state.paren_ty = Some((T!['['], T![']'])); - } - _ => (), - } - if state.paren_ty.is_some() { - state.paren_level = 1; - state.rule_state.transition(); - } - } - } -} - -fn is_metavariable(element: SyntaxElement) -> Option { - let tok = element.as_token()?; - match tok.kind() { - kind if kind == SyntaxKind::IDENT || kind.is_keyword() => { - if let Some(_dollar) = tok.prev_token().filter(|t| t.kind() == T![$]) { - return Some(tok.text_range()); - } - } - _ => (), - }; - None -} diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 8b2dd3b70..1eaa7b75b 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html @@ -41,7 +41,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd mod inner {} #[rustc_builtin_macro] -macro Copy {} +macro Copy {} // Needed for function consuming vs normal pub mod marker { @@ -158,6 +158,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd ($type:ty) => ($type) } +macro with_args($i:ident) { + $i +} + +macro without_args { + ($i:ident) => { + $i + } +} + // comment fn main() { println!("Hello, {}!", 92); diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 7b2922b0d..369ae0972 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -129,6 +129,16 @@ macro_rules! keyword_frag { ($type:ty) => ($type) } +macro with_args($i:ident) { + $i +} + +macro without_args { + ($i:ident) => { + $i + } +} + // comment fn main() { println!("Hello, {}!", 92); -- cgit v1.2.3