4925: Syntax highlighting for escape sequences in strings r=matklad a=ltentrup

I have added a new semantic token type `ESCAPE_SEQUENCE` as the LSP specification does not seem to have an appropriate token type. This may actually be a regression for some users, as the TextMate Rust grammar has a scope `constant.character.escape.rust` which highlights escape sequences (which caused problems with semantic highlighting, see #4138).

Fixes #2604.

Co-authored-by: Leander Tentrup <leander.tentrup@gmail.com>
This commit is contained in:
bors[bot] 2020-06-17 15:08:17 +00:00 committed by GitHub
commit f061b2daeb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 38 additions and 5 deletions

View File

@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.format_specifier { color: #CC696B; }
.mutable { text-decoration: underline; }
.unresolved_reference { color: #FC5555; }
.escape_sequence { color: #94BFF3; }
.keyword { color: #F0DFAF; font-weight: bold; }
.keyword.unsafe { color: #BC8383; font-weight: bold; }

View File

@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.format_specifier { color: #CC696B; }
.mutable { text-decoration: underline; }
.unresolved_reference { color: #FC5555; }
.escape_sequence { color: #94BFF3; }
.keyword { color: #F0DFAF; font-weight: bold; }
.keyword.unsafe { color: #BC8383; font-weight: bold; }

View File

@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.format_specifier { color: #CC696B; }
.mutable { text-decoration: underline; }
.unresolved_reference { color: #FC5555; }
.escape_sequence { color: #94BFF3; }
.keyword { color: #F0DFAF; font-weight: bold; }
.keyword.unsafe { color: #BC8383; font-weight: bold; }
@ -83,6 +84,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="macro">println!</span>(<span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>);
<span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span>, A = <span class="numeric_literal">92</span>);
<span class="comment">// escape sequences</span>
<span class="macro">println!</span>(<span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span>);
<span class="macro">println!</span>(<span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span>);
<span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span>, A = <span class="numeric_literal">92</span>);
<span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span>, ничоси = <span class="numeric_literal">92</span>);
}</code></pre>

View File

@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.format_specifier { color: #CC696B; }
.mutable { text-decoration: underline; }
.unresolved_reference { color: #FC5555; }
.escape_sequence { color: #94BFF3; }
.keyword { color: #F0DFAF; font-weight: bold; }
.keyword.unsafe { color: #BC8383; font-weight: bold; }

View File

@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.format_specifier { color: #CC696B; }
.mutable { text-decoration: underline; }
.unresolved_reference { color: #FC5555; }
.escape_sequence { color: #94BFF3; }
.keyword { color: #F0DFAF; font-weight: bold; }
.keyword.unsafe { color: #BC8383; font-weight: bold; }

View File

@ -26,6 +26,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.format_specifier { color: #CC696B; }
.mutable { text-decoration: underline; }
.unresolved_reference { color: #FC5555; }
.escape_sequence { color: #94BFF3; }
.keyword { color: #F0DFAF; font-weight: bold; }
.keyword.unsafe { color: #BC8383; font-weight: bold; }

View File

@ -212,8 +212,8 @@ pub(crate) fn highlight(
if let Some(string) =
element_to_highlight.as_token().cloned().and_then(ast::String::cast)
{
stack.push();
if is_format_string {
stack.push();
string.lex_format_specifier(|piece_range, kind| {
if let Some(highlight) = highlight_format_specifier(kind) {
stack.add(HighlightedRange {
@ -223,13 +223,27 @@ pub(crate) fn highlight(
});
}
});
stack.pop();
}
// Highlight escape sequences
if let Some(char_ranges) = string.char_ranges() {
stack.push();
for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) {
if string.text()[piece_range.start().into()..].starts_with('\\') {
stack.add(HighlightedRange {
range: piece_range + range.start(),
highlight: HighlightTag::EscapeSequence.into(),
binding_hash: None,
});
}
}
stack.pop_and_inject(false);
}
stack.pop();
} else if let Some(string) =
element_to_highlight.as_token().cloned().and_then(ast::RawString::cast)
{
stack.push();
if is_format_string {
stack.push();
string.lex_format_specifier(|piece_range, kind| {
if let Some(highlight) = highlight_format_specifier(kind) {
stack.add(HighlightedRange {
@ -239,8 +253,8 @@ pub(crate) fn highlight(
});
}
});
stack.pop();
}
stack.pop();
}
}
}

View File

@ -85,6 +85,7 @@ fn html_escape(text: &str) -> String {
.format_specifier { color: #CC696B; }
.mutable { text-decoration: underline; }
.unresolved_reference { color: #FC5555; }
.escape_sequence { color: #94BFF3; }
.keyword { color: #F0DFAF; font-weight: bold; }
.keyword.unsafe { color: #BC8383; font-weight: bold; }

View File

@ -23,6 +23,7 @@ pub enum HighlightTag {
Constant,
Enum,
EnumVariant,
EscapeSequence,
Field,
FormatSpecifier,
Function,
@ -71,6 +72,7 @@ fn as_str(self) -> &'static str {
HighlightTag::Constant => "constant",
HighlightTag::Enum => "enum",
HighlightTag::EnumVariant => "enum_variant",
HighlightTag::EscapeSequence => "escape_sequence",
HighlightTag::Field => "field",
HighlightTag::FormatSpecifier => "format_specifier",
HighlightTag::Function => "function",

View File

@ -246,6 +246,10 @@ fn main() {
println!(r"Hello, {}!", "world");
// escape sequences
println!("Hello\nWorld");
println!("\u{48}\x65\x6C\x6C\x6F World");
println!("{\x41}", A = 92);
println!("{ничоси}", ничоси = 92);
}"#

View File

@ -45,6 +45,7 @@ macro_rules! define_semantic_token_types {
(UNION, "union"),
(UNRESOLVED_REFERENCE, "unresolvedReference"),
(FORMAT_SPECIFIER, "formatSpecifier"),
(ESCAPE_SEQUENCE, "escapeSequence"),
];
macro_rules! define_semantic_token_modifiers {

View File

@ -324,6 +324,7 @@ fn semantic_token_type_and_modifiers(
HighlightTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE,
HighlightTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
HighlightTag::Operator => lsp_types::SemanticTokenType::OPERATOR,
HighlightTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
};
for modifier in highlight.modifiers.iter() {