From 632d4ab219715cd3a4bc012f4d4fa71f7a2deb31 Mon Sep 17 00:00:00 2001 From: Jonas Maier Date: Mon, 1 Jun 2026 20:50:42 +0200 Subject: syntax highlighting for variable interpolation and escape codes --- src/parse/mod.rs | 39 +++++++++++++++++++++++++++++++++++++-- src/syntax_highlighting.rs | 2 ++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 4cba0fd..449df98 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -972,11 +972,13 @@ impl Parse for ExpString { } } + let begin = b.loc(); let x = b.adv(); if x == b'\\' && !delim.is_strict() { if let Some(x) = parse_escape_code(b)? { add_char(p, x); + b.highlight_from(begin, OtherHighlights::Escapes); } } else if x == b'$' && !delim.is_strict() { if !b.has() { @@ -989,13 +991,17 @@ impl Parse for ExpString { if is_var_begin(x) { let v = VarName::parse(b)?; p.push(StringPart::Var(Var::new(v))); + b.highlight_from(begin, OtherHighlights::Variable); continue; } b.adv(); match x { - b'?' | b'!' => p.push(StringPart::Var(Var::new(VarName { name: vec![x] }))), + b'?' | b'!' => { + b.highlight_from(begin, OtherHighlights::Variable); + p.push(StringPart::Var(Var::new(VarName { name: vec![x] }))) + } b'{' => { let v = VarName::parse(b)?; let mut default = None; @@ -1031,6 +1037,7 @@ impl Parse for ExpString { b.adv(); } + b.highlight_from(begin, OtherHighlights::Variable); p.push(StringPart::Var(Var { name: v, default, @@ -1077,6 +1084,7 @@ impl Parse for ExpString { default: None, already_complete: true, })); + b.highlight_from(begin, OtherHighlights::Variable); } else { add_char(p, x); } @@ -1348,15 +1356,31 @@ pub enum HighlightKind { Other(OtherHighlights), } +impl From for HighlightKind { + fn from(value: Keyword) -> Self { + Self::Keyword(value) + } +} + +impl From for HighlightKind { + fn from(value: OtherHighlights) -> Self { + Self::Other(value) + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Variants)] pub enum OtherHighlights { String, + Variable, + Escapes, } impl OtherHighlights { pub fn identifier(&self) -> &bstr { match self { OtherHighlights::String => b"string", + OtherHighlights::Variable => b"var", + OtherHighlights::Escapes => b"escape", } } } @@ -1574,6 +1598,17 @@ impl<'a> Cursor<'a> { self.file.from(self.loc_u32()) } + fn highlight_from(&mut self, from: span::SpanFrom, kind: impl Into) { + self.highlight(from.to(self.loc_u32()), kind) + } + + fn highlight(&mut self, span: span::Span, kind: impl Into) { + self.highlights.push(Highlight { + span, + kind: kind.into(), + }); + } + fn spaces_stats(&mut self) -> SpaceStats { let mut stats = SpaceStats::default(); while self.has() && b" \t\n\r".contains(&self.buf[0]) { @@ -1623,7 +1658,7 @@ impl<'a> Cursor<'a> { self.spaces(); Ok(()) } else { - if self.is_completion() { + if self.is_completion() && self.buf.len() == bytes.len() { self.buf = &self.buf[bytes.len()..]; Ok(()) } else { diff --git a/src/syntax_highlighting.rs b/src/syntax_highlighting.rs index 19f44ab..22a8c3e 100644 --- a/src/syntax_highlighting.rs +++ b/src/syntax_highlighting.rs @@ -28,6 +28,8 @@ impl Highlighter { sc("keywords", GREEN_FG); sc("braces", CYAN_FG); sc("string", MAGENTA_FG); + sc("var", CYAN_FG); + sc("escape", RED_FG); this } -- cgit v1.2.3