mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
wip: let's figure out how edn keymaps will work
This commit is contained in:
parent
4ab08e48e5
commit
794d4210c6
33 changed files with 161 additions and 85 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1448,6 +1448,7 @@ name = "tek_input"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tek_edn",
|
"tek_edn",
|
||||||
|
"tek_tui",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
15
Justfile
15
Justfile
|
|
@ -1,18 +1,15 @@
|
||||||
default:
|
default:
|
||||||
bacon -sj test
|
bacon -sj test
|
||||||
|
|
||||||
edn:
|
edn-view:
|
||||||
reset
|
reset
|
||||||
cargo run --example edn
|
cargo run --example edn-view
|
||||||
|
edn-keys:
|
||||||
|
reset
|
||||||
|
cargo run --example edn-keys
|
||||||
|
|
||||||
test:
|
test:
|
||||||
reset
|
cargo test --workspace
|
||||||
cd engine && cargo test && cd ..
|
|
||||||
cd layout && cargo test && cd ..
|
|
||||||
cd edn && cargo test && cd ..
|
|
||||||
cd tui && cargo test && cd ..
|
|
||||||
cargo test
|
|
||||||
|
|
||||||
cloc:
|
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
|
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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,10 +62,10 @@ impl<'a> Token<'a> {
|
||||||
)),
|
)),
|
||||||
_ => return Err(ParseError::Unexpected(c))
|
_ => return Err(ParseError::Unexpected(c))
|
||||||
},
|
},
|
||||||
Exp(source, index, length, depth) => match c {
|
Exp(source, index, length, balance) => match c {
|
||||||
')' => Exp(source, index, length + 1, depth - 1),
|
')' => Exp(source, index, length + 1, balance - 1),
|
||||||
'(' => Exp(source, index, length + 1, depth + 1),
|
'(' => Exp(source, index, length + 1, balance + 1),
|
||||||
_ => Exp(source, index, length + 1, depth)
|
_ => Exp(source, index, length + 1, balance)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
chars = next
|
chars = next
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,6 @@ version = "0.2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tek_edn = { path = "../edn" }
|
tek_edn = { path = "../edn" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tek_tui = { path = "../tui" }
|
||||||
|
|
|
||||||
0
input/examples/edn-keys.rs
Normal file
0
input/examples/edn-keys.rs
Normal file
0
input/examples/keys00.edn
Normal file
0
input/examples/keys00.edn
Normal file
0
input/examples/keys01.edn
Normal file
0
input/examples/keys01.edn
Normal file
0
input/examples/keys02.edn
Normal file
0
input/examples/keys02.edn
Normal file
|
|
@ -5,10 +5,22 @@ use std::marker::PhantomData;
|
||||||
/// Turns an EDN symbol sequence into a command enum variant.
|
/// Turns an EDN symbol sequence into a command enum variant.
|
||||||
pub trait EdnCommand<C>: Command<C> {
|
pub trait EdnCommand<C>: Command<C> {
|
||||||
fn from_edn <'a> (state: &C, head: &EdnItem<&str>, tail: &'a [EdnItem<String>]) -> Self;
|
fn from_edn <'a> (state: &C, head: &EdnItem<&str>, tail: &'a [EdnItem<String>]) -> Self;
|
||||||
|
fn get_isize (state: &C, item: &EdnItem<&str>) -> Option<isize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn get_usize (state: &C, item: &EdnItem<&str>) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn get_bool (state: &C, item: &EdnItem<&str>) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait EdnInput: Input {
|
pub trait EdnInput: Input {
|
||||||
fn matches (&self, token: &str) -> bool;
|
fn matches (&self, token: &str) -> bool;
|
||||||
|
fn get_event <S: AsRef<str>> (_: &EdnItem<S>) -> Option<Self::Event> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EdnKeymap(pub Vec<EdnItem<String>>);
|
pub struct EdnKeymap(pub Vec<EdnItem<String>>);
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
(:enter note/put)
|
(:enter add :false)
|
||||||
(:del note/del)
|
(:shift-enter add :true)
|
||||||
(:comma note/dur/dec)
|
(:del del :false)
|
||||||
(:period note/dur/inc)
|
(:shift-del del :true)
|
||||||
(:plus note/range/inc)
|
(:comma note/length :prev-note-length)
|
||||||
(:underscore note/range/dec)
|
(:period note/length :next-note-length)
|
||||||
(:up note/pos/inc)
|
(:plus note/range :next-note-range)
|
||||||
(:down note/pos/dec)
|
(:underscore note/range :prev-note-range)
|
||||||
(:left time/pos/dec)
|
(:up note/point :next-note-point)
|
||||||
(:right time/pos/inc)
|
(:down note/point :prev-note-point)
|
||||||
(:z time/zoom/lock)
|
(:left time/point :next-time-point)
|
||||||
(:equal time/zoom/in)
|
(:right time/point :prev-time-point)
|
||||||
(:minus time/zoom/out)
|
(:z time/lock :next-time-lock)
|
||||||
(:space clock/toggle)
|
(:equal time/zoom :next-time-zoom)
|
||||||
(:shift-space clock/toggle/zero)
|
(:minus time/zoom :prev-time-zoom)
|
||||||
(:u undo)
|
(:space clock/play :play-current)
|
||||||
(:r redo)
|
(:shift-space clock/play :play-start)
|
||||||
(:tab compact)
|
(:u history :history-prev)
|
||||||
(:q enqueue)
|
(:r history :history-next)
|
||||||
(:0 stop)
|
(:tab compact :next-compact)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ pub trait HasMidiClip {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A MIDI sequence.
|
/// A MIDI sequence.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct MidiClip {
|
pub struct MidiClip {
|
||||||
pub uuid: uuid::Uuid,
|
pub uuid: uuid::Uuid,
|
||||||
/// Name of clip
|
/// Name of clip
|
||||||
|
|
@ -83,10 +83,7 @@ impl MidiClip {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
pub fn stop_all () -> Self {
|
||||||
|
|
||||||
impl Default for MidiClip {
|
|
||||||
fn default () -> Self {
|
|
||||||
Self::new(
|
Self::new(
|
||||||
"Stop",
|
"Stop",
|
||||||
false,
|
false,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,23 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use self::MidiEditCommand::*;
|
use self::MidiEditCommand::*;
|
||||||
use KeyCode::*;
|
use KeyCode::*;
|
||||||
#[derive(Clone, Debug)]
|
impl EdnCommand<MidiEditor> for MidiEditCommand {
|
||||||
pub enum MidiEditCommand {
|
fn from_edn <'a> (state: &MidiEditor, head: &EdnItem<&str>, tail: &'a [EdnItem<String>]) -> 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
|
// TODO: 1-9 seek markers that by default start every 8th of the clip
|
||||||
AppendNote,
|
AppendNote,
|
||||||
PutNote,
|
PutNote,
|
||||||
|
|
@ -70,8 +85,3 @@ impl Command<MidiEditor> for MidiEditCommand {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl EdnCommand<MidiEditor> for MidiEditCommand {
|
|
||||||
fn from_edn <'a> (state: &MidiEditor, head: &EdnItem<&str>, tail: &'a [EdnItem<String>]) -> Self {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -135,34 +135,3 @@ impl ClipLengthFocus {
|
||||||
*self = match self { Self::Bar => Self::Tick, Self::Beat => Self::Bar, Self::Tick => Self::Beat, }
|
*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<str>),
|
|
||||||
}
|
|
||||||
impl Command<PoolModel> for ClipRenameCommand {
|
|
||||||
fn execute (self, state: &mut PoolModel) -> Perhaps<Self> {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -317,7 +317,6 @@ command!(|self: ClipLengthCommand,state:PoolModel|{
|
||||||
};
|
};
|
||||||
None
|
None
|
||||||
});
|
});
|
||||||
|
|
||||||
input_to_command!(ClipLengthCommand: |state: PoolModel, input: Event|{
|
input_to_command!(ClipLengthCommand: |state: PoolModel, input: Event|{
|
||||||
if let Some(PoolMode::Length(_, length, _)) = state.clips_mode() {
|
if let Some(PoolMode::Length(_, length, _)) = state.clips_mode() {
|
||||||
match input {
|
match input {
|
||||||
|
|
@ -333,10 +332,6 @@ input_to_command!(ClipLengthCommand: |state: PoolModel, input: Event|{
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
use crate::*;
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
|
|
||||||
impl InputToCommand<Event, PoolModel> for ClipRenameCommand {
|
impl InputToCommand<Event, PoolModel> for ClipRenameCommand {
|
||||||
fn input_to_command (state: &PoolModel, input: &Event) -> Option<Self> {
|
fn input_to_command (state: &PoolModel, input: &Event) -> Option<Self> {
|
||||||
use KeyCode::{Char, Backspace, Enter, Esc};
|
use KeyCode::{Char, Backspace, Enter, Esc};
|
||||||
|
|
@ -361,3 +356,34 @@ impl InputToCommand<Event, PoolModel> for ClipRenameCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum ClipRenameCommand {
|
||||||
|
Begin,
|
||||||
|
Cancel,
|
||||||
|
Confirm,
|
||||||
|
Set(Arc<str>),
|
||||||
|
}
|
||||||
|
impl Command<PoolModel> for ClipRenameCommand {
|
||||||
|
fn execute (self, state: &mut PoolModel) -> Perhaps<Self> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ name = "tek_output"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
tek_tui = { path = "../tui" }
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tek_edn = { path = "../edn" }
|
tek_edn = { path = "../edn" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tek_tui = { path = "../tui" }
|
||||||
|
|
|
||||||
|
|
@ -38,3 +38,6 @@
|
||||||
(< :track-swap-prev)
|
(< :track-swap-prev)
|
||||||
(> :track-swap-next)
|
(> :track-swap-next)
|
||||||
(del :track-delete))
|
(del :track-delete))
|
||||||
|
|
||||||
|
(:q enqueue :clip)
|
||||||
|
(:0 enqueue :stop)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
use crate::*;
|
||||||
|
impl EdnInput for TuiIn {
|
||||||
|
fn matches (&self, token: &str) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
fn get_event <S: AsRef<str>> (item: &EdnItem<S>) -> Option<Event> {
|
||||||
|
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<Event> {
|
||||||
|
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::<Vec<_>>();
|
||||||
|
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:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue