diff options
-rw-r--r-- | crates/ide/src/syntax_highlighting.rs | 40 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/format.rs | 82 |
2 files changed, 54 insertions, 68 deletions
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index b82e3775e..f2d4da78d 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -24,7 +24,7 @@ use syntax::{ | |||
24 | 24 | ||
25 | use crate::{ | 25 | use crate::{ |
26 | syntax_highlighting::{ | 26 | syntax_highlighting::{ |
27 | format::FormatStringHighlighter, highlights::Highlights, | 27 | format::highlight_format_string, highlights::Highlights, |
28 | macro_rules::MacroRulesHighlighter, tags::Highlight, | 28 | macro_rules::MacroRulesHighlighter, tags::Highlight, |
29 | }, | 29 | }, |
30 | FileId, HlMod, HlTag, SymbolKind, | 30 | FileId, HlMod, HlTag, SymbolKind, |
@@ -88,7 +88,6 @@ fn traverse( | |||
88 | 88 | ||
89 | let mut current_macro_call: Option<ast::MacroCall> = None; | 89 | let mut current_macro_call: Option<ast::MacroCall> = None; |
90 | let mut current_macro_rules: Option<ast::MacroRules> = None; | 90 | let mut current_macro_rules: Option<ast::MacroRules> = None; |
91 | let mut format_string_highlighter = FormatStringHighlighter::default(); | ||
92 | let mut macro_rules_highlighter = MacroRulesHighlighter::default(); | 91 | let mut macro_rules_highlighter = MacroRulesHighlighter::default(); |
93 | let mut inside_attribute = false; | 92 | let mut inside_attribute = false; |
94 | 93 | ||
@@ -120,7 +119,6 @@ fn traverse( | |||
120 | WalkEvent::Leave(Some(mc)) => { | 119 | WalkEvent::Leave(Some(mc)) => { |
121 | assert_eq!(current_macro_call, Some(mc)); | 120 | assert_eq!(current_macro_call, Some(mc)); |
122 | current_macro_call = None; | 121 | current_macro_call = None; |
123 | format_string_highlighter = FormatStringHighlighter::default(); | ||
124 | } | 122 | } |
125 | _ => (), | 123 | _ => (), |
126 | } | 124 | } |
@@ -175,8 +173,6 @@ fn traverse( | |||
175 | let token = sema.descend_into_macros(token.clone()); | 173 | let token = sema.descend_into_macros(token.clone()); |
176 | let parent = token.parent(); | 174 | let parent = token.parent(); |
177 | 175 | ||
178 | format_string_highlighter.check_for_format_string(&parent); | ||
179 | |||
180 | // We only care Name and Name_ref | 176 | // We only care Name and Name_ref |
181 | match (token.kind(), parent.kind()) { | 177 | match (token.kind(), parent.kind()) { |
182 | (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), | 178 | (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), |
@@ -195,6 +191,10 @@ fn traverse( | |||
195 | } | 191 | } |
196 | } | 192 | } |
197 | 193 | ||
194 | if let Some(_) = macro_rules_highlighter.highlight(element_to_highlight.clone()) { | ||
195 | continue; | ||
196 | } | ||
197 | |||
198 | if let Some((mut highlight, binding_hash)) = highlight::element( | 198 | if let Some((mut highlight, binding_hash)) = highlight::element( |
199 | &sema, | 199 | &sema, |
200 | &mut bindings_shadow_count, | 200 | &mut bindings_shadow_count, |
@@ -205,24 +205,20 @@ fn traverse( | |||
205 | highlight = highlight | HlMod::Attribute; | 205 | highlight = highlight | HlMod::Attribute; |
206 | } | 206 | } |
207 | 207 | ||
208 | if macro_rules_highlighter.highlight(element_to_highlight.clone()).is_none() { | 208 | hl.add(HlRange { range, highlight, binding_hash }); |
209 | hl.add(HlRange { range, highlight, binding_hash }); | 209 | } |
210 | } | ||
211 | 210 | ||
212 | if let Some(string) = | 211 | if let Some(string) = element_to_highlight.as_token().cloned().and_then(ast::String::cast) { |
213 | element_to_highlight.as_token().cloned().and_then(ast::String::cast) | 212 | highlight_format_string(hl, &string, range); |
214 | { | 213 | // Highlight escape sequences |
215 | format_string_highlighter.highlight_format_string(hl, &string, range); | 214 | if let Some(char_ranges) = string.char_ranges() { |
216 | // Highlight escape sequences | 215 | for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) { |
217 | if let Some(char_ranges) = string.char_ranges() { | 216 | if string.text()[piece_range.start().into()..].starts_with('\\') { |
218 | for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) { | 217 | hl.add(HlRange { |
219 | if string.text()[piece_range.start().into()..].starts_with('\\') { | 218 | range: piece_range + range.start(), |
220 | hl.add(HlRange { | 219 | highlight: HlTag::EscapeSequence.into(), |
221 | range: piece_range + range.start(), | 220 | binding_hash: None, |
222 | highlight: HlTag::EscapeSequence.into(), | 221 | }); |
223 | binding_hash: None, | ||
224 | }); | ||
225 | } | ||
226 | } | 222 | } |
227 | } | 223 | } |
228 | } | 224 | } |
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs index d807ad0ad..a74ca844b 100644 --- a/crates/ide/src/syntax_highlighting/format.rs +++ b/crates/ide/src/syntax_highlighting/format.rs | |||
@@ -1,60 +1,48 @@ | |||
1 | //! Syntax highlighting for format macro strings. | 1 | //! Syntax highlighting for format macro strings. |
2 | use syntax::{ | 2 | use syntax::{ |
3 | ast::{self, FormatSpecifier, HasFormatSpecifier}, | 3 | ast::{self, FormatSpecifier, HasFormatSpecifier}, |
4 | AstNode, AstToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, | 4 | AstNode, AstToken, TextRange, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{HlRange, HlTag, SymbolKind}; | 7 | use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag, SymbolKind}; |
8 | 8 | ||
9 | use super::highlights::Highlights; | 9 | pub(super) fn highlight_format_string( |
10 | stack: &mut Highlights, | ||
11 | string: &ast::String, | ||
12 | range: TextRange, | ||
13 | ) { | ||
14 | if is_format_string(string).is_none() { | ||
15 | return; | ||
16 | } | ||
10 | 17 | ||
11 | #[derive(Default)] | 18 | string.lex_format_specifier(|piece_range, kind| { |
12 | pub(super) struct FormatStringHighlighter { | 19 | if let Some(highlight) = highlight_format_specifier(kind) { |
13 | format_string: Option<SyntaxElement>, | 20 | stack.add(HlRange { |
21 | range: piece_range + range.start(), | ||
22 | highlight: highlight.into(), | ||
23 | binding_hash: None, | ||
24 | }); | ||
25 | } | ||
26 | }); | ||
14 | } | 27 | } |
15 | 28 | ||
16 | impl FormatStringHighlighter { | 29 | fn is_format_string(string: &ast::String) -> Option<()> { |
17 | pub(super) fn check_for_format_string(&mut self, parent: &SyntaxNode) { | 30 | let parent = string.syntax().parent(); |
18 | // Check if macro takes a format string and remember it for highlighting later. | 31 | |
19 | // The macros that accept a format string expand to a compiler builtin macros | 32 | let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; |
20 | // `format_args` and `format_args_nl`. | 33 | if !matches!(name.text().as_str(), "format_args" | "format_args_nl") { |
21 | if let Some(name) = parent | 34 | return None; |
22 | .parent() | ||
23 | .and_then(ast::MacroCall::cast) | ||
24 | .and_then(|mc| mc.path()) | ||
25 | .and_then(|p| p.segment()) | ||
26 | .and_then(|s| s.name_ref()) | ||
27 | { | ||
28 | match name.text().as_str() { | ||
29 | "format_args" | "format_args_nl" => { | ||
30 | self.format_string = parent | ||
31 | .children_with_tokens() | ||
32 | .filter(|t| t.kind() != SyntaxKind::WHITESPACE) | ||
33 | .nth(1) | ||
34 | .filter(|e| ast::String::can_cast(e.kind())) | ||
35 | } | ||
36 | _ => {} | ||
37 | } | ||
38 | } | ||
39 | } | 35 | } |
40 | pub(super) fn highlight_format_string( | 36 | |
41 | &self, | 37 | let first_literal = parent |
42 | stack: &mut Highlights, | 38 | .children_with_tokens() |
43 | string: &impl HasFormatSpecifier, | 39 | .filter_map(|it| it.as_token().cloned().and_then(ast::String::cast)) |
44 | range: TextRange, | 40 | .next()?; |
45 | ) { | 41 | if &first_literal != string { |
46 | if self.format_string.as_ref() == Some(&SyntaxElement::from(string.syntax().clone())) { | 42 | return None; |
47 | string.lex_format_specifier(|piece_range, kind| { | ||
48 | if let Some(highlight) = highlight_format_specifier(kind) { | ||
49 | stack.add(HlRange { | ||
50 | range: piece_range + range.start(), | ||
51 | highlight: highlight.into(), | ||
52 | binding_hash: None, | ||
53 | }); | ||
54 | } | ||
55 | }); | ||
56 | } | ||
57 | } | 43 | } |
44 | |||
45 | Some(()) | ||
58 | } | 46 | } |
59 | 47 | ||
60 | fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> { | 48 | fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> { |
@@ -70,7 +58,9 @@ fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> { | |||
70 | | FormatSpecifier::Dot | 58 | | FormatSpecifier::Dot |
71 | | FormatSpecifier::Asterisk | 59 | | FormatSpecifier::Asterisk |
72 | | FormatSpecifier::QuestionMark => HlTag::FormatSpecifier, | 60 | | FormatSpecifier::QuestionMark => HlTag::FormatSpecifier, |
61 | |||
73 | FormatSpecifier::Integer | FormatSpecifier::Zero => HlTag::NumericLiteral, | 62 | FormatSpecifier::Integer | FormatSpecifier::Zero => HlTag::NumericLiteral, |
63 | |||
74 | FormatSpecifier::Identifier => HlTag::Symbol(SymbolKind::Local), | 64 | FormatSpecifier::Identifier => HlTag::Symbol(SymbolKind::Local), |
75 | }) | 65 | }) |
76 | } | 66 | } |