From 44201ebf76a4ed691ea36a2de375210daf20f39b Mon Sep 17 00:00:00 2001 From: unspeaker Date: Tue, 14 Jan 2025 19:44:50 +0100 Subject: [PATCH] a random KeyMatcher appears --- midi/src/midi_pool.rs | 2 +- tek/src/keys.edn | 52 ++----------- tek/src/keys_clip.edn | 10 +++ tek/src/keys_scene.edn | 7 ++ tek/src/keys_track.edn | 7 ++ tui/src/tui_edn_keymap.rs | 154 +++++++++++++++++++++++++++++--------- 6 files changed, 152 insertions(+), 80 deletions(-) diff --git a/midi/src/midi_pool.rs b/midi/src/midi_pool.rs index bd5d2c33..6d3b2711 100644 --- a/midi/src/midi_pool.rs +++ b/midi/src/midi_pool.rs @@ -169,7 +169,7 @@ pub struct PoolView<'a>(pub bool, pub &'a MidiPool); content!(TuiOut: |self: PoolView<'a>| { let Self(compact, model) = self; let MidiPool { clips, mode, .. } = self.1; - let color = self.1.clip().map(|c|c.read().unwrap().color).unwrap_or_else(||TuiTheme::g(32).into()); + //let color = self.1.clip().map(|c|c.read().unwrap().color).unwrap_or_else(||TuiTheme::g(32).into()); let on_bg = |x|x;//Bsp::b(Repeat(" "), Tui::bg(color.darkest.rgb, x)); let border = |x|x;//Outer(Style::default().fg(color.dark.rgb).bg(color.darkest.rgb)).enclose(x); let iter = | |model.clips().clone().into_iter(); diff --git a/tek/src/keys.edn b/tek/src/keys.edn index e86e1916..1f5d4d18 100644 --- a/tek/src/keys.edn +++ b/tek/src/keys.edn @@ -1,44 +1,8 @@ -(def keys - (u :undo 1) - (shift-u :redo 1) - (ctrl-k :todo "keyboard") - (space :play-toggle) - (shift-space :play-start-toggle) - (e :editor-show :pool-phrase) - (ctrl-a :scene-add) - (ctrl-t :track-add) - (tab :pool-toggle)) - -(def keys-clip - (q :clip-launch) - (c :clip-color) - (g :clip-get) - (p :clip-put) - (del :clip-del) - (, :clip-prev) - (. :clip-next) - (< :clip-swap-prev) - (> :clip-swap-next) - (l :clip-loop-toggle)) - -(def keys-scene - (q :scene-launch) - (c :scene-color) - (, :scene-prev) - (. :scene-next) - (< :scene-swap-prev) - (> :scene-swap-next) - (del :scene-delete)) - -(def keys-track - (q :track-launch) - (c :track-color) - (, :track-prev) - (. :track-next) - (< :track-swap-prev) - (> :track-swap-next) - (del :track-delete)) - -(:q enqueue :clip) -(:0 enqueue :stop) - +(:u undo 1) +(:shift-u redo 1) +(:space play/toggle) +(:shift-space play/start-toggle) +(:e editor/show :pool-phrase) +(:ctrl-a scene/add) +(:ctrl-t track/add) +(:tab pool/toggle) diff --git a/tek/src/keys_clip.edn b/tek/src/keys_clip.edn index e69de29b..0822d8a4 100644 --- a/tek/src/keys_clip.edn +++ b/tek/src/keys_clip.edn @@ -0,0 +1,10 @@ +(q :clip-launch) +(c :clip-color) +(g :clip-get) +(p :clip-put) +(del :clip-del) +(, :clip-prev) +(. :clip-next) +(< :clip-swap-prev) +(> :clip-swap-next) +(l :clip-loop-toggle) diff --git a/tek/src/keys_scene.edn b/tek/src/keys_scene.edn index e69de29b..03866609 100644 --- a/tek/src/keys_scene.edn +++ b/tek/src/keys_scene.edn @@ -0,0 +1,7 @@ +(q :scene-launch) +(c :scene-color) +(, :scene-prev) +(. :scene-next) +(< :scene-swap-prev) +(> :scene-swap-next) +(del :scene-delete) diff --git a/tek/src/keys_track.edn b/tek/src/keys_track.edn index e69de29b..a756063b 100644 --- a/tek/src/keys_track.edn +++ b/tek/src/keys_track.edn @@ -0,0 +1,7 @@ +(q :track-launch) +(c :track-color) +(, :track-prev) +(. :track-next) +(< :track-swap-prev) +(> :track-swap-next) +(del :track-delete) diff --git a/tui/src/tui_edn_keymap.rs b/tui/src/tui_edn_keymap.rs index 05678878..5b5be2d9 100644 --- a/tui/src/tui_edn_keymap.rs +++ b/tui/src/tui_edn_keymap.rs @@ -2,50 +2,134 @@ use crate::*; impl EdnInput for TuiIn { fn matches_edn (&self, token: &str) -> bool { - if let Some(event) = parse_key_spec(token.to_string(), KeyModifiers::NONE) { + if let Some(event) = KeyMatcher::new(token).build() { &event == self.event() } else { false } } fn get_event > (item: &EdnItem) -> Option { - match item { EdnItem::Sym(s) => parse_key_spec(s.as_ref().to_string(), KeyModifiers::NONE), _ => None } + match item { EdnItem::Sym(s) => KeyMatcher::new(s).build(), _ => None } } } -fn parse_key_spec (spec: String, mut mods: KeyModifiers) -> Option { - Some(Event::Key(match spec.as_str() { - ":enter" | ":return" => KeyEvent::new(KeyCode::Enter, mods), - ":delete" | ":del" => KeyEvent::new(KeyCode::Enter, mods), - - ":comma" => KeyEvent::new(KeyCode::Char(','), mods), - ":period" => KeyEvent::new(KeyCode::Char('.'), mods), - - ":plus" => KeyEvent::new(KeyCode::Char('+'), mods), - ":underscore" => KeyEvent::new(KeyCode::Char('_'), mods), - - ":up" => KeyEvent::new(KeyCode::Up, mods), - ":down" => KeyEvent::new(KeyCode::Down, mods), - ":left" => KeyEvent::new(KeyCode::Left, mods), - ":right" => KeyEvent::new(KeyCode::Right, mods), - - _ => { - let chars = spec.chars().collect::>(); - match chars.as_slice() { - [':', c] => KeyEvent::new(KeyCode::Char(*c), mods), - [':', c @ ..] => { - let mut splits = c.split(|c|*c=='-'); - while let Some(split) = splits.next() { - match split { - ['c','t','r','l'] => mods |= KeyModifiers::CONTROL, - ['a','l','t'] => mods |= KeyModifiers::ALT, - ['s','h','i','f','t'] => mods |= KeyModifiers::SHIFT, - _ => return parse_key_spec(split.iter().collect(), mods) - } - } - panic!("invalid key event {spec:?}") +struct KeyMatcher { + valid: bool, + key: Option, + mods: KeyModifiers, +} +impl KeyMatcher { + fn new (token: impl AsRef) -> Self { + let token = token.as_ref(); + if token.len() < 2 { + Self { valid: false, key: None, mods: KeyModifiers::NONE } + } else if token.chars().next() != Some(':') { + Self { valid: false, key: None, mods: KeyModifiers::NONE } + } else { + Self { valid: true, key: None, mods: KeyModifiers::NONE }.next(&token[1..]) + } + } + fn next (mut self, token: &str) -> Self { + let mut tokens = token.split('-').peekable(); + while let Some(token) = tokens.next() { + if tokens.peek().is_some() { + match token { + "ctrl" | "Ctrl" | "c" | "C" => self.mods |= KeyModifiers::CONTROL, + "alt" | "Alt" | "m" | "M" => self.mods |= KeyModifiers::ALT, + "shift" | "Shift" | "s" | "S" => { + self.mods |= KeyModifiers::SHIFT; + // + TODO normalize character case, BackTab, etc. + }, + _ => panic!("unknown modifier {token}"), + } + } else { + self.key = if token.len() == 1 { + Some(KeyCode::Char(token.chars().next().unwrap())) + } else { + Some(Self::named_key(token).unwrap_or_else(||panic!("unknown character {token}"))) } - _ => panic!("invalid key event {spec:?}") } } - })) + self + } + fn named_key (token: &str) -> Option { + use KeyCode::*; + Some(match token { + "up" => Up, + "down" => Down, + "left" => Left, + "right" => Right, + "enter" | "return" => Enter, + "delete" | "del" => Delete, + "tab" => Tab, + "space" => Char(' '), + "comma" => Char(','), + "period" => Char('.'), + "plus" => Char('+'), + "minus" | "dash" => Char('-'), + "equal" | "equals" => Char('='), + "underscore" => Char('_'), + "backtick" => Char('`'), + _ => return None, + }) + } + fn build (self) -> Option { + if self.valid && self.key.is_some() { + Some(Event::Key(KeyEvent::new(self.key.unwrap(), self.mods))) + } else { + None + } + } } + +#[cfg(test)] #[test] fn test_parse_key () { + use KeyModifiers as Mods; + let test = |x: &str, y|assert_eq!(KeyMatcher::new(x).build(), Some(Event::Key(y))); + test(":x", + KeyEvent::new(KeyCode::Char('x'), Mods::NONE)); + test(":ctrl-x", + KeyEvent::new(KeyCode::Char('x'), Mods::CONTROL)); + test(":alt-x", + KeyEvent::new(KeyCode::Char('x'), Mods::ALT)); + test(":shift-x", + KeyEvent::new(KeyCode::Char('x'), Mods::SHIFT)); + test(":ctrl-alt-shift-x", + KeyEvent::new(KeyCode::Char('x'), Mods::CONTROL | Mods::ALT | Mods::SHIFT )); +} + +//fn parse_key (spec: std::str::Chars<'_>, mut mods: KeyModifiers) -> Option { + //Some(Event::Key(match spec.chars() { + //":enter" | ":return" => KeyEvent::new(KeyCode::Enter, mods), + //":delete" | ":del" => KeyEvent::new(KeyCode::Enter, mods), + + //":comma" => KeyEvent::new(KeyCode::Char(','), mods), + //":period" => KeyEvent::new(KeyCode::Char('.'), mods), + + //":plus" => KeyEvent::new(KeyCode::Char('+'), mods), + //":underscore" => KeyEvent::new(KeyCode::Char('_'), mods), + + //":up" => KeyEvent::new(KeyCode::Up, mods), + //":down" => KeyEvent::new(KeyCode::Down, mods), + //":left" => KeyEvent::new(KeyCode::Left, mods), + //":right" => KeyEvent::new(KeyCode::Right, mods), + + //_ => { + //let chars = spec.chars().collect::>(); + //match chars.as_slice() { + //[':', c] => KeyEvent::new(KeyCode::Char(*c), mods), + //[':', c @ ..] => { + //let mut splits = c.split(|c|*c=='-'); + //while let Some(split) = splits.next() { + //match split { + //['c','t','r','l'] => mods |= KeyModifiers::CONTROL, + //['a','l','t'] => mods |= KeyModifiers::ALT, + //['s','h','i','f','t'] => mods |= KeyModifiers::SHIFT, + //_ => return parse_key(split.iter().collect(), mods) + //} + //} + //panic!("invalid key event {spec:?}") + //} + //_ => panic!("invalid key event {spec:?}") + //} + //} + //})) +//}