From 794d4210c672086654838977cf7acae0b1f46af5 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sun, 12 Jan 2025 13:01:15 +0100 Subject: [PATCH] wip: let's figure out how edn keymaps will work --- Cargo.lock | 1 + Justfile | 15 +++--- edn/src/edn_token.rs | 8 ++-- input/Cargo.toml | 3 ++ input/examples/edn-keys.rs | 0 input/examples/keys00.edn | 0 input/examples/keys01.edn | 0 input/examples/keys02.edn | 0 input/src/edn_cmd.rs | 12 +++++ midi/edn/midi-keys.edn | 40 ++++++++-------- midi/edn/pool-keys.edn | 14 +++++- midi/src/midi_clip.rs | 7 +-- midi/src/midi_edit_cmd.rs | 24 +++++++--- midi/src/midi_pool.rs | 31 ------------- midi/src/midi_pool_cmd.rs | 36 +++++++++++++-- output/Cargo.toml | 6 +-- .../edn.rs => output/examples/edn-view.rs | 0 {tek => output}/examples/edn01.edn | 0 {tek => output}/examples/edn02.edn | 0 {tek => output}/examples/edn03.edn | 0 {tek => output}/examples/edn04.edn | 0 {tek => output}/examples/edn05.edn | 0 {tek => output}/examples/edn06.edn | 0 {tek => output}/examples/edn07.edn | 0 {tek => output}/examples/edn08.edn | 0 {tek => output}/examples/edn09.edn | 0 {tek => output}/examples/edn10.edn | 0 {tek => output}/examples/edn11.edn | 0 {tek => output}/examples/edn12.edn | 0 {tek => output}/examples/edn13.edn | 0 {tek => output}/examples/edn99.edn | 0 tek/edn/arranger-keys.edn | 3 ++ tui/src/tui_edn_keymap.rs | 46 +++++++++++++++++++ 33 files changed, 161 insertions(+), 85 deletions(-) create mode 100644 input/examples/edn-keys.rs create mode 100644 input/examples/keys00.edn create mode 100644 input/examples/keys01.edn create mode 100644 input/examples/keys02.edn rename tek/examples/edn.rs => output/examples/edn-view.rs (100%) rename {tek => output}/examples/edn01.edn (100%) rename {tek => output}/examples/edn02.edn (100%) rename {tek => output}/examples/edn03.edn (100%) rename {tek => output}/examples/edn04.edn (100%) rename {tek => output}/examples/edn05.edn (100%) rename {tek => output}/examples/edn06.edn (100%) rename {tek => output}/examples/edn07.edn (100%) rename {tek => output}/examples/edn08.edn (100%) rename {tek => output}/examples/edn09.edn (100%) rename {tek => output}/examples/edn10.edn (100%) rename {tek => output}/examples/edn11.edn (100%) rename {tek => output}/examples/edn12.edn (100%) rename {tek => output}/examples/edn13.edn (100%) rename {tek => output}/examples/edn99.edn (100%) diff --git a/Cargo.lock b/Cargo.lock index 1238a4d0..328e45fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1448,6 +1448,7 @@ name = "tek_input" version = "0.2.0" dependencies = [ "tek_edn", + "tek_tui", ] [[package]] diff --git a/Justfile b/Justfile index 63dea41c..70dd3e79 100644 --- a/Justfile +++ b/Justfile @@ -1,18 +1,15 @@ default: bacon -sj test -edn: +edn-view: reset - cargo run --example edn + cargo run --example edn-view +edn-keys: + reset + cargo run --example edn-keys test: - reset - cd engine && cargo test && cd .. - cd layout && cargo test && cd .. - cd edn && cargo test && cd .. - cd tui && cargo test && cd .. - cargo test - + cargo test --workspace cloc: for src in {cli,edn/src,input/src,jack/src,midi/src,output/src,plugin/src,sampler/src,tek/src,time/src,tui/src}; do echo; echo $src; cloc --quiet $src; done diff --git a/edn/src/edn_token.rs b/edn/src/edn_token.rs index d29867d8..55205676 100644 --- a/edn/src/edn_token.rs +++ b/edn/src/edn_token.rs @@ -62,10 +62,10 @@ impl<'a> Token<'a> { )), _ => return Err(ParseError::Unexpected(c)) }, - Exp(source, index, length, depth) => match c { - ')' => Exp(source, index, length + 1, depth - 1), - '(' => Exp(source, index, length + 1, depth + 1), - _ => Exp(source, index, length + 1, depth) + Exp(source, index, length, balance) => match c { + ')' => Exp(source, index, length + 1, balance - 1), + '(' => Exp(source, index, length + 1, balance + 1), + _ => Exp(source, index, length + 1, balance) }, }; chars = next diff --git a/input/Cargo.toml b/input/Cargo.toml index 76504c2a..8022543e 100644 --- a/input/Cargo.toml +++ b/input/Cargo.toml @@ -5,3 +5,6 @@ version = "0.2.0" [dependencies] tek_edn = { path = "../edn" } + +[dev-dependencies] +tek_tui = { path = "../tui" } diff --git a/input/examples/edn-keys.rs b/input/examples/edn-keys.rs new file mode 100644 index 00000000..e69de29b diff --git a/input/examples/keys00.edn b/input/examples/keys00.edn new file mode 100644 index 00000000..e69de29b diff --git a/input/examples/keys01.edn b/input/examples/keys01.edn new file mode 100644 index 00000000..e69de29b diff --git a/input/examples/keys02.edn b/input/examples/keys02.edn new file mode 100644 index 00000000..e69de29b diff --git a/input/src/edn_cmd.rs b/input/src/edn_cmd.rs index 2fbd9d39..5bee02e3 100644 --- a/input/src/edn_cmd.rs +++ b/input/src/edn_cmd.rs @@ -5,10 +5,22 @@ use std::marker::PhantomData; /// Turns an EDN symbol sequence into a command enum variant. pub trait EdnCommand: Command { fn from_edn <'a> (state: &C, head: &EdnItem<&str>, tail: &'a [EdnItem]) -> Self; + fn get_isize (state: &C, item: &EdnItem<&str>) -> Option { + None + } + fn get_usize (state: &C, item: &EdnItem<&str>) -> Option { + None + } + fn get_bool (state: &C, item: &EdnItem<&str>) -> Option { + None + } } pub trait EdnInput: Input { fn matches (&self, token: &str) -> bool; + fn get_event > (_: &EdnItem) -> Option { + None + } } pub struct EdnKeymap(pub Vec>); diff --git a/midi/edn/midi-keys.edn b/midi/edn/midi-keys.edn index 5aee15fb..43c129ae 100644 --- a/midi/edn/midi-keys.edn +++ b/midi/edn/midi-keys.edn @@ -1,20 +1,20 @@ -(:enter note/put) -(:del note/del) -(:comma note/dur/dec) -(:period note/dur/inc) -(:plus note/range/inc) -(:underscore note/range/dec) -(:up note/pos/inc) -(:down note/pos/dec) -(:left time/pos/dec) -(:right time/pos/inc) -(:z time/zoom/lock) -(:equal time/zoom/in) -(:minus time/zoom/out) -(:space clock/toggle) -(:shift-space clock/toggle/zero) -(:u undo) -(:r redo) -(:tab compact) -(:q enqueue) -(:0 stop) +(:enter add :false) +(:shift-enter add :true) +(:del del :false) +(:shift-del del :true) +(:comma note/length :prev-note-length) +(:period note/length :next-note-length) +(:plus note/range :next-note-range) +(:underscore note/range :prev-note-range) +(:up note/point :next-note-point) +(:down note/point :prev-note-point) +(:left time/point :next-time-point) +(:right time/point :prev-time-point) +(:z time/lock :next-time-lock) +(:equal time/zoom :next-time-zoom) +(:minus time/zoom :prev-time-zoom) +(:space clock/play :play-current) +(:shift-space clock/play :play-start) +(:u history :history-prev) +(:r history :history-next) +(:tab compact :next-compact) diff --git a/midi/edn/pool-keys.edn b/midi/edn/pool-keys.edn index 08d1b928..cc4a01da 100644 --- a/midi/edn/pool-keys.edn +++ b/midi/edn/pool-keys.edn @@ -1 +1,13 @@ -;TODO +(:n clip/rename/begin) +(:t clip/length/begin) +(:m clip/import/begin) +(:x clip/export/begin) +(:c clip/color/random) +(:bracket-open clip/select/prev) +(:bracket-close clip/select/next) +(:lt clip/move/prev) +(:gt clip/move/next) +(:del clip/delete) +(:shift-a clip/add) +(:i clip/insert) +(:d clip/duplicate) diff --git a/midi/src/midi_clip.rs b/midi/src/midi_clip.rs index 29c3f6a4..ae03ef05 100644 --- a/midi/src/midi_clip.rs +++ b/midi/src/midi_clip.rs @@ -13,7 +13,7 @@ pub trait HasMidiClip { } /// A MIDI sequence. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct MidiClip { pub uuid: uuid::Uuid, /// Name of clip @@ -83,10 +83,7 @@ impl MidiClip { } false } -} - -impl Default for MidiClip { - fn default () -> Self { + pub fn stop_all () -> Self { Self::new( "Stop", false, diff --git a/midi/src/midi_edit_cmd.rs b/midi/src/midi_edit_cmd.rs index 68c022f8..8c3926c4 100644 --- a/midi/src/midi_edit_cmd.rs +++ b/midi/src/midi_edit_cmd.rs @@ -1,8 +1,23 @@ use crate::*; use self::MidiEditCommand::*; use KeyCode::*; -#[derive(Clone, Debug)] -pub enum MidiEditCommand { +impl EdnCommand for MidiEditCommand { + fn from_edn <'a> (state: &MidiEditor, head: &EdnItem<&str>, tail: &'a [EdnItem]) -> Self { + use EdnItem::*; + match (head, tail) { + (Key("note/put"), [a]) => Self::PutNote, + (Key("note/del"), [a]) => Self::AppendNote, + (Key("note/dur"), [a]) => Self::AppendNote, + (Key("note/range"), [a]) => Self::AppendNote, + (Key("note/pos"), [a]) => Self::AppendNote, + (Key("time/pos"), [a]) => Self::AppendNote, + (Key("time/zoom"), [a]) => Self::AppendNote, + (Key("time/lock"), [a]) => Self::AppendNote, + _ => todo!() + } + } +} +#[derive(Clone, Debug)] pub enum MidiEditCommand { // TODO: 1-9 seek markers that by default start every 8th of the clip AppendNote, PutNote, @@ -70,8 +85,3 @@ impl Command for MidiEditCommand { Ok(None) } } -impl EdnCommand for MidiEditCommand { - fn from_edn <'a> (state: &MidiEditor, head: &EdnItem<&str>, tail: &'a [EdnItem]) -> Self { - todo!() - } -} diff --git a/midi/src/midi_pool.rs b/midi/src/midi_pool.rs index 72263c7d..a31aefa0 100644 --- a/midi/src/midi_pool.rs +++ b/midi/src/midi_pool.rs @@ -135,34 +135,3 @@ impl ClipLengthFocus { *self = match self { Self::Bar => Self::Tick, Self::Beat => Self::Bar, Self::Tick => Self::Beat, } } } -#[derive(Clone, Debug, PartialEq)] -pub enum ClipRenameCommand { - Begin, - Cancel, - Confirm, - Set(Arc), -} -impl Command for ClipRenameCommand { - fn execute (self, state: &mut PoolModel) -> Perhaps { - use ClipRenameCommand::*; - match state.clips_mode_mut().clone() { - Some(PoolMode::Rename(clip, ref mut old_name)) => match self { - Set(s) => { - state.clips()[clip].write().unwrap().name = s; - return Ok(Some(Self::Set(old_name.clone().into()))) - }, - Confirm => { - let old_name = old_name.clone(); - *state.clips_mode_mut() = None; - return Ok(Some(Self::Set(old_name))) - }, - Cancel => { - state.clips()[clip].write().unwrap().name = old_name.clone().into(); - }, - _ => unreachable!() - }, - _ => unreachable!() - }; - Ok(None) - } -} diff --git a/midi/src/midi_pool_cmd.rs b/midi/src/midi_pool_cmd.rs index 88895601..f163bba5 100644 --- a/midi/src/midi_pool_cmd.rs +++ b/midi/src/midi_pool_cmd.rs @@ -317,7 +317,6 @@ command!(|self: ClipLengthCommand,state:PoolModel|{ }; None }); - input_to_command!(ClipLengthCommand: |state: PoolModel, input: Event|{ if let Some(PoolMode::Length(_, length, _)) = state.clips_mode() { match input { @@ -333,10 +332,6 @@ input_to_command!(ClipLengthCommand: |state: PoolModel, input: Event|{ unreachable!() } }); -use crate::*; -use super::*; - - impl InputToCommand for ClipRenameCommand { fn input_to_command (state: &PoolModel, input: &Event) -> Option { use KeyCode::{Char, Backspace, Enter, Esc}; @@ -361,3 +356,34 @@ impl InputToCommand for ClipRenameCommand { } } } +#[derive(Clone, Debug, PartialEq)] +pub enum ClipRenameCommand { + Begin, + Cancel, + Confirm, + Set(Arc), +} +impl Command for ClipRenameCommand { + fn execute (self, state: &mut PoolModel) -> Perhaps { + use ClipRenameCommand::*; + match state.clips_mode_mut().clone() { + Some(PoolMode::Rename(clip, ref mut old_name)) => match self { + Set(s) => { + state.clips()[clip].write().unwrap().name = s; + return Ok(Some(Self::Set(old_name.clone().into()))) + }, + Confirm => { + let old_name = old_name.clone(); + *state.clips_mode_mut() = None; + return Ok(Some(Self::Set(old_name))) + }, + Cancel => { + state.clips()[clip].write().unwrap().name = old_name.clone().into(); + }, + _ => unreachable!() + }, + _ => unreachable!() + }; + Ok(None) + } +} diff --git a/output/Cargo.toml b/output/Cargo.toml index 69b39203..11da9a3a 100644 --- a/output/Cargo.toml +++ b/output/Cargo.toml @@ -3,8 +3,8 @@ name = "tek_output" edition = "2021" version = "0.2.0" -[dev-dependencies] -tek_tui = { path = "../tui" } - [dependencies] tek_edn = { path = "../edn" } + +[dev-dependencies] +tek_tui = { path = "../tui" } diff --git a/tek/examples/edn.rs b/output/examples/edn-view.rs similarity index 100% rename from tek/examples/edn.rs rename to output/examples/edn-view.rs diff --git a/tek/examples/edn01.edn b/output/examples/edn01.edn similarity index 100% rename from tek/examples/edn01.edn rename to output/examples/edn01.edn diff --git a/tek/examples/edn02.edn b/output/examples/edn02.edn similarity index 100% rename from tek/examples/edn02.edn rename to output/examples/edn02.edn diff --git a/tek/examples/edn03.edn b/output/examples/edn03.edn similarity index 100% rename from tek/examples/edn03.edn rename to output/examples/edn03.edn diff --git a/tek/examples/edn04.edn b/output/examples/edn04.edn similarity index 100% rename from tek/examples/edn04.edn rename to output/examples/edn04.edn diff --git a/tek/examples/edn05.edn b/output/examples/edn05.edn similarity index 100% rename from tek/examples/edn05.edn rename to output/examples/edn05.edn diff --git a/tek/examples/edn06.edn b/output/examples/edn06.edn similarity index 100% rename from tek/examples/edn06.edn rename to output/examples/edn06.edn diff --git a/tek/examples/edn07.edn b/output/examples/edn07.edn similarity index 100% rename from tek/examples/edn07.edn rename to output/examples/edn07.edn diff --git a/tek/examples/edn08.edn b/output/examples/edn08.edn similarity index 100% rename from tek/examples/edn08.edn rename to output/examples/edn08.edn diff --git a/tek/examples/edn09.edn b/output/examples/edn09.edn similarity index 100% rename from tek/examples/edn09.edn rename to output/examples/edn09.edn diff --git a/tek/examples/edn10.edn b/output/examples/edn10.edn similarity index 100% rename from tek/examples/edn10.edn rename to output/examples/edn10.edn diff --git a/tek/examples/edn11.edn b/output/examples/edn11.edn similarity index 100% rename from tek/examples/edn11.edn rename to output/examples/edn11.edn diff --git a/tek/examples/edn12.edn b/output/examples/edn12.edn similarity index 100% rename from tek/examples/edn12.edn rename to output/examples/edn12.edn diff --git a/tek/examples/edn13.edn b/output/examples/edn13.edn similarity index 100% rename from tek/examples/edn13.edn rename to output/examples/edn13.edn diff --git a/tek/examples/edn99.edn b/output/examples/edn99.edn similarity index 100% rename from tek/examples/edn99.edn rename to output/examples/edn99.edn diff --git a/tek/edn/arranger-keys.edn b/tek/edn/arranger-keys.edn index 0a8a50f4..222787c0 100644 --- a/tek/edn/arranger-keys.edn +++ b/tek/edn/arranger-keys.edn @@ -38,3 +38,6 @@ (< :track-swap-prev) (> :track-swap-next) (del :track-delete)) + +(:q enqueue :clip) +(:0 enqueue :stop) diff --git a/tui/src/tui_edn_keymap.rs b/tui/src/tui_edn_keymap.rs index e69de29b..071f32ee 100644 --- a/tui/src/tui_edn_keymap.rs +++ b/tui/src/tui_edn_keymap.rs @@ -0,0 +1,46 @@ +use crate::*; +impl EdnInput for TuiIn { + fn matches (&self, token: &str) -> bool { + false + } + fn get_event > (item: &EdnItem) -> Option { + match item { EdnItem::Sym(s) => parse_key_spec(s.as_ref().to_string(), KeyModifiers::NONE), _ => 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:?}") + } + _ => panic!("invalid key event {spec:?}") + } + } + })) +}