fixed up some parsing and removed some edn mentions

This commit is contained in:
🪞👃🪞 2025-01-18 01:54:06 +01:00
parent 5e7b867aba
commit 452bdf9598
15 changed files with 290 additions and 292 deletions

View file

@ -30,17 +30,17 @@ macro_rules! iterate {
}
}
}
#[derive(Clone, PartialEq)] pub struct TokenIterator<'a>(&'a str);
impl<'a> Iterator for TokenIterator<'a> {
#[derive(Clone, PartialEq)] pub struct TokensIterator<'a>(&'a str);
impl<'a> Iterator for TokensIterator<'a> {
type Item = TokenResult<'a>;
fn next (&mut self) -> Option<TokenResult<'a>> { self.next_mut().map(|(result, _)|result) }
}
impl<'a> ConstIntoIter for TokenIterator<'a> {
impl<'a> ConstIntoIter for TokensIterator<'a> {
type Kind = IsIteratorKind;
type Item = Token<'a>;
type IntoIter = Self;
}
impl<'a> TokenIterator<'a> {
impl<'a> TokensIterator<'a> {
pub const fn new (source: &'a str) -> Self { Self(source) }
pub const fn split (&self, index: usize) -> Self { Self(split_at(self.0, index).1) }
pub const fn next (mut self) -> Option<(TokenResult<'a>, Self)> {
@ -124,17 +124,19 @@ impl<'a> Token<'a> {
d => Ok(Self { length: self.length + 1, depth: d - 1, ..self })
}
}
pub const fn to_ref_atom (&'a self) -> Result<RefAtom, ParseError> {
Ok(match self.kind {
Nil => return Err(ParseError::Empty),
Num => match to_number(self.slice()) {
Ok(n) => RefAtom::Num(n),
Err(e) => return Err(e)
pub const fn to_ref_atom (&self, source: &'a str) -> Result<RefAtom<'a>, ParseError> {
match self.kind {
Nil => Err(ParseError::Empty),
Num => match to_number(self.slice_source(source)) {
Err(e) => Err(e),
Ok(n) => Ok(RefAtom::Num(n)),
},
Sym => RefAtom::Sym(self.slice()),
Key => RefAtom::Key(self.slice()),
Exp => todo!()
})
Sym => Ok(RefAtom::Sym(self.slice_source(source))),
Key => Ok(RefAtom::Key(self.slice_source(source))),
Exp => Ok(
RefAtom::Exp(RefAtomsIterator(TokensIterator::new(self.slice_source(source))))
)
}
}
}
const fn to_number (digits: &str) -> Result<usize, ParseError> {
@ -155,32 +157,21 @@ const fn to_digit (c: char) -> Result<usize, ParseError> {
pub trait Atom: Sized {
fn kind (&self) -> TokenKind;
fn text (&self) -> &str;
fn num (&self) -> usize;
}
#[derive(Clone, PartialEq)] pub enum RefAtom<'a> {
Num(usize),
Sym(&'a str),
Key(&'a str),
Exp(RefAtomIterator<'a>),
Exp(RefAtomsIterator<'a>),
}
type RefAtomResult<'a> = Result<RefAtom<'a>, ParseError>;
#[derive(Clone, PartialEq)] pub struct RefAtomIterator<'a>(TokenIterator<'a>);
impl<'a> Iterator for RefAtomIterator<'a> {
#[derive(Clone, PartialEq)] pub struct RefAtomsIterator<'a>(TokensIterator<'a>);
impl<'a> Iterator for RefAtomsIterator<'a> {
type Item = RefAtomResult<'a>;
fn next (&mut self) -> Option<RefAtomResult<'a>> {
Some(if let Some(result) = Iterator::next(&mut self.0) {
match result {
Err(e) => Err(e),
Ok(token) => match token.kind {
Nil => Err(ParseError::Empty),
Num => match to_number(token.slice_source(self.0.0)) {
Ok(n) => Ok(RefAtom::Num(n)),
Err(e) => Err(e)
},
Sym => Ok(RefAtom::Sym(token.slice_source(self.0.0))),
Key => Ok(RefAtom::Key(token.slice_source(self.0.0))),
Exp => todo!()
}
}
match result { Ok(token) => token.to_ref_atom(self.0.0), Err(e) => Err(e), }
} else {
return None
})
@ -193,20 +184,8 @@ impl<'a> RefAtom<'a> {
pub fn read_all <'b: 'a> (source: &'b str)
-> impl Iterator<Item = Result<RefAtom<'b>, ParseError>> + 'b
{
TokenIterator::new(source).map(move |result|match result{
Err(e) => Err(e),
Ok(token) => match token.kind {
Nil => Err(ParseError::Empty),
Num => match to_number(token.slice_source(source)) {
Ok(n) => Ok(RefAtom::Num(n)),
Err(e) => return Err(e)
},
Sym => Ok(RefAtom::Sym(token.slice_source(source))),
Key => Ok(RefAtom::Key(token.slice_source(source))),
Exp => Ok(
RefAtom::Exp(RefAtomIterator(TokenIterator::new(token.slice_source(source))))
)
},
TokensIterator::new(source).map(move |result|match result {
Ok(token) => token.to_ref_atom(source), Err(e) => Err(e),
})
}
}
@ -226,6 +205,12 @@ impl<'a> Atom for RefAtom<'a> {
Self::Key(k) => k,
}
}
fn num (&self) -> usize {
match self {
Self::Num(n) => *n,
_ => 0
}
}
}
impl<'a> Debug for RefAtom<'a> {
fn fmt (&self, f: &mut Formatter<'_>) -> Result<(), FormatError> {
@ -245,7 +230,7 @@ impl<'a> Debug for RefAtom<'a> {
}
impl ArcAtom {
pub fn read_all <'a> (source: &'a str) -> impl Iterator<Item = Result<ArcAtom, ParseError>> + 'a {
TokenIterator::new(source).map(move |result: TokenResult<'a>|match result{
TokensIterator::new(source).map(move |result: TokenResult<'a>|match result{
Err(e) => Err(e),
Ok(token) => match token.kind {
Nil => Err(ParseError::Empty),
@ -283,6 +268,12 @@ impl<'a> Atom for ArcAtom {
Self::Key(k) => k.as_ref(),
}
}
fn num (&self) -> usize {
match self {
Self::Num(n) => *n,
_ => 0
}
}
}
impl<'a> Debug for ArcAtom {
fn fmt (&self, f: &mut Formatter<'_>) -> Result<(), FormatError> {
@ -306,27 +297,27 @@ impl<'a> Display for ArcAtom {
}
/// Map EDN tokens to parameters of a given type for a given context
pub trait Context<'a, U>: Sized {
fn get (&'a self, _edn: &'a impl Atom) -> Option<U> {
fn get (&'a self, _atom: &'a impl Atom) -> Option<U> {
None
}
fn get_or_fail (&'a self, edn: &'a impl Atom) -> U {
self.get(edn).expect("no value")
fn get_or_fail (&'a self, atom: &'a impl Atom) -> U {
self.get(atom).expect("no value")
}
}
impl<'a, T: Context<'a, U>, U> Context<'a, U> for &T {
fn get (&'a self, edn: &'a impl Atom) -> Option<U> {
(*self).get(edn)
fn get (&'a self, atom: &'a impl Atom) -> Option<U> {
(*self).get(atom)
}
fn get_or_fail (&'a self, edn: &'a impl Atom) -> U {
(*self).get_or_fail(edn)
fn get_or_fail (&'a self, atom: &'a impl Atom) -> U {
(*self).get_or_fail(atom)
}
}
impl<'a, T: Context<'a, U>, U> Context<'a, U> for Option<T> {
fn get (&'a self, edn: &'a impl Atom) -> Option<U> {
self.as_ref().map(|s|s.get(edn)).flatten()
fn get (&'a self, atom: &'a impl Atom) -> Option<U> {
self.as_ref().map(|s|s.get(atom)).flatten()
}
fn get_or_fail (&'a self, edn: &'a impl Atom) -> U {
self.as_ref().map(|s|s.get_or_fail(edn)).expect("no provider")
fn get_or_fail (&'a self, atom: &'a impl Atom) -> U {
self.as_ref().map(|s|s.get_or_fail(atom)).expect("no provider")
}
}
/// Implement `Context` for a context and type.
@ -334,18 +325,22 @@ impl<'a, T: Context<'a, U>, U> Context<'a, U> for Option<T> {
// Provide a value to the EDN template
($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
impl<'a> Context<'a, $type> for $State {
fn get (&'a $self, edn: &'a impl Atom) -> Option<$type> {
use RefAtom::*;
Some(match edn.to_ref() { $(Sym($pat) => $expr,)* _ => return None })
fn get (&'a $self, atom: &'a impl Atom) -> Option<$type> {
Some(match (atom.kind(), atom.text()) {
$((TokenKind::Sym, $pat) => $expr,)*
_ => return None
})
}
}
};
// Provide a value more generically
($lt:lifetime: $type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
impl<$lt> Context<$lt, $type> for $State {
fn get (&$lt $self, edn: &$lt impl Atom) -> Option<$type> {
use RefAtom::*;
Some(match edn.to_ref() { $(Sym($pat) => $expr,)* _ => return None })
fn get (&$lt $self, atom: &$lt impl Atom) -> Option<$type> {
Some(match (atom.kind(), atom.text()) {
$((TokenKind::Sym, $pat) => $expr,)*
_ => return None
})
}
}
};
@ -357,18 +352,24 @@ impl<'a, T: Context<'a, U>, U> Context<'a, U> for Option<T> {
// Provide a value that may also be a numeric literal in the EDN, to a generic implementation.
($type:ty:|$self:ident:<$T:ident:$Trait:path>|{ $($pat:pat => $expr:expr),* $(,)? }) => {
impl<'a, $T: $Trait> Context<'a, $type> for $T {
fn get (&'a $self, edn: &'a impl Atom) -> Option<$type> {
use RefAtom::*;
Some(match edn.to_ref() { $(Sym($pat) => $expr,)* Num(n) => n as $type, _ => return None })
fn get (&'a $self, atom: &'a impl Atom) -> Option<$type> {
Some(match (atom.kind(), atom.text()) {
$((TokenKind::Sym, $pat) => $expr,)*
(TokenKind::Num, _) => atom.num() as $type,
_ => return None
})
}
}
};
// Provide a value that may also be a numeric literal in the EDN, to a concrete implementation.
($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
impl<'a> Context<'a, $type> for $State {
fn get (&'a $self, edn: &'a impl Atom) -> Option<$type> {
use RefAtom::*;
Some(match edn.to_ref() { $(Sym($pat) => $expr,)* Num(n) => n as $type, _ => return None })
fn get (&'a $self, atom: &'a impl Atom) -> Option<$type> {
Some(match (atom.kind(), atom.text()) {
$((TokenKind::Sym, $pat) => $expr,)*
(TokenKind::Num, _) => atom.num() as $type,
_ => return None
})
}
}
};
@ -379,27 +380,35 @@ impl<'a, T: Context<'a, U>, U> Context<'a, U> for Option<T> {
#[macro_export] macro_rules! provide_content {
(|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
impl<'a, E: Output> Context<'a, Box<dyn Render<E> + 'a>> for $State {
fn get (&'a $self, edn: &'a impl Atom) -> Option<Box<dyn Render<E> + 'a>> {
fn get (&'a $self, atom: &'a impl Atom) -> Option<Box<dyn Render<E> + 'a>> {
use RefAtom::*;
Some(match edn.to_ref() { $(RefAtom::Sym($pat) => $expr),*, _ => return None })
Some(match atom.to_ref() { $(RefAtom::Sym($pat) => $expr),*, _ => return None })
}
}
};
($Output:ty: |$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
impl<'a> Context<'a, Box<dyn Render<$Output> + 'a>> for $State {
fn get (&'a $self, edn: &'a impl Atom) -> Option<Box<dyn Render<$Output> + 'a>> {
fn get (&'a $self, atom: &'a impl Atom) -> Option<Box<dyn Render<$Output> + 'a>> {
use RefAtom::*;
Some(match edn.to_ref() { $(Sym($pat) => $expr),*, _ => return None })
Some(match atom.to_ref() { $(Sym($pat) => $expr),*, _ => return None })
}
}
}
}
pub trait TryFromEdn<'a, T>: Sized {
fn try_from_edn (state: &'a T, head: &impl Atom, tail: &'a [impl Atom]) ->
#[macro_export] macro_rules! try_delegate {
($s:ident, $atom:expr, $T:ty) => {
if let [head, tail @ ..] = $atom.as_slice() {
if let Some(value) = <$T>::try_from_atom($s, head, tail) {
return Some(value.boxed())
}
}
}
}
pub trait TryFromAtom<'a, T>: Sized {
fn try_from_atom (state: &'a T, head: &impl Atom, tail: &'a [impl Atom]) ->
Option<Self>;
}
pub trait TryIntoEdn<'a, T>: Sized {
fn try_from_edn (state: &'a T, head: &impl Atom, tail: &'a [impl Atom]) ->
pub trait TryIntoAtom<'a, T>: Sized {
fn try_from_atom (state: &'a T, head: &impl Atom, tail: &'a [impl Atom]) ->
Option<Self>;
}

View file

@ -1,58 +1,58 @@
use crate::*;
pub trait KeyMap {
/// Try to find a command that matches the currently pressed key
fn command <S, C: EdnCommand<S>> (&self, state: &S, input: &impl EdnInput) -> Option<C>;
fn command <S, C: AtomCommand<S>> (&self, state: &S, input: &impl AtomInput) -> Option<C>;
}
pub struct SourceKeyMap<'a>(&'a str);
impl<'a> KeyMap for SourceKeyMap<'a> {
fn command <S, C: EdnCommand<S>> (&self, state: &S, input: &impl EdnInput) -> Option<C> {
todo!();
None
}
}
pub struct ParsedKeyMap<'a>(TokenIterator<'a>);
impl<'a> KeyMap for ParsedKeyMap<'a> {
fn command <S, C: EdnCommand<S>> (&self, state: &S, input: &impl EdnInput) -> Option<C> {
todo!();
None
}
}
pub struct RefKeyMap<'a>(TokenIterator<'a>);
impl<'a> KeyMap for RefKeyMap<'a> {
fn command <S, C: EdnCommand<S>> (&self, state: &S, input: &impl EdnInput) -> Option<C> {
todo!();
//for token in self.0 {
//match token?.kind() {
//TokenKind::Exp => match atoms.as_slice() {
//[key, command, args @ ..] => match (key.kind(), key.text()) {
//(TokenKind::Sym, key) => {
//if input.matches_edn(key) {
//let command = C::from_edn(state, command, args);
//if command.is_some() {
//return command
//pub struct SourceKeyMap<'a>(&'a str);
//impl<'a> KeyMap for SourceKeyMap<'a> {
//fn command <S, C: AtomCommand<S>> (&self, state: &S, input: &impl AtomInput) -> Option<C> {
//todo!();
//None
//}
//}
//},
//_ => panic!("invalid config: {item}")
//},
//_ => panic!("invalid config: {item}")
//}
//_ => panic!("invalid config: {item}")
//pub struct ParsedKeyMap<'a>(TokensIterator<'a>);
//impl<'a> KeyMap for ParsedKeyMap<'a> {
//fn command <S, C: AtomCommand<S>> (&self, state: &S, input: &impl AtomInput) -> Option<C> {
//todo!();
//None
//}
//}
//pub struct RefKeyMap<'a>(TokensIterator<'a>);
//impl<'a> KeyMap for RefKeyMap<'a> {
//fn command <S, C: AtomCommand<S>> (&self, state: &S, input: &impl AtomInput) -> Option<C> {
//todo!();
////for token in self.0 {
////match token?.kind() {
////TokenKind::Exp => match atoms.as_slice() {
////[key, command, args @ ..] => match (key.kind(), key.text()) {
////(TokenKind::Sym, key) => {
////if input.matches_atom(key) {
////let command = C::from_atom(state, command, args);
////if command.is_some() {
////return command
////}
////}
////},
////_ => panic!("invalid config: {item}")
////},
////_ => panic!("invalid config: {item}")
////}
////_ => panic!("invalid config: {item}")
////}
////}
//None
//}
//}
None
}
}
pub struct ArcKeyMap(Vec<ArcAtom>);
impl<'a> KeyMap for ArcKeyMap {
fn command <S, C: EdnCommand<S>> (&self, state: &S, input: &impl EdnInput) -> Option<C> {
fn command <S, C: AtomCommand<S>> (&self, state: &S, input: &impl AtomInput) -> Option<C> {
for atom in self.0.iter() {
match atom {
ArcAtom::Exp(atoms) => match atoms.as_slice() {
[key, command, args @ ..] => match (key.kind(), key.text()) {
(TokenKind::Sym, key) => {
if input.matches_edn(key) {
let command = C::from_edn(state, command, args);
if input.matches_atom(key) {
let command = C::from_atom(state, command, args);
if command.is_some() {
return command
}
@ -69,22 +69,22 @@ impl<'a> KeyMap for ArcKeyMap {
}
}
/// [Input] state that can be matched against an [Atom].
pub trait EdnInput: Input {
fn matches_edn (&self, token: &str) -> bool;
pub trait AtomInput: Input {
fn matches_atom (&self, token: &str) -> bool;
fn get_event <'a> (_: &impl Atom) -> Option<Self::Event> {
None
}
}
/// Turns an EDN item sequence into a command enum variant.
pub trait EdnCommand<C>: Command<C> {
fn from_edn <'a> (
pub trait AtomCommand<C>: Command<C> {
fn from_atom <'a> (
state: &C,
head: &impl Atom,
tail: &'a [impl Atom]
) -> Option<Self>;
}
/** Implement `EdnCommand` for given `State` and `Command` */
#[macro_export] macro_rules! edn_command {
/** Implement `AtomCommand` for given `State` and `Command` */
#[macro_export] macro_rules! atom_command {
($Command:ty : |$state:ident:<$T:ident: $Trait:path>| { $((
// identifier
$key:literal [
@ -106,22 +106,20 @@ pub trait EdnCommand<C>: Command<C> {
// bound command:
$command:expr
))* }) => {
impl<$T: $Trait> EdnCommand<$T> for $Command {
fn from_edn <'a> (
$state: &$T,
head: &impl Atom,
tail: &'a [impl Atom]
impl<$T: $Trait> AtomCommand<$T> for $Command {
fn from_atom <'a> (
$state: &$T, head: &impl Atom, tail: &'a [impl Atom]
) -> Option<Self> {
$(if let (Atom::Key($key), [ // if the identifier matches
$(if let (TokenType::Key, $key, [ // if the identifier matches
// bind argument ids
$($arg),*
// bind rest parameters
$(, $rest @ ..)?
]) = (head.to_ref(), tail) {
]) = (head.kind(), head.text(), tail) {
$(
$(let $arg: Option<$type> = Context::<$type>::get($state, $arg);)?
)*
//$(edn_command!(@bind $state => $arg $(?)? : $type);)*
//$(atom_command!(@bind $state => $arg $(?)? : $type);)*
return Some($command)
})*
None
@ -149,22 +147,22 @@ pub trait EdnCommand<C>: Command<C> {
// bound command:
$command:expr
))* }) => {
impl EdnCommand<$State> for $Command {
fn from_edn <'a> (
impl AtomCommand<$State> for $Command {
fn from_atom <'a> (
$state: &$State,
head: &impl Atom,
tail: &'a [impl Atom],
) -> Option<Self> {
$(if let (Atom::Key($key), [ // if the identifier matches
$(if let (TokenType::Key, $key, [ // if the identifier matches
// bind argument ids
$($arg),*
// bind rest parameters
$(, $rest @ ..)?
]) = (head.to_ref(), tail) {
]) = (head.kind(), head.text(), tail) {
$(
$(let $arg: Option<$type> = Context::<$type>::get($state, $arg);)?
)*
//$(edn_command!(@bind $state => $arg $(?)? : $type);)*
//$(atom_command!(@bind $state => $arg $(?)? : $type);)*
return Some($command)
})*
None
@ -178,7 +176,7 @@ pub trait EdnCommand<C>: Command<C> {
let $arg: $type = Context::<$type>::get_or_fail($state, $arg);
};
}
#[cfg(test)] #[test] fn test_edn_keymap () -> Usually<()> {
#[cfg(test)] #[test] fn test_atom_keymap () -> Usually<()> {
let keymap = KeyMap::new("")?;
Ok(())
}

View file

@ -184,7 +184,7 @@ impl MidiViewer for MidiEditor {
fn clip_mut (&mut self) -> &mut Option<Arc<RwLock<MidiClip>>> { self.mode.clip_mut() }
fn set_clip (&mut self, p: Option<&Arc<RwLock<MidiClip>>>) { self.mode.set_clip(p) }
}
edn_command!(MidiEditCommand: |state: MidiEditor| {
atom_command!(MidiEditCommand: |state: MidiEditor| {
("note/put" [_a: bool] Self::PutNote)
("note/del" [_a: bool] Self::PutNote)
("note/pos" [a: usize] Self::SetNoteCursor(a.expect("no note cursor")))
@ -208,14 +208,14 @@ edn_command!(MidiEditCommand: |state: MidiEditor| {
Show(Option<Arc<RwLock<MidiClip>>>),
}
impl MidiEditCommand {
fn from_tui_event (state: &MidiEditor, input: &impl EdnInput) -> Usually<Option<Self>> {
use EdnItem::*;
let edns = EdnItem::read_all(KEYS_EDIT)?;
for item in edns.iter() {
if let Exp(e) = item {
fn from_tui_event (state: &MidiEditor, input: &impl AtomInput) -> Usually<Option<Self>> {
use AtomItem::*;
let atoms = AtomItem::read_all(KEYS_EDIT)?;
for atom in atoms.iter() {
if let Exp(e) = atom {
match e.as_slice() {
[Sym(key), command, args @ ..] if input.matches_edn(key) => {
return Ok(MidiEditCommand::from_edn(state, command, args))
[Sym(key), command, args @ ..] if input.matches_atom(key) => {
return Ok(MidiEditCommand::from_atom(state, command, args))
}
_ => {}
}

View file

@ -190,19 +190,19 @@ content!(TuiOut: |self: ClipLength| {
}
});
impl PoolCommand {
pub fn from_tui_event (state: &MidiPool, input: &impl EdnInput) -> Usually<Option<Self>> {
use EdnItem::*;
let edns: Vec<EdnItem<_>> = EdnItem::read_all(match state.mode() {
pub fn from_tui_event (state: &MidiPool, input: &impl AtomInput) -> Usually<Option<Self>> {
use AtomItem::*;
let atoms: Vec<AtomItem<_>> = AtomItem::read_all(match state.mode() {
Some(PoolMode::Rename(..)) => KEYS_RENAME,
Some(PoolMode::Length(..)) => KEYS_LENGTH,
Some(PoolMode::Import(..)) | Some(PoolMode::Export(..)) => KEYS_FILE,
_ => KEYS_POOL
})?;
for item in edns {
for item in atoms {
match item {
Exp(e) => match e.as_slice() {
[Sym(key), command, args @ ..] if input.matches_edn(key) => {
return Ok(PoolCommand::from_edn(state, command, args))
[Sym(key), command, args @ ..] if input.matches_atom(key) => {
return Ok(PoolCommand::from_atom(state, command, args))
}
_ => {}
},
@ -273,14 +273,14 @@ provide!(ItemColor: |self: MidiPool| {
/// Update the contents of the clip pool
Clip(PoolClipCommand),
}
edn_command!(PoolCommand: |state: MidiPool| {
atom_command!(PoolCommand: |state: MidiPool| {
("show" [a: bool] Self::Show(a.expect("no flag")))
("select" [i: usize] Self::Select(i.expect("no index")))
("rename" [a, ..b] ClipRenameCommand::from_edn(state, &a.to_ref(), b).map(Self::Rename).expect("invalid command"))
("length" [a, ..b] ClipLengthCommand::from_edn(state, &a.to_ref(), b).map(Self::Length).expect("invalid command"))
("import" [a, ..b] FileBrowserCommand::from_edn(state, &a.to_ref(), b).map(Self::Import).expect("invalid command"))
("export" [a, ..b] FileBrowserCommand::from_edn(state, &a.to_ref(), b).map(Self::Export).expect("invalid command"))
("clip" [a, ..b] PoolClipCommand::from_edn(state, &a.to_ref(), b).map(Self::Clip).expect("invalid command"))
("rename" [a, ..b] ClipRenameCommand::from_atom(state, &a.to_ref(), b).map(Self::Rename).expect("invalid command"))
("length" [a, ..b] ClipLengthCommand::from_atom(state, &a.to_ref(), b).map(Self::Length).expect("invalid command"))
("import" [a, ..b] FileBrowserCommand::from_atom(state, &a.to_ref(), b).map(Self::Import).expect("invalid command"))
("export" [a, ..b] FileBrowserCommand::from_atom(state, &a.to_ref(), b).map(Self::Export).expect("invalid command"))
("clip" [a, ..b] PoolClipCommand::from_atom(state, &a.to_ref(), b).map(Self::Clip).expect("invalid command"))
});
command!(|self: PoolCommand, state: MidiPool|{
use PoolCommand::*;
@ -308,7 +308,7 @@ command!(|self: PoolCommand, state: MidiPool|{
SetLength(usize, usize),
SetColor(usize, ItemColor),
}
edn_command!(PoolClipCommand: |state: MidiPool| {
atom_command!(PoolClipCommand: |state: MidiPool| {
("add" [i: usize, c: MidiClip] Self::Add(i.expect("no index"), c.expect("no clip")))
("delete" [i: usize] Self::Delete(i.expect("no index")))
("swap" [a: usize, b: usize] Self::Swap(a.expect("no index"), b.expect("no index")))
@ -389,7 +389,7 @@ impl<T: HasClips> Command<T> for PoolClipCommand {
Confirm,
Set(Arc<str>),
}
edn_command!(ClipRenameCommand: |state: MidiPool| {
atom_command!(ClipRenameCommand: |state: MidiPool| {
("begin" [] Self::Begin)
("cancel" [] Self::Cancel)
("confirm" [] Self::Confirm)
@ -429,7 +429,7 @@ command!(|self: ClipRenameCommand, state: MidiPool|{
Inc,
Dec,
}
edn_command!(ClipLengthCommand: |state: MidiPool| {
atom_command!(ClipLengthCommand: |state: MidiPool| {
("begin" [] Self::Begin)
("cancel" [] Self::Cancel)
("next" [] Self::Next)
@ -475,7 +475,7 @@ command!(|self: ClipLengthCommand, state: MidiPool|{
}
None
});
edn_command!(FileBrowserCommand: |state: MidiPool| {
atom_command!(FileBrowserCommand: |state: MidiPool| {
("begin" [] Self::Begin)
("cancel" [] Self::Cancel)
("confirm" [] Self::Confirm)

View file

@ -45,8 +45,8 @@ impl<E: Output, A: Content<E>> Content<E> for Align<E, A> {
to.place(Content::layout(self, to.area()), &self.content())
}
}
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromEdn<'a, T> for Align<E, RenderBox<'a, E>> {
fn try_from_edn (
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for Align<E, RenderBox<'a, E>> {
fn try_from_atom (
state: &'a T,
head: &impl Atom,
tail: &'a [impl Atom]

View file

@ -93,8 +93,8 @@ impl<E: Output, A: Content<E>, B: Content<E>> BspAreas<E, A, B> for Bsp<E, A, B>
fn direction (&self) -> Direction { self.1 }
fn contents (&self) -> (&A, &B) { (&self.2, &self.3) }
}
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromEdn<'a, T> for Bsp<E, RenderBox<'a, E>, RenderBox<'a, E>> {
fn try_from_edn (s: &'a T, head: &impl Atom, tail: &'a [impl Atom]) -> Option<Self> {
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for Bsp<E, RenderBox<'a, E>, RenderBox<'a, E>> {
fn try_from_atom (s: &'a T, head: &impl Atom, tail: &'a [impl Atom]) -> Option<Self> {
Some(match (head.to_ref(), tail) {
(Key("bsp/n"), [a, b]) => Self::n(
s.get_content(a).expect("no south"),

View file

@ -7,8 +7,8 @@ impl<E, A> When<E, A> {
Self(Default::default(), c, a)
}
}
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromEdn<'a, T> for When<E, RenderBox<'a, E>> {
fn try_from_edn (
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for When<E, RenderBox<'a, E>> {
fn try_from_atom (
state: &'a T, head: &impl Atom, tail: &'a [impl Atom]
) -> Option<Self> {
if let (Key("when"), [condition, content]) = (head.to_ref(), tail) {
@ -47,8 +47,8 @@ impl<E, A, B> Either<E, A, B> {
Self(Default::default(), c, a, b)
}
}
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromEdn<'a, T> for Either<E, RenderBox<'a, E>, RenderBox<'a, E>> {
fn try_from_edn (state: &'a T, head: &impl Atom, tail: &'a [impl Atom]) -> Option<Self> {
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for Either<E, RenderBox<'a, E>, RenderBox<'a, E>> {
fn try_from_atom (state: &'a T, head: &impl Atom, tail: &'a [impl Atom]) -> Option<Self> {
if let (Key("either"), [condition, content, alternative]) = (head.to_ref(), tail) {
Some(Self::new(
state.get_bool(condition).expect("either: no condition"),

View file

@ -27,8 +27,8 @@ macro_rules! transform_xy {
$area
}
}
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromEdn<'a, T> for $Enum<E, RenderBox<'a, E>> {
fn try_from_edn (
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for $Enum<E, RenderBox<'a, E>> {
fn try_from_atom (
state: &'a T, head: &impl Atom, tail: &'a [impl Atom]
) -> Option<Self> {
Some(match (head.to_ref(), tail) {
@ -82,8 +82,8 @@ macro_rules! transform_xy_unit {
$layout.into()
}
}
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromEdn<'a, T> for $Enum<E, E::Unit, RenderBox<'a, E>> {
fn try_from_edn (
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for $Enum<E, E::Unit, RenderBox<'a, E>> {
fn try_from_atom (
state: &'a T, head: &impl Atom, tail: &'a [impl Atom]
) -> Option<Self> {
Some(match (head.to_ref(), tail) {

View file

@ -1,5 +1,6 @@
use crate::*;
use std::{sync::Arc, marker::PhantomData};
use TokenKind::*;
/// Define an EDN-backed view.
///
/// This consists of:
@ -14,8 +15,8 @@ use std::{sync::Arc, marker::PhantomData};
}
$(
impl<'a> Context<'a, $type> for $App {
fn get (&'a $self, edn: &'a impl Atom) -> Option<$type> {
Some(match edn.to_ref() { $(Atom::Sym($sym) => $value,)* _ => return None })
fn get (&'a $self, atom: &'a impl Atom) -> Option<$type> {
Some(match atom.to_ref() { $(Atom::Sym($sym) => $value,)* _ => return None })
}
}
)*
@ -25,8 +26,8 @@ use std::{sync::Arc, marker::PhantomData};
#[macro_export] macro_rules! provide_content {
(|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
impl<'a, E: Output> Context<'a, Box<dyn Render<E> + 'a>> for $State {
fn get (&'a $self, edn: &'a impl Atom) -> Option<Box<dyn Render<E> + 'a>> {
Some(match edn.to_ref() {
fn get (&'a $self, atom: &'a impl Atom) -> Option<Box<dyn Render<E> + 'a>> {
Some(match atom.to_ref() {
$(Atom::Sym($pat) => $expr),*,
_ => return None
})
@ -35,8 +36,8 @@ use std::{sync::Arc, marker::PhantomData};
};
($Output:ty: |$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
impl<'a> Context<'a, Box<dyn Render<$Output> + 'a>> for $State {
fn get (&'a $self, edn: &'a impl Atom) -> Option<Box<dyn Render<$Output> + 'a>> {
Some(match edn.to_ref() {
fn get (&'a $self, atom: &'a impl Atom) -> Option<Box<dyn Render<$Output> + 'a>> {
Some(match atom.to_ref() {
$(Atom::Sym($pat) => $expr),*,
_ => return None
})
@ -45,22 +46,22 @@ use std::{sync::Arc, marker::PhantomData};
}
}
/// Renders from EDN source and context.
#[derive(Default)] pub enum EdnView<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> {
#[derive(Default)] pub enum AtomView<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> {
#[default] Inert,
Ok(T, Atom<Arc<str>>),
//render: Box<dyn Fn(&'a T)->Box<dyn Render<E> + Send + Sync + 'a> + Send + Sync + 'a>
Err(String),
_Unused(PhantomData<&'a E>),
}
impl<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> std::fmt::Debug for EdnView<'a, E, T> {
impl<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> std::fmt::Debug for AtomView<'a, E, T> {
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
Self::Inert | Self::_Unused(_) =>
write!(f, "EdnView::Inert"),
write!(f, "AtomView::Inert"),
Self::Ok(state, view) =>
write!(f, "EdnView::Ok(state={state:?} view={view:?}"),
write!(f, "AtomView::Ok(state={state:?} view={view:?}"),
Self::Err(error) =>
write!(f, "EdnView::Err({error})"),
write!(f, "AtomView::Err({error})"),
_ => unreachable!()
}
}
@ -71,40 +72,29 @@ impl<'a, E: Output, T> ViewContext<'a, E> for T where T:
Context<'a, E::Unit> +
Context<'a, Box<dyn Render<E> + 'a>>
{}
impl<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> EdnView<'a, E, T> {
impl<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> AtomView<'a, E, T> {
pub fn from_source (state: T, source: &'a str) -> Self {
match Atom::read_one(&source) {
Ok((layout, _)) => Self::Ok(state, layout),
Err(error) => Self::Err(format!("{error} in {source}"))
}
}
pub fn from_items (state: T, items: Vec<impl Atom>) -> Self {
Self::Ok(state, Atom::Exp(items).to_arc())
pub fn from_atoms (state: T, atoms: Vec<impl Atom>) -> Self {
Self::Ok(state, Atom::Exp(atoms).to_arc())
}
}
impl<E: Output, T: for<'a>ViewContext<'a, E> + Send + Sync + std::fmt::Debug> Content<E> for EdnView<'_, E, T> {
impl<E: Output, T: for<'a>ViewContext<'a, E> + Send + Sync + std::fmt::Debug> Content<E> for AtomView<'_, E, T> {
fn content (&self) -> impl Render<E> {
match self {
Self::Ok(state, layout) => state.get_content(layout),
Self::Err(_error) => {
panic!("{self:?}");
//TODO:&format!("EdnView error: {error:?}")) // FIXME: String is not Render
//TODO:&format!("AtomView error: {error:?}")) // FIXME: String is not Render
},
_ => todo!()
}
}
}
macro_rules! edn_try_delegate {
($s:ident, $e:expr, $T:ty) => {
if let [head, tail @ ..] = $e.as_slice() {
if let Some(content) = <$T>::try_from_edn($s, head, tail) {
return Some(content.boxed())
}
}
}
}
/// Provides values to the template
pub trait ViewContext<'a, E: Output>:
Context<'a, bool> +
@ -112,52 +102,53 @@ pub trait ViewContext<'a, E: Output>:
Context<'a, E::Unit> +
Context<'a, Box<dyn Render<E> + 'a>>
{
fn get_bool (&'a self, item: &'a impl Atom) -> Option<bool> {
Some(match &item {
Sym(s) => match s.as_ref() {
fn get_bool (&'a self, atom: &'a impl Atom) -> Option<bool> {
Some(match atom.kind() {
Sym => match atom.text().as_ref() {
":false" | ":f" => false,
":true" | ":t" => true,
_ => return Context::get(self, item)
_ => return Context::get(self, atom)
},
Num(0) => false,
Num(_) => true,
_ => return Context::get(self, item)
Num => match atom.num() {
0 => false,
_ => true
},
_ => return Context::get(self, atom)
})
}
fn get_usize (&'a self, item: &'a impl Atom) -> Option<usize> {
Some(match &item { Num(n) => *n, _ => return Context::get(self, item) })
}
fn get_unit (&'a self, item: &'a impl Atom) -> Option<E::Unit> {
Some(match &item { Num(n) => (*n as u16).into(), _ => return Context::get(self, item) })
}
fn get_content (&'a self, item: &'a impl Atom) -> Option<Box<dyn Render<E> + 'a>> where E: 'a {
Some(match item {
Nil => Box::new(()),
Exp(ref e) => {
edn_try_delegate!(self, e, When::<_, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Either::<_, RenderBox<'a, E>, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Align::<_, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Bsp::<_, RenderBox<'a, E>, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Fill::<_, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Fixed::<_, _, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Min::<_, _, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Max::<_, _, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Shrink::<_, _, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Expand::<_, _, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Push::<_, _, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Pull::<_, _, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Margin::<_, _, RenderBox<'a, E>>);
edn_try_delegate!(self, e, Padding::<_, _, RenderBox<'a, E>>);
Context::get_or_fail(self, &item)
},
_ => Context::get_or_fail(self, &item)
fn get_usize (&'a self, atom: &'a impl Atom) -> Option<usize> {
Some(match atom.kind() {
Num => atom.num(),
_ => return Context::get(self, atom)
})
//panic!("no content")
}
fn get_unit (&'a self, atom: &'a impl Atom) -> Option<E::Unit> {
Some(match atom.kind() {
Num => E::Unit::from(atom.num() as u16),
_ => return Context::get(self, atom)
})
}
fn get_content (&'a self, atom: &'a impl Atom) -> Option<Box<dyn Render<E> + 'a>> where E: 'a {
try_delegate!(self, atom, When::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Either::<_, RenderBox<'a, E>, RenderBox<'a, E>>);
try_delegate!(self, atom, Align::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Bsp::<_, RenderBox<'a, E>, RenderBox<'a, E>>);
try_delegate!(self, atom, Fill::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Fixed::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Min::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Max::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Shrink::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Expand::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Push::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Pull::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Margin::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Padding::<_, _, RenderBox<'a, E>>);
Context::get_or_fail(self, atom)
}
}
// A function that returns a `RenderBox.
pub type EdnCallback<'a, O, State> =
pub type AtomCallback<'a, O, State> =
dyn Fn(&'a State)-> RenderBox<'a, O> + Send + Sync + 'a;
// A box containing a function that returns a `RenderBox.
pub type EdnRenderCallback<'a, O, State> =
Box<EdnCallback<'a, O, State>>;
pub type AtomRenderCallback<'a, O, State> =
Box<AtomCallback<'a, O, State>>;

View file

@ -257,15 +257,15 @@ fn draw_header (state: &Plugin, to: &mut TuiOut, x: u16, y: u16, w: u16) {
//}
//});
from_edn!("plugin/lv2" => |jack: &Arc<RwLock<JackConnection>>, args| -> Plugin {
from_atom!("plugin/lv2" => |jack: &Arc<RwLock<JackConnection>>, args| -> Plugin {
let mut name = String::new();
let mut path = String::new();
edn!(edn in args {
Edn::Map(map) => {
if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) {
atom!(atom in args {
Atom::Map(map) => {
if let Some(Atom::Str(n)) = map.get(&Atom::Key(":name")) {
name = String::from(*n);
}
if let Some(Edn::Str(p)) = map.get(&Edn::Key(":path")) {
if let Some(Atom::Str(p)) = map.get(&Atom::Key(":path")) {
path = String::from(*p);
}
},

View file

@ -349,22 +349,22 @@ impl Sampler {
}
///////////////////////////////////////////////////////////////////////////////////////////////////
type MidiSample = (Option<u7>, Arc<RwLock<crate::Sample>>);
from_edn!("sampler" => |jack: &Arc<RwLock<JackConnection>>, args| -> crate::Sampler {
from_atom!("sampler" => |jack: &Arc<RwLock<JackConnection>>, args| -> crate::Sampler {
let mut name = String::new();
let mut dir = String::new();
let mut samples = BTreeMap::new();
edn!(edn in args {
Edn::Map(map) => {
if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) {
atom!(atom in args {
Atom::Map(map) => {
if let Some(Atom::Str(n)) = map.get(&Atom::Key(":name")) {
name = String::from(*n);
}
if let Some(Edn::Str(n)) = map.get(&Edn::Key(":dir")) {
if let Some(Atom::Str(n)) = map.get(&Atom::Key(":dir")) {
dir = String::from(*n);
}
},
Edn::List(args) => match args.first() {
Some(Edn::Symbol("sample")) => {
let (midi, sample) = MidiSample::from_edn((jack, &dir), &args[1..])?;
Atom::List(args) => match args.first() {
Some(Atom::Symbol("sample")) => {
let (midi, sample) = MidiSample::from_atom((jack, &dir), &args[1..])?;
if let Some(midi) = midi {
samples.insert(midi, sample);
} else {
@ -373,27 +373,27 @@ from_edn!("sampler" => |jack: &Arc<RwLock<JackConnection>>, args| -> crate::Samp
},
_ => panic!("unexpected in sampler {name}: {args:?}")
},
_ => panic!("unexpected in sampler {name}: {edn:?}")
_ => panic!("unexpected in sampler {name}: {atom:?}")
});
Self::new(jack, &name)
});
from_edn!("sample" => |(_jack, dir): (&Arc<RwLock<JackConnection>>, &str), args| -> MidiSample {
from_atom!("sample" => |(_jack, dir): (&Arc<RwLock<JackConnection>>, &str), args| -> MidiSample {
let mut name = String::new();
let mut file = String::new();
let mut midi = None;
let mut start = 0usize;
edn!(edn in args {
Edn::Map(map) => {
if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) {
atom!(atom in args {
Atom::Map(map) => {
if let Some(Atom::Str(n)) = map.get(&Atom::Key(":name")) {
name = String::from(*n);
}
if let Some(Edn::Str(f)) = map.get(&Edn::Key(":file")) {
if let Some(Atom::Str(f)) = map.get(&Atom::Key(":file")) {
file = String::from(*f);
}
if let Some(Edn::Int(i)) = map.get(&Edn::Key(":start")) {
if let Some(Atom::Int(i)) = map.get(&Atom::Key(":start")) {
start = *i as usize;
}
if let Some(Edn::Int(m)) = map.get(&Edn::Key(":midi")) {
if let Some(Atom::Int(m)) = map.get(&Atom::Key(":midi")) {
midi = Some(u7::from(*m as u8));
}
},
@ -661,14 +661,14 @@ pub enum SamplerMode {
Select(usize),
Sample(SamplerCommand),
}
edn_command!(SamplerTuiCommand: |state: SamplerTui| {
atom_command!(SamplerTuiCommand: |state: SamplerTui| {
("select" [i: usize] Self::Select(i.expect("no index")))
("import" [a, ..b] if let Some(command) = FileBrowserCommand::from_edn(state, a, b) {
("import" [a, ..b] if let Some(command) = FileBrowserCommand::from_atom(state, a, b) {
Self::Import(command)
} else {
return None
})
("sample" [a, ..b] if let Some(command) = SamplerCommand::from_edn(&state.state, a, b) {
("sample" [a, ..b] if let Some(command) = SamplerCommand::from_atom(&state.state, a, b) {
Self::Sample(command)
} else {
return None
@ -677,7 +677,7 @@ edn_command!(SamplerTuiCommand: |state: SamplerTui| {
provide!(usize: |self: SamplerTui| {});
provide!(PathBuf: |self: SamplerTui| {});
provide!(Arc<str>: |self: SamplerTui| {});
edn_command!(FileBrowserCommand: |state: SamplerTui| {
atom_command!(FileBrowserCommand: |state: SamplerTui| {
("begin" [] Self::Begin)
("cancel" [] Self::Cancel)
("confirm" [] Self::Confirm)
@ -695,7 +695,7 @@ edn_command!(FileBrowserCommand: |state: SamplerTui| {
NoteOn(u7, u7),
NoteOff(u7),
}
edn_command!(SamplerCommand: |state: Sampler| {
atom_command!(SamplerCommand: |state: Sampler| {
("record/begin" [i: u7]
Self::RecordBegin(i.expect("no index")))
("record/cancel" []

View file

@ -119,7 +119,7 @@ impl TekCli {
/// Must not be dropped for the duration of the process
pub jack: Arc<RwLock<JackConnection>>,
/// View definition
pub edn: String,
pub atom: String,
/// Source of time
pub clock: Clock,
/// Theme
@ -168,7 +168,7 @@ provide_num!(usize: |self: Tek| {
":track" => self.selected.track().unwrap_or(0),
":track-next" => (self.selected.track().unwrap_or(0) + 1).min(self.tracks.len()),
":track-prev" => self.selected.track().unwrap_or(0).saturating_sub(1) });
view!(TuiOut: |self: Tek| self.size.of(EdnView::from_source(self, self.edn.as_ref())); {
view!(TuiOut: |self: Tek| self.size.of(AtomView::from_source(self, self.atom.as_ref())); {
bool {};
isize {};
Color {};
@ -206,7 +206,7 @@ impl Tek {
midi_froms: &[PortConnection], midi_tos: &[PortConnection],
) -> Usually<Self> {
let tek = Self {
edn: include_str!("./view_transport.edn").to_string(),
atom: include_str!("./view_transport.edn").to_string(),
jack: jack.clone(),
color: ItemPalette::random(),
clock: Clock::new(jack, bpm),
@ -226,7 +226,7 @@ impl Tek {
let clip = MidiClip::new("Clip", true, 384usize, None, Some(ItemColor::random().into()));
let clip = Arc::new(RwLock::new(clip));
Ok(Self {
edn: include_str!("./view_sequencer.edn").to_string(),
atom: include_str!("./view_sequencer.edn").to_string(),
pool: Some((&clip).into()),
editor: Some((&clip).into()),
editing: false.into(),
@ -242,7 +242,7 @@ impl Tek {
audio_froms: &[&[PortConnection];2], audio_tos: &[&[PortConnection];2],
) -> Usually<Self> {
let app = Self {
edn: include_str!("./view_groovebox.edn").to_string(),
atom: include_str!("./view_groovebox.edn").to_string(),
sampler: Some(Sampler::new(jack, &"sampler", midi_froms, audio_froms, audio_tos)?),
..Self::new_sequencer(jack, bpm, sync_lead, sync_follow, midi_froms, midi_tos)?
};
@ -259,7 +259,7 @@ impl Tek {
scenes: usize, tracks: usize, track_width: usize,
) -> Usually<Self> {
let mut arranger = Self {
edn: include_str!("./view_arranger.edn").to_string(),
atom: include_str!("./view_arranger.edn").to_string(),
..Self::new_groovebox(
jack, bpm, sync_lead, sync_follow,
midi_froms, midi_tos, audio_froms, audio_tos,
@ -628,7 +628,7 @@ handle!(TuiIn: |self: Tek, input|Ok({
Track(TrackCommand),
Zoom(Option<usize>),
}
edn_command!(TekCommand: |app: Tek| {
atom_command!(TekCommand: |app: Tek| {
("stop-all" [] Self::StopAll)
("undo" [d: usize] Self::History(-(d.unwrap_or(0)as isize)))
("redo" [d: usize] Self::History(d.unwrap_or(0) as isize))
@ -643,19 +643,19 @@ edn_command!(TekCommand: |app: Tek| {
(0, s) => Self::Select(Selection::Scene(s)),
(t, s) => Self::Select(Selection::Clip(t, s)),
})
("clip" [a, ..b] Self::Clip(ClipCommand::from_edn(app, &a.to_ref(), b)
("clip" [a, ..b] Self::Clip(ClipCommand::from_atom(app, &a.to_ref(), b)
.expect("invalid command")))
("clock" [a, ..b] Self::Clock(ClockCommand::from_edn(app.clock(), &a.to_ref(), b)
("clock" [a, ..b] Self::Clock(ClockCommand::from_atom(app.clock(), &a.to_ref(), b)
.expect("invalid command")))
("editor" [a, ..b] Self::Editor(MidiEditCommand::from_edn(app.editor.as_ref().expect("no editor"), &a.to_ref(), b)
("editor" [a, ..b] Self::Editor(MidiEditCommand::from_atom(app.editor.as_ref().expect("no editor"), &a.to_ref(), b)
.expect("invalid command")))
("pool" [a, ..b] Self::Pool(PoolCommand::from_edn(app.pool.as_ref().expect("no pool"), &a.to_ref(), b)
("pool" [a, ..b] Self::Pool(PoolCommand::from_atom(app.pool.as_ref().expect("no pool"), &a.to_ref(), b)
.expect("invalid command")))
("sampler" [a, ..b] Self::Sampler(SamplerCommand::from_edn(app.sampler.as_ref().expect("no sampler"), &a.to_ref(), b)
("sampler" [a, ..b] Self::Sampler(SamplerCommand::from_atom(app.sampler.as_ref().expect("no sampler"), &a.to_ref(), b)
.expect("invalid command")))
("scene" [a, ..b] Self::Scene(SceneCommand::from_edn(app, &a.to_ref(), b)
("scene" [a, ..b] Self::Scene(SceneCommand::from_atom(app, &a.to_ref(), b)
.expect("invalid command")))
("track" [a, ..b] Self::Track(TrackCommand::from_edn(app, &a.to_ref(), b)
("track" [a, ..b] Self::Track(TrackCommand::from_atom(app, &a.to_ref(), b)
.expect("invalid command")))
});
command!(|self: TekCommand, app: Tek|match self {
@ -852,7 +852,7 @@ impl Track {
SetZoom(usize),
SetColor(usize, ItemPalette),
}
edn_command!(TrackCommand: |app: Tek| {
atom_command!(TrackCommand: |app: Tek| {
("add" [] Self::Add)
("size" [a: usize] Self::SetSize(a.unwrap()))
("zoom" [a: usize] Self::SetZoom(a.unwrap()))
@ -1025,7 +1025,7 @@ impl Scene {
SetColor(usize, ItemPalette),
Enqueue(usize),
}
edn_command!(SceneCommand: |app: Tek| {
atom_command!(SceneCommand: |app: Tek| {
("add" [] Self::Add)
("del" [a: usize] Self::Del(0))
("zoom" [a: usize] Self::SetZoom(a.unwrap()))
@ -1129,7 +1129,7 @@ trait HasScenes: HasSelection + HasEditor + Send + Sync {
SetLoop(usize, usize, bool),
SetColor(usize, usize, ItemPalette),
}
edn_command!(ClipCommand: |app: Tek| {
atom_command!(ClipCommand: |app: Tek| {
("get" [a: usize ,b: usize]
Self::Get(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1)))
("put" [a: usize, b: usize, c: Option<Arc<RwLock<MidiClip>>>]

View file

@ -24,7 +24,7 @@ pub enum ClockCommand {
}
provide_num!(u32: |self: Clock| {});
provide!(f64: |self: Clock| {});
edn_command!(ClockCommand: |state: Clock| {
atom_command!(ClockCommand: |state: Clock| {
("play" [] Self::Play(None))
("play" [t: u32] Self::Play(t))
("pause" [] Self::Pause(None))

View file

@ -20,7 +20,7 @@ handle!(TuiIn: |self: Example, input|{
return Ok(None)
});
enum ExampleCommand { Next, Previous }
edn_command!(ExampleCommand: |app: Example| {
atom_command!(ExampleCommand: |app: Example| {
(":prev" [] Self::Previous)
(":next" [] Self::Next)
});
@ -51,7 +51,7 @@ view!(TuiOut: |self: Example|{
let code = Tui::bg(Color::Rgb(10,60,10),
Push::y(2, Align::n(format!("{}", EXAMPLES[self.0]))));
let content = Tui::bg(Color::Rgb(10,10,60),
EdnView::from_source(self, EXAMPLES[self.0]));
AtomView::from_source(self, EXAMPLES[self.0]));
self.1.of(Bsp::s(title, Bsp::n(""/*code*/, content)))
}; {
bool {};

View file

@ -46,16 +46,16 @@ impl TuiIn {
})
}
}
impl EdnInput for TuiIn {
fn matches_edn (&self, token: &str) -> bool {
impl AtomInput for TuiIn {
fn matches_atom (&self, token: &str) -> bool {
if let Some(event) = KeyMatcher::new(token).build() {
&event == self.event()
} else {
false
}
}
fn get_event (item: &EdnItem<impl AsRef<str>>) -> Option<Event> {
match item { EdnItem::Sym(s) => KeyMatcher::new(s).build(), _ => None }
fn get_event (item: &AtomItem<impl AsRef<str>>) -> Option<Event> {
match item { AtomItem::Sym(s) => KeyMatcher::new(s).build(), _ => None }
}
}
struct KeyMatcher {