From 92d747ba2a4fdb82b544abaf094c7d8975cd368c Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 5 Sep 2024 23:01:16 +0300 Subject: [PATCH] key pattern matching macro --- crates/tek_core/src/handle.rs | 1 - crates/tek_core/src/keymap.rs | 47 ++++++- crates/tek_mixer/src/plugin.rs | 4 +- crates/tek_mixer/src/sample_add.rs | 4 +- crates/tek_mixer/src/track.rs | 7 +- crates/tek_mixer/src/track_handle.rs | 63 +++++---- crates/tek_sequencer/src/arranger_handle.rs | 135 ++++++++++++-------- 7 files changed, 168 insertions(+), 93 deletions(-) delete mode 100644 crates/tek_core/src/handle.rs diff --git a/crates/tek_core/src/handle.rs b/crates/tek_core/src/handle.rs deleted file mode 100644 index c7b7e813..00000000 --- a/crates/tek_core/src/handle.rs +++ /dev/null @@ -1 +0,0 @@ -use crate::*; diff --git a/crates/tek_core/src/keymap.rs b/crates/tek_core/src/keymap.rs index 191d97ea..c6b5e61d 100644 --- a/crates/tek_core/src/keymap.rs +++ b/crates/tek_core/src/keymap.rs @@ -33,8 +33,53 @@ pub fn handle_keymap ( } } -#[macro_export] macro_rules! key { +#[macro_export] macro_rules! map_key { ($k:ident $(($char:literal))?, $m:ident, $n: literal, $d: literal, $f: expr) => { (KeyCode::$k $(($char))?, KeyModifiers::$m, $n, $d, &$f as &dyn Fn()->Usually) } } + +#[macro_export] macro_rules! key { + ($code:pat) => { + crossterm::event::Event::Key(crossterm::event::KeyEvent { + code: $code, + modifiers: crossterm::event::KeyModifiers::NONE, + kind: crossterm::event::KeyEventKind::Press, + state: crossterm::event::KeyEventState::NONE + }) + }; + (Ctrl-$code:pat) => { + crossterm::event::Event::Key(crossterm::event::KeyEvent { + code: $code, + modifiers: crossterm::event::KeyModifiers::CONTROL, + kind: crossterm::event::KeyEventKind::Press, + state: crossterm::event::KeyEventState::NONE + }) + }; + (Alt-$code:pat) => { + crossterm::event::Event::Key(crossterm::event::KeyEvent { + code: $code, + modifiers: crossterm::event::KeyModifiers::ALT, + kind: crossterm::event::KeyEventKind::Press, + state: crossterm::event::KeyEventState::NONE + }) + } +} + +#[macro_export] macro_rules! match_key { + ($event:expr, { + $($key:pat=>$block:expr),* $(,)? + }) => { + match $event { + $(crossterm::event::Event::Key(crossterm::event::KeyEvent { + code: $key, + modifiers: crossterm::event::KeyModifiers::NONE, + kind: crossterm::event::KeyEventKind::Press, + state: crossterm::event::KeyEventState::NONE + }) => { + $block + })* + _ => Ok(None) + } + } +} diff --git a/crates/tek_mixer/src/plugin.rs b/crates/tek_mixer/src/plugin.rs index 6bfe3a87..2ddba9fe 100644 --- a/crates/tek_mixer/src/plugin.rs +++ b/crates/tek_mixer/src/plugin.rs @@ -10,8 +10,8 @@ pub struct Plugin { pub ports: JackPorts, } impl Handle for Plugin { - fn handle (&mut self, e: &Tui) -> Perhaps { - handle_keymap(self, event, KEYMAP_PLUGIN) + fn handle (&mut self, from: &Tui) -> Perhaps { + handle_keymap(self, &from.event(), KEYMAP_PLUGIN).map(|x|Some(x)) } } process!(Plugin = Plugin::process); diff --git a/crates/tek_mixer/src/sample_add.rs b/crates/tek_mixer/src/sample_add.rs index 85010f00..bf755b8b 100644 --- a/crates/tek_mixer/src/sample_add.rs +++ b/crates/tek_mixer/src/sample_add.rs @@ -60,9 +60,9 @@ impl Render for AddSampleModal { impl Handle for AddSampleModal { fn handle (&mut self, from: &Tui) -> Perhaps { if handle_keymap(self, &from.event(), KEYMAP_ADD_SAMPLE)? { - return Ok(true) + return Ok(Some(true)) } - Ok(true) + Ok(Some(true)) } } diff --git a/crates/tek_mixer/src/track.rs b/crates/tek_mixer/src/track.rs index 06f14a96..b38e24d1 100644 --- a/crates/tek_mixer/src/track.rs +++ b/crates/tek_mixer/src/track.rs @@ -49,12 +49,13 @@ impl Track { //None => () //}) //} - +} +impl Track { pub fn from_edn <'a, 'e> (args: &[Edn<'e>]) -> Usually> { let mut _gain = 0.0f64; let mut track = Self::new("")?; #[allow(unused_mut)] - let mut devices: Vec> = vec![]; + let mut devices: Vec> = vec![]; edn!(edn in args { Edn::Map(map) => { if let Some(Edn::Str(n)) = map.get(&Edn::Key(SYM_NAME)) { @@ -95,7 +96,7 @@ impl Track { } Ok(track) } - pub fn add_device (&mut self, device: JackDevice) { + pub fn add_device (&mut self, device: JackDevice) { self.devices.push(device); } } diff --git a/crates/tek_mixer/src/track_handle.rs b/crates/tek_mixer/src/track_handle.rs index 1add38d3..fcff5429 100644 --- a/crates/tek_mixer/src/track_handle.rs +++ b/crates/tek_mixer/src/track_handle.rs @@ -3,38 +3,37 @@ use crate::*; impl Handle for Track { fn handle (&mut self, from: &Tui) -> Perhaps { match from.event() { - TuiEvent::Input(crossterm::event::Event::Key(event)) => { - for (code, modifiers, _, _, command) in [ - key!(Up, NONE, "chain_cursor_up", "move cursor up", || { - Ok(true) - }), - key!(Down, NONE, "chain_cursor_down", "move cursor down", || { - Ok(true) - }), - key!(Left, NONE, "chain_cursor_left", "move cursor left", || { - //if let Some(track) = app.arranger.track_mut() { - //track.device = track.device.saturating_sub(1); - //return Ok(true) - //} - Ok(false) - }), - key!(Right, NONE, "chain_cursor_right", "move cursor right", || { - //if let Some(track) = app.arranger.track_mut() { - //track.device = (track.device + 1).min(track.devices.len().saturating_sub(1)); - //return Ok(true) - //} - Ok(false) - }), - key!(Char('`'), NONE, "chain_mode_switch", "switch the display mode", || { - //app.chain_mode = !app.chain_mode; - Ok(true) - }), - ].iter() { - if *code == event.code && modifiers.bits() == event.modifiers.bits() { - return command() - } - } - return Ok(None) + TuiEvent::Input(key) => match key { + //, NONE, "chain_cursor_up", "move cursor up", || { + key!(KeyCode::Up) => { + Ok(Some(true)) + }, + // , NONE, "chain_cursor_down", "move cursor down", || { + key!(KeyCode::Down) => { + Ok(Some(true)) + }, + // Left, NONE, "chain_cursor_left", "move cursor left", || { + key!(KeyCode::Left) => { + //if let Some(track) = app.arranger.track_mut() { + //track.device = track.device.saturating_sub(1); + //return Ok(true) + //} + Ok(Some(true)) + }, + // , NONE, "chain_cursor_right", "move cursor right", || { + key!(KeyCode::Right) => { + //if let Some(track) = app.arranger.track_mut() { + //track.device = (track.device + 1).min(track.devices.len().saturating_sub(1)); + //return Ok(true) + //} + Ok(Some(true)) + }, + // , NONE, "chain_mode_switch", "switch the display mode", || { + key!(KeyCode::Char('`')) => { + //app.chain_mode = !app.chain_mode; + Ok(Some(true)) + }, + _ => Ok(None) }, _ => Ok(None) } diff --git a/crates/tek_sequencer/src/arranger_handle.rs b/crates/tek_sequencer/src/arranger_handle.rs index 772d4b5d..05deadcd 100644 --- a/crates/tek_sequencer/src/arranger_handle.rs +++ b/crates/tek_sequencer/src/arranger_handle.rs @@ -10,58 +10,89 @@ impl Handle for Arranger { return Ok(result) } match from.event() { - TuiEvent::Input(crossterm::event::Event::Key(event)) => { - for (code, modifiers, _, _, command) in [ - key!(Char('`'), NONE, "mode_switch", "switch the display mode", || { - self.mode.to_next(); - Ok(true) - }), - key!(Up, NONE, "cursor_up", "move cursor up", || { - match self.mode { - ArrangerViewMode::Horizontal => self.track_prev(), - _ => self.scene_prev(), - }; - self.show_phrase()?; - Ok(true) - }), - key!(Down, NONE, "cursor_down", "move cursor down", || { - match self.mode { - ArrangerViewMode::Horizontal => self.track_next(), - _ => self.scene_next(), - }; - self.show_phrase()?; - Ok(true) - }), - key!(Left, NONE, "cursor_left", "move cursor left", || { - match self.mode { - ArrangerViewMode::Horizontal => self.scene_prev(), - _ => self.track_prev(), - }; - self.show_phrase()?; - Ok(true) - }), - key!(Right, NONE, "cursor_right", "move cursor right", || { - match self.mode { - ArrangerViewMode::Horizontal => self.scene_next(), - _ => self.track_next(), - }; - self.show_phrase()?; - Ok(true) - }), - key!(Char('.'), NONE, "increment", "set next clip at cursor", || { self.phrase_next(); Ok(true) }), - key!(Char(','), NONE, "decrement", "set previous clip at cursor", || { self.phrase_prev(); Ok(true) }), - key!(Enter, NONE, "activate", "activate item at cursor", || { self.activate(); Ok(true) }), - key!(Char('a'), CONTROL, "scene_add", "add a new scene", || { self.scene_add(None)?; Ok(true) }), - key!(Char('t'), CONTROL, "track_add", "add a new track", || { self.track_add(None)?; Ok(true) }), - key!(Char('n'), NONE, "rename", "rename item at cursor", || { self.rename_selected(); Ok(true) }), - key!(Char('l'), NONE, "length", "set length of item at cursor", || { todo!(); Ok(true) }), - key!(Char('c'), NONE, "color", "set color of item at cursor", || { todo!(); Ok(true) }) - ].iter() { - if *code == event.code && modifiers.bits() == event.modifiers.bits() { - return command() - } - } - return Ok(None) + TuiEvent::Input(key) => match key { + // mode_switch: switch the display mode + key!(KeyCode::Char('`')) => { + self.mode.to_next(); + Ok(Some(true)) + }, + // cursor_up: move cursor up + key!(KeyCode::Up) => { + match self.mode { + ArrangerViewMode::Horizontal => self.track_prev(), + _ => self.scene_prev(), + }; + self.show_phrase()?; + Ok(Some(true)) + }, + // cursor_down + key!(KeyCode::Down) => { + match self.mode { + ArrangerViewMode::Horizontal => self.track_next(), + _ => self.scene_next(), + }; + self.show_phrase()?; + Ok(Some(true)) + }, + // cursor left + key!(KeyCode::Left) => { + match self.mode { + ArrangerViewMode::Horizontal => self.scene_prev(), + _ => self.track_prev(), + }; + self.show_phrase()?; + Ok(Some(true)) + }, + // cursor right + key!(KeyCode::Right) => { + match self.mode { + ArrangerViewMode::Horizontal => self.scene_next(), + _ => self.track_next(), + }; + self.show_phrase()?; + Ok(Some(true)) + }, + // increment: use next clip here + key!(KeyCode::Char('.')) => { + self.phrase_next(); + Ok(Some(true)) + }, + // increment: use next clip here + key!(KeyCode::Char(',')) => { + self.phrase_prev(); + Ok(Some(true)) + }, + // decrement: use previous clip here + key!(KeyCode::Enter) => { + self.activate(); + Ok(Some(true)) + }, + // scene_add: add a new scene + key!(Ctrl-KeyCode::Char('a')) => { + self.scene_add(None)?; + Ok(Some(true)) + }, + // track_add: add a new scene + key!(Ctrl-KeyCode::Char('t')) => { + self.track_add(None)?; + Ok(Some(true)) + }, + // rename: add a new scene + key!(KeyCode::Char('n')) => { + self.rename_selected(); + Ok(Some(true)) + }, + // length: add a new scene + key!(KeyCode::Char('l')) => { + todo!(); + Ok(Some(true)) + }, + // color: set color of item at cursor + key!(KeyCode::Char('c')) => { + todo!(); + Ok(Some(true)) + }, + _ => Ok(None) }, _ => Ok(None) }