key pattern matching macro

This commit is contained in:
🪞👃🪞 2024-09-05 23:01:16 +03:00
parent e0c8a427f1
commit 92d747ba2a
7 changed files with 168 additions and 93 deletions

View file

@ -1 +0,0 @@
use crate::*;

View file

@ -33,8 +33,53 @@ pub fn handle_keymap <T> (
} }
} }
#[macro_export] macro_rules! key { #[macro_export] macro_rules! map_key {
($k:ident $(($char:literal))?, $m:ident, $n: literal, $d: literal, $f: expr) => { ($k:ident $(($char:literal))?, $m:ident, $n: literal, $d: literal, $f: expr) => {
(KeyCode::$k $(($char))?, KeyModifiers::$m, $n, $d, &$f as &dyn Fn()->Usually<bool>) (KeyCode::$k $(($char))?, KeyModifiers::$m, $n, $d, &$f as &dyn Fn()->Usually<bool>)
} }
} }
#[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)
}
}
}

View file

@ -10,8 +10,8 @@ pub struct Plugin {
pub ports: JackPorts, pub ports: JackPorts,
} }
impl Handle<Tui> for Plugin { impl Handle<Tui> for Plugin {
fn handle (&mut self, e: &Tui) -> Perhaps<bool> { fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
handle_keymap(self, event, KEYMAP_PLUGIN) handle_keymap(self, &from.event(), KEYMAP_PLUGIN).map(|x|Some(x))
} }
} }
process!(Plugin = Plugin::process); process!(Plugin = Plugin::process);

View file

@ -60,9 +60,9 @@ impl Render<Tui> for AddSampleModal {
impl Handle<Tui> for AddSampleModal { impl Handle<Tui> for AddSampleModal {
fn handle (&mut self, from: &Tui) -> Perhaps<bool> { fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
if handle_keymap(self, &from.event(), KEYMAP_ADD_SAMPLE)? { if handle_keymap(self, &from.event(), KEYMAP_ADD_SAMPLE)? {
return Ok(true) return Ok(Some(true))
} }
Ok(true) Ok(Some(true))
} }
} }

View file

@ -49,12 +49,13 @@ impl<E: Engine> Track<E> {
//None => () //None => ()
//}) //})
//} //}
}
impl Track<Tui> {
pub fn from_edn <'a, 'e> (args: &[Edn<'e>]) -> Usually<Track<Tui>> { pub fn from_edn <'a, 'e> (args: &[Edn<'e>]) -> Usually<Track<Tui>> {
let mut _gain = 0.0f64; let mut _gain = 0.0f64;
let mut track = Self::new("")?; let mut track = Self::new("")?;
#[allow(unused_mut)] #[allow(unused_mut)]
let mut devices: Vec<JackDevice<E>> = vec![]; let mut devices: Vec<JackDevice<Tui>> = vec![];
edn!(edn in args { edn!(edn in args {
Edn::Map(map) => { Edn::Map(map) => {
if let Some(Edn::Str(n)) = map.get(&Edn::Key(SYM_NAME)) { if let Some(Edn::Str(n)) = map.get(&Edn::Key(SYM_NAME)) {
@ -95,7 +96,7 @@ impl<E: Engine> Track<E> {
} }
Ok(track) Ok(track)
} }
pub fn add_device (&mut self, device: JackDevice<E>) { pub fn add_device (&mut self, device: JackDevice<Tui>) {
self.devices.push(device); self.devices.push(device);
} }
} }

View file

@ -3,38 +3,37 @@ use crate::*;
impl Handle<Tui> for Track<Tui> { impl Handle<Tui> for Track<Tui> {
fn handle (&mut self, from: &Tui) -> Perhaps<bool> { fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
match from.event() { match from.event() {
TuiEvent::Input(crossterm::event::Event::Key(event)) => { TuiEvent::Input(key) => match key {
for (code, modifiers, _, _, command) in [ //, NONE, "chain_cursor_up", "move cursor up", || {
key!(Up, NONE, "chain_cursor_up", "move cursor up", || { key!(KeyCode::Up) => {
Ok(true) Ok(Some(true))
}), },
key!(Down, NONE, "chain_cursor_down", "move cursor down", || { // , NONE, "chain_cursor_down", "move cursor down", || {
Ok(true) key!(KeyCode::Down) => {
}), Ok(Some(true))
key!(Left, NONE, "chain_cursor_left", "move cursor left", || { },
//if let Some(track) = app.arranger.track_mut() { // Left, NONE, "chain_cursor_left", "move cursor left", || {
//track.device = track.device.saturating_sub(1); key!(KeyCode::Left) => {
//return Ok(true) //if let Some(track) = app.arranger.track_mut() {
//} //track.device = track.device.saturating_sub(1);
Ok(false) //return Ok(true)
}), //}
key!(Right, NONE, "chain_cursor_right", "move cursor right", || { Ok(Some(true))
//if let Some(track) = app.arranger.track_mut() { },
//track.device = (track.device + 1).min(track.devices.len().saturating_sub(1)); // , NONE, "chain_cursor_right", "move cursor right", || {
//return Ok(true) key!(KeyCode::Right) => {
//} //if let Some(track) = app.arranger.track_mut() {
Ok(false) //track.device = (track.device + 1).min(track.devices.len().saturating_sub(1));
}), //return Ok(true)
key!(Char('`'), NONE, "chain_mode_switch", "switch the display mode", || { //}
//app.chain_mode = !app.chain_mode; Ok(Some(true))
Ok(true) },
}), // , NONE, "chain_mode_switch", "switch the display mode", || {
].iter() { key!(KeyCode::Char('`')) => {
if *code == event.code && modifiers.bits() == event.modifiers.bits() { //app.chain_mode = !app.chain_mode;
return command() Ok(Some(true))
} },
} _ => Ok(None)
return Ok(None)
}, },
_ => Ok(None) _ => Ok(None)
} }

View file

@ -10,58 +10,89 @@ impl Handle<Tui> for Arranger<Tui> {
return Ok(result) return Ok(result)
} }
match from.event() { match from.event() {
TuiEvent::Input(crossterm::event::Event::Key(event)) => { TuiEvent::Input(key) => match key {
for (code, modifiers, _, _, command) in [ // mode_switch: switch the display mode
key!(Char('`'), NONE, "mode_switch", "switch the display mode", || { key!(KeyCode::Char('`')) => {
self.mode.to_next(); self.mode.to_next();
Ok(true) Ok(Some(true))
}), },
key!(Up, NONE, "cursor_up", "move cursor up", || { // cursor_up: move cursor up
match self.mode { key!(KeyCode::Up) => {
ArrangerViewMode::Horizontal => self.track_prev(), match self.mode {
_ => self.scene_prev(), ArrangerViewMode::Horizontal => self.track_prev(),
}; _ => self.scene_prev(),
self.show_phrase()?; };
Ok(true) self.show_phrase()?;
}), Ok(Some(true))
key!(Down, NONE, "cursor_down", "move cursor down", || { },
match self.mode { // cursor_down
ArrangerViewMode::Horizontal => self.track_next(), key!(KeyCode::Down) => {
_ => self.scene_next(), match self.mode {
}; ArrangerViewMode::Horizontal => self.track_next(),
self.show_phrase()?; _ => self.scene_next(),
Ok(true) };
}), self.show_phrase()?;
key!(Left, NONE, "cursor_left", "move cursor left", || { Ok(Some(true))
match self.mode { },
ArrangerViewMode::Horizontal => self.scene_prev(), // cursor left
_ => self.track_prev(), key!(KeyCode::Left) => {
}; match self.mode {
self.show_phrase()?; ArrangerViewMode::Horizontal => self.scene_prev(),
Ok(true) _ => self.track_prev(),
}), };
key!(Right, NONE, "cursor_right", "move cursor right", || { self.show_phrase()?;
match self.mode { Ok(Some(true))
ArrangerViewMode::Horizontal => self.scene_next(), },
_ => self.track_next(), // cursor right
}; key!(KeyCode::Right) => {
self.show_phrase()?; match self.mode {
Ok(true) ArrangerViewMode::Horizontal => self.scene_next(),
}), _ => self.track_next(),
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) }), self.show_phrase()?;
key!(Enter, NONE, "activate", "activate item at cursor", || { self.activate(); Ok(true) }), Ok(Some(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) }), // increment: use next clip here
key!(Char('n'), NONE, "rename", "rename item at cursor", || { self.rename_selected(); Ok(true) }), key!(KeyCode::Char('.')) => {
key!(Char('l'), NONE, "length", "set length of item at cursor", || { todo!(); Ok(true) }), self.phrase_next();
key!(Char('c'), NONE, "color", "set color of item at cursor", || { todo!(); Ok(true) }) Ok(Some(true))
].iter() { },
if *code == event.code && modifiers.bits() == event.modifiers.bits() { // increment: use next clip here
return command() key!(KeyCode::Char(',')) => {
} self.phrase_prev();
} Ok(Some(true))
return Ok(None) },
// 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) _ => Ok(None)
} }