aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide/src/syntax_highlighting.rs40
-rw-r--r--crates/ide/src/syntax_highlighting/format.rs82
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
25use crate::{ 25use 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.
2use syntax::{ 2use 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
7use crate::{HlRange, HlTag, SymbolKind}; 7use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag, SymbolKind};
8 8
9use super::highlights::Highlights; 9pub(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| {
12pub(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
16impl FormatStringHighlighter { 29fn 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
60fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> { 48fn 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}