diff options
| author | Jonas Maier <jonas@x77.dev> | 2026-05-22 21:26:41 +0200 |
|---|---|---|
| committer | Jonas Maier <jonas@x77.dev> | 2026-05-22 21:26:41 +0200 |
| commit | eeb267c46340d5d47f41cc2440f0b281f9ae9261 (patch) | |
| tree | abcbc6624e0903cc1c7cd919d15a42ebb970692a /src/syntax_highlighting.rs | |
| parent | 07daff9331dbdc607584edbf1a8fb3e415c338ea (diff) | |
| download | pish-eeb267c46340d5d47f41cc2440f0b281f9ae9261.tar.gz | |
basic syntax highlighting
Diffstat (limited to 'src/syntax_highlighting.rs')
| -rw-r--r-- | src/syntax_highlighting.rs | 76 |
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(()) + } +} |
