aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-29 10:32:13 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-29 10:32:13 +0200
commit3d507acb42554b2551024ee3ca8490c203a1a9f8 (patch)
treececa79f3696cf9eab522be55c07c32e38de5edaf /pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi
parentflake.lock: Update (diff)
downloadnixos-config-3d507acb42554b2551024ee3ca8490c203a1a9f8.zip
pkgs/river-mk-keymap: Improve with key-chord support and which-key interface
Diffstat (limited to 'pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi')
-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
+}