Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22993 from shulaoda/08-02-fix_recognize_format_arguments_after_a_backslash_in_raw_strings
fix: recognize format arguments after a backslash in raw strings
3 files changed, 76 insertions, 0 deletions
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_raw_string_format_specifiers.html b/crates/ide/src/syntax_highlighting/test_data/highlight_raw_string_format_specifiers.html new file mode 100644 index 0000000000..4497e83a4d --- /dev/null +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_raw_string_format_specifiers.html @@ -0,0 +1,49 @@ + +<style> +body { margin: 0; } +pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } + +.lifetime { color: #DFAF8F; font-style: italic; } +.label { color: #DFAF8F; font-style: italic; } +.comment { color: #7F9F7F; } +.documentation { color: #629755; } +.intra_doc_link { font-style: italic; } +.injected { opacity: 0.65 ; } +.struct, .enum { color: #7CB8BB; } +.enum_variant { color: #BDE0F3; } +.string_literal { color: #CC9393; } +.field { color: #94BFF3; } +.function { color: #93E0E3; } +.parameter { color: #94BFF3; } +.text { color: #DCDCCC; } +.type { color: #7CB8BB; } +.builtin_type { color: #8CD0D3; } +.type_param { color: #DFAF8F; } +.attribute { color: #94BFF3; } +.numeric_literal { color: #BFEBBF; } +.bool_literal { color: #BFE6EB; } +.macro { color: #94BFF3; } +.proc_macro { color: #94BFF3; text-decoration: underline; } +.derive { color: #94BFF3; font-style: italic; } +.module { color: #AFD8AF; } +.value_param { color: #DCDCCC; } +.variable { color: #DCDCCC; } +.format_specifier { color: #CC696B; } +.mutable { text-decoration: underline; } +.escape_sequence { color: #94BFF3; } +.keyword { color: #F0DFAF; font-weight: bold; } +.control { font-style: italic; } +.reference { font-style: italic; font-weight: bold; } +.const { font-weight: bolder; } +.unsafe { color: #BC8383; } +.deprecated { text-decoration: line-through; } + +.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } +.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } +</style> +<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> + <span class="keyword">let</span> <span class="variable declaration">here</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span> + <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">r"backslash \</span><span class="format_specifier">{</span><span class="variable">here</span><span class="format_specifier">}</span><span class="string_literal macro"> arg"</span><span class="parenthesis">)</span><span class="semicolon">;</span> + <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">r#"hashed \</span><span class="format_specifier">{</span><span class="variable">here</span><span class="format_specifier">}</span><span class="string_literal macro"> arg"#</span><span class="parenthesis">)</span><span class="semicolon">;</span> + <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"plain </span><span class="format_specifier">{</span><span class="variable">here</span><span class="format_specifier">}</span><span class="string_literal macro"> arg"</span><span class="parenthesis">)</span><span class="semicolon">;</span> +<span class="brace">}</span></code></pre>
\ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 6cb323b46a..7a3d71f519 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -453,6 +453,23 @@ macro_rules! void_2024 { } #[test] +fn test_raw_string_format_specifiers() { + check_highlighting( + r####" +//- minicore: fmt +fn main() { + let here = 1; + format_args!(r"backslash \{here} arg"); + format_args!(r#"hashed \{here} arg"#); + format_args!("plain {here} arg"); +} +"####, + expect_file!["./test_data/highlight_raw_string_format_specifiers.html"], + false, + ); +} + +#[test] fn test_string_highlighting() { // The format string detection is based on macro-expansion, // thus, we have to copy the macro definition from `std` diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index b5c4e1aa9d..f8bffe9d47 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -183,6 +183,16 @@ pub trait IsString: AstToken { let text = &self.text()[text_range_no_quotes - start]; let offset = text_range_no_quotes.start() - start; + if self.is_raw() { + let mut pos = offset; + for c in text.chars() { + let len = TextSize::of(c); + cb(TextRange::at(pos, len), Ok(c)); + pos += len; + } + return; + } + self.unescape(text, &mut |range: Range<usize>, unescaped_char| { if let Some((s, e)) = range.start.try_into().ok().zip(range.end.try_into().ok()) { cb(TextRange::new(s, e) + offset, unescaped_char); |