about summary refs log tree commit diff stats
path: root/pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi/mod.rs')
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi/mod.rs173
1 files changed, 173 insertions, 0 deletions
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi/mod.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi/mod.rs
new file mode 100644
index 00000000..0517ecf2
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi/mod.rs
@@ -0,0 +1,173 @@
+use std::mem;
+
+use vte::{Params, Parser, Perform};
+
+#[derive(Debug, Clone, Copy)]
+pub(crate) enum Color {
+    Black,
+    Red,
+    Green,
+    Yellow,
+    Blue,
+    Purple,
+    Cyan,
+    White,
+}
+
+#[derive(Debug)]
+struct Cleaner {
+    current_color: Option<Color>,
+    styles: StyledString,
+    current: String,
+}
+
+#[derive(Debug)]
+struct StyledStringInner {
+    val: String,
+    color: Option<Color>,
+}
+
+pub(crate) struct StyledChar {
+    ch: char,
+    color: Option<Color>,
+}
+
+impl StyledChar {
+    pub(crate) fn as_char(&self) -> char {
+        self.ch
+    }
+
+    pub(crate) fn is_bold(&self) -> bool {
+        self.color.is_some()
+    }
+
+    pub(crate) fn color(&self) -> Option<Color> {
+        self.color
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct StyledString {
+    inner: Vec<StyledStringInner>,
+}
+
+impl StyledString {
+    fn push(&mut self, val: StyledStringInner) {
+        self.inner.push(val);
+    }
+
+    pub(crate) fn chars(&self) -> impl Iterator<Item = StyledChar> + use<'_> {
+        self.inner.iter().flat_map(|inner| {
+            inner.val.chars().map(|ch| StyledChar {
+                ch,
+                color: inner.color,
+            })
+        })
+    }
+}
+
+impl Cleaner {
+    fn reset_color(&mut self) {
+        self.styles.push(StyledStringInner {
+            val: mem::take(&mut self.current),
+            color: mem::take(&mut self.current_color),
+        });
+    }
+
+    fn set_color(&mut self, color: Color) {
+        self.current_color = Some(color);
+    }
+
+    fn add_char(&mut self, c: char) {
+        self.current.push(c);
+    }
+}
+
+impl Perform for Cleaner {
+    fn print(&mut self, c: char) {
+        self.add_char(c);
+    }
+
+    fn execute(&mut self, byte: u8) {
+        if byte == b'\n' {
+            self.reset_color();
+            self.add_char('\n');
+            self.reset_color();
+        } else {
+            eprintln!("Unknown [execute]: {byte:02x}");
+        }
+    }
+
+    fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
+        eprintln!(
+            "Unknown [hook] params={params:?}, intermediates={intermediates:?}, ignore={ignore:?}, char={c:?}"
+        );
+    }
+
+    fn put(&mut self, byte: u8) {
+        eprintln!("Unknonw [put] {byte:02x}");
+    }
+
+    fn unhook(&mut self) {
+        eprintln!("Unknown [unhook]");
+    }
+
+    fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
+        eprintln!("Unkown [osc_dispatch] params={params:?} bell_terminated={bell_terminated}");
+    }
+
+    fn csi_dispatch(&mut self, params: &Params, _: &[u8], _: bool, c: char) {
+        let params: Vec<u16> = params.iter().flatten().copied().collect();
+
+        if c != 'm' {
+            return;
+        }
+
+        // See: https://gist.github.com/JBlond/2fea43a3049b38287e5e9cefc87b2124
+        match params[..] {
+            [0] => self.reset_color(),
+            // [0, regular] if matches!(regular, 30..=37) => {}
+            [1, bold] if matches!(bold, 30..=37) => match bold {
+                30 => self.set_color(Color::Black),
+                31 => self.set_color(Color::Red),
+                32 => self.set_color(Color::Green),
+                36 => self.set_color(Color::Yellow),
+                34 => self.set_color(Color::Blue),
+                35 => self.set_color(Color::Purple),
+                33 => self.set_color(Color::Cyan),
+                37 => self.set_color(Color::White),
+                _ => unreachable!("Was filtered out"),
+            },
+            // [4, underline] if matches!(underline, 30..=37) => {}
+            // [background] if matches!(background, 40..=47) => {}
+            _ => todo!(),
+        }
+
+        // println!(
+        //     "[csi_dispatch] params={:#?}, intermediates={:?}, ignore={:?}, char={:?}",
+        //     params, intermediates, ignore, c
+        // );
+    }
+
+    fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) {
+        eprintln!(
+            "Unkown [esc_dispatch] intermediates={intermediates:?}, ignore={ignore:?}, byte={byte:02x}"
+        );
+    }
+}
+
+pub(crate) fn parse(input: &str) -> StyledString {
+    let mut statemachine = Parser::new();
+    let mut performer = Cleaner {
+        current_color: None,
+        styles: StyledString { inner: vec![] },
+        current: String::new(),
+    };
+
+    let buf: Vec<_> = input.bytes().collect();
+
+    statemachine.advance(&mut performer, &buf[..]);
+
+    assert!(performer.current.is_empty() && performer.current_color.is_none());
+    performer.styles
+}