diff options
Diffstat (limited to 'crates/ide/src/syntax_highlighting/format.rs')
-rw-r--r-- | crates/ide/src/syntax_highlighting/format.rs | 82 |
1 files changed, 36 insertions, 46 deletions
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 | } |