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/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 ++ 5 files changed, 151 insertions(+), 132 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/src/syntax_highlighting') 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