mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
fixed up some parsing and removed some edn mentions
This commit is contained in:
parent
5e7b867aba
commit
452bdf9598
15 changed files with 290 additions and 292 deletions
163
edn/src/token.rs
163
edn/src/token.rs
|
|
@ -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>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
}
|
||||
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
|
||||
//}
|
||||
//}
|
||||
//},
|
||||
//_ => panic!("invalid config: {item}")
|
||||
//},
|
||||
//_ => panic!("invalid config: {item}")
|
||||
//}
|
||||
//_ => panic!("invalid config: {item}")
|
||||
//}
|
||||
//}
|
||||
None
|
||||
}
|
||||
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: AtomCommand<S>> (&self, state: &S, input: &impl AtomInput) -> Option<C> {
|
||||
//todo!();
|
||||
//None
|
||||
//}
|
||||
//}
|
||||
//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
|
||||
//}
|
||||
//}
|
||||
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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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>>;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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" []
|
||||
|
|
|
|||
|
|
@ -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>>>]
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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 {};
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue