aboutsummaryrefslogtreecommitdiffstats
path: root/src/parse
diff options
context:
space:
mode:
authorJonas Maier <jonas@x77.dev>2026-06-01 20:50:42 +0200
committerJonas Maier <jonas@x77.dev>2026-06-01 20:50:42 +0200
commit632d4ab219715cd3a4bc012f4d4fa71f7a2deb31 (patch)
tree328ecb7462e1be08300a43a31e2eb60b181a9e36 /src/parse
parent53774d619c2b5c078d6c166b596664691f3c93d0 (diff)
downloadpish-632d4ab219715cd3a4bc012f4d4fa71f7a2deb31.tar.gz
syntax highlighting for variable interpolation and escape codes
Diffstat (limited to 'src/parse')
-rw-r--r--src/parse/mod.rs39
1 files changed, 37 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<Keyword> for HighlightKind {
+ fn from(value: Keyword) -> Self {
+ Self::Keyword(value)
+ }
+}
+
+impl From<OtherHighlights> 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<HighlightKind>) {
+ self.highlight(from.to(self.loc_u32()), kind)
+ }
+
+ fn highlight(&mut self, span: span::Span, kind: impl Into<HighlightKind>) {
+ 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 {