diff --git a/crates/ide-db/src/syntax_helpers/format_string.rs b/crates/ide-db/src/syntax_helpers/format_string.rs index 3c584a6cbc..819134a255 100644 --- a/crates/ide-db/src/syntax_helpers/format_string.rs +++ b/crates/ide-db/src/syntax_helpers/format_string.rs @@ -1,7 +1,7 @@ //! Tools to work with format string literals for the `format_args!` family of macros. use syntax::{ ast::{self, IsString}, - AstNode, AstToken, TextRange, + AstNode, AstToken, TextRange, TextSize, }; pub fn is_format_string(string: &ast::String) -> bool { @@ -48,6 +48,7 @@ pub enum FormatSpecifier { Dot, Asterisk, QuestionMark, + Escape, } pub fn lex_format_specifiers( @@ -66,7 +67,7 @@ pub fn lex_format_specifiers( // Format specifier, see syntax at https://doc.rust-lang.org/std/fmt/index.html#syntax if let Some((_, '{')) = chars.peek() { // Escaped format specifier, `{{` - chars.next(); + read_escaped_format_specifier(&mut chars, &mut callback); continue; } @@ -238,6 +239,11 @@ pub fn lex_format_specifiers( skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback); } continue; + } else if let '}' = first_char { + if let Some((_, '}')) = chars.peek() { + // Escaped format specifier, `}}` + read_escaped_format_specifier(&mut chars, &mut callback); + } } } @@ -288,4 +294,15 @@ pub fn lex_format_specifiers( } callback(range, FormatSpecifier::Identifier); } + + fn read_escaped_format_specifier(chars: &mut std::iter::Peekable, callback: &mut F) + where + I: Iterator, + F: FnMut(TextRange, FormatSpecifier), + { + let (range, _) = chars.peek().unwrap(); + let offset = TextSize::from(1); + callback(TextRange::new(range.start() - offset, range.end()), FormatSpecifier::Escape); + chars.next(); + } } diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs index 2d5f5f00e1..2ed57e2013 100644 --- a/crates/ide/src/syntax_highlighting/format.rs +++ b/crates/ide/src/syntax_highlighting/format.rs @@ -45,5 +45,6 @@ fn highlight_format_specifier(kind: FormatSpecifier) -> Option { FormatSpecifier::Integer | FormatSpecifier::Zero => HlTag::NumericLiteral, FormatSpecifier::Identifier => HlTag::Symbol(SymbolKind::Local), + FormatSpecifier::Escape => HlTag::EscapeSequence, }) } diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 60bc290121..c627bc9b09 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -93,6 +93,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } fn main() { + println!("Hello {{Hello}}"); // from https://doc.rust-lang.org/std/fmt/index.html println!("Hello"); // => "Hello" println!("Hello, {}!", "world"); // => "Hello, world!" @@ -105,7 +106,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd println!("{argument}", argument = "test"); // => "test" println!("{name} {}", 1, name = 2); // => "2 1" println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" - println!("{{{}}}", 2); // => "{2}" + println!("{{{}}}", 2); // => "{2}" println!("Hello {:5}!", "x"); println!("Hello {:1$}!", "x", 5); println!("Hello {1:0$}!", 5, "x"); @@ -128,8 +129,17 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56); println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56"); println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56"); - println!("Hello {{}}"); - println!("{{ Hello"); + + let _ = "{}" + let _ = "{{}}"; + + println!("Hello {{}}"); + println!("{{ Hello"); + println!("Hello }}"); + println!("{{Hello}}"); + println!("{{ Hello }}"); + println!("{{Hello }}"); + println!("{{ Hello}}"); println!(r"Hello, {}!", "world"); diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index e436a0574b..83bdca295d 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -421,6 +421,7 @@ macro_rules! toho { } fn main() { + println!("Hello {{Hello}}"); // from https://doc.rust-lang.org/std/fmt/index.html println!("Hello"); // => "Hello" println!("Hello, {}!", "world"); // => "Hello, world!" @@ -456,8 +457,17 @@ fn main() { println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56); println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56"); println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56"); + + let _ = "{}" + let _ = "{{}}"; + println!("Hello {{}}"); println!("{{ Hello"); + println!("Hello }}"); + println!("{{Hello}}"); + println!("{{ Hello }}"); + println!("{{Hello }}"); + println!("{{ Hello}}"); println!(r"Hello, {}!", "world");