aboutsummaryrefslogtreecommitdiffstats
path: root/src/syntax_highlighting.rs
diff options
context:
space:
mode:
authorJonas Maier <jonas@x77.dev>2026-05-22 21:26:41 +0200
committerJonas Maier <jonas@x77.dev>2026-05-22 21:26:41 +0200
commiteeb267c46340d5d47f41cc2440f0b281f9ae9261 (patch)
treeabcbc6624e0903cc1c7cd919d15a42ebb970692a /src/syntax_highlighting.rs
parent07daff9331dbdc607584edbf1a8fb3e415c338ea (diff)
downloadpish-eeb267c46340d5d47f41cc2440f0b281f9ae9261.tar.gz
basic syntax highlighting
Diffstat (limited to 'src/syntax_highlighting.rs')
-rw-r--r--src/syntax_highlighting.rs76
1 files changed, 76 insertions, 0 deletions
diff --git a/src/syntax_highlighting.rs b/src/syntax_highlighting.rs
new file mode 100644
index 0000000..8a369da
--- /dev/null
+++ b/src/syntax_highlighting.rs
@@ -0,0 +1,76 @@
+use crate::parse::{Highlight, HighlightKind, Keyword};
+
+pub struct Highlighter {
+ pub enabled: bool,
+}
+
+impl Highlighter {
+ pub fn new() -> Self {
+ Self { enabled: true }
+ }
+
+ pub fn color(&self, h: HighlightKind) -> &[u8] {
+ // TODO: configurable
+ const GREEN: &[u8] = b"\x1b[32m";
+ const BLUE: &[u8] = b"\x1b[36m";
+ const MAGENTA: &[u8] = b"\x1b[95m";
+ const COLOR_RESET: &[u8] = b"\x1b[0m";
+ match h {
+ HighlightKind::Keyword(
+ Keyword::If | Keyword::Elif | Keyword::Else | Keyword::While,
+ ) => GREEN,
+ HighlightKind::Keyword(Keyword::OpenBrace | Keyword::CloseBrace) => BLUE,
+ HighlightKind::String => MAGENTA,
+ HighlightKind::None => COLOR_RESET,
+ }
+ }
+
+ pub fn pretty_print(
+ &self,
+ bytes: &[u8],
+ colors: Vec<Highlight>,
+ stdout: &mut dyn std::io::Write,
+ ) -> std::io::Result<()> {
+ let mut coloring: Vec<_> = colors
+ .into_iter()
+ .flat_map(|hi| {
+ [
+ (hi.span.start as usize, false, hi.kind),
+ (hi.span.end as usize, true, hi.kind),
+ ]
+ })
+ .collect();
+ coloring.sort_by_key(|x| (x.0, x.1));
+ let mut coloring = &coloring[..];
+ let mut color_stack = Vec::new();
+
+ let mut current_color = self.color(HighlightKind::None);
+
+ for (i, x) in bytes.iter().cloned().enumerate() {
+ while let Some((k, is_end, kind)) = coloring.first().cloned()
+ && k == i
+ {
+ coloring = &coloring[1..];
+ if is_end {
+ color_stack.pop();
+ } else {
+ color_stack.push(kind);
+ }
+
+ let new_color =
+ self.color(color_stack.last().cloned().unwrap_or(HighlightKind::None));
+
+ if current_color != new_color {
+ stdout.write_all(new_color)?;
+ current_color = new_color;
+ }
+ }
+
+ stdout.write_all(&[x])?;
+ }
+
+ stdout.write_all(self.color(HighlightKind::None))?;
+
+ Ok(())
+ }
+}