ide/syntax_highlighting/
escape.rs

1//! Syntax highlighting for escape sequences
2use crate::syntax_highlighting::highlights::Highlights;
3use crate::{HighlightConfig, HlRange, HlTag};
4use syntax::ast::{Byte, Char, IsString};
5use syntax::{AstToken, TextRange, TextSize};
6
7pub(super) fn highlight_escape_string<T: IsString>(
8    stack: &mut Highlights,
9    config: &HighlightConfig<'_>,
10    string: &T,
11) {
12    let text = string.text();
13    let start = string.syntax().text_range().start();
14    string.escaped_char_ranges(&mut |piece_range, char| {
15        if text[piece_range.start().into()..].starts_with('\\') {
16            let highlight = match char {
17                Ok(_) => HlTag::EscapeSequence,
18                Err(_) => HlTag::InvalidEscapeSequence,
19            };
20            stack.add_with(
21                config,
22                HlRange {
23                    range: piece_range + start,
24                    highlight: highlight.into(),
25                    binding_hash: None,
26                },
27            );
28        }
29    });
30}
31
32pub(super) fn highlight_escape_char(
33    stack: &mut Highlights,
34    config: &HighlightConfig<'_>,
35    char: &Char,
36) {
37    if char.value().is_err() {
38        // We do not emit invalid escapes highlighting here. The lexer would likely be in a bad
39        // state and this token contains junk, since `'` is not a reliable delimiter (consider
40        // lifetimes). Nonetheless, parser errors should already be emitted.
41        return;
42    }
43
44    let text = char.text();
45    let Some(text) = text
46        .strip_prefix('\'')
47        .and_then(|it| it.strip_suffix('\''))
48        .filter(|it| it.starts_with('\\'))
49    else {
50        return;
51    };
52
53    let range = TextRange::at(
54        char.syntax().text_range().start() + TextSize::from(1),
55        TextSize::from(text.len() as u32),
56    );
57    stack.add_with(
58        config,
59        HlRange { range, highlight: HlTag::EscapeSequence.into(), binding_hash: None },
60    )
61}
62
63pub(super) fn highlight_escape_byte(
64    stack: &mut Highlights,
65    config: &HighlightConfig<'_>,
66    byte: &Byte,
67) {
68    if byte.value().is_err() {
69        // See `highlight_escape_char` for why no error highlighting here.
70        return;
71    }
72
73    let text = byte.text();
74    let Some(text) = text
75        .strip_prefix("b'")
76        .and_then(|it| it.strip_suffix('\''))
77        .filter(|it| it.starts_with('\\'))
78    else {
79        return;
80    };
81
82    let range = TextRange::at(
83        byte.syntax().text_range().start() + TextSize::from(2),
84        TextSize::from(text.len() as u32),
85    );
86    stack.add_with(
87        config,
88        HlRange { range, highlight: HlTag::EscapeSequence.into(), binding_hash: None },
89    )
90}