mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
remove Atom. almost there
This commit is contained in:
parent
dc7b713108
commit
cf1fd5b45a
20 changed files with 539 additions and 739 deletions
|
|
@ -1,91 +1,38 @@
|
|||
use crate::*;
|
||||
pub trait KeyMap {
|
||||
/// Try to find a command that matches the currently pressed key
|
||||
fn command <S, C: AtomCommand<S>> (&self, state: &S, input: &impl AtomInput) -> Option<C>;
|
||||
/// [Input] state that can be matched against an [Atom].
|
||||
pub trait AtomInput: Input {
|
||||
fn matches_atom (&self, token: &str) -> bool;
|
||||
}
|
||||
//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 KeyMap for ArcKeyMap {
|
||||
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_atom(key) {
|
||||
let command = C::from_atom(state, command, args);
|
||||
if command.is_some() {
|
||||
return command
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => panic!("invalid config: {atom}")
|
||||
},
|
||||
_ => panic!("invalid config: {atom}")
|
||||
pub trait KeyMap {
|
||||
/// Try to find a command that matches the current input event.
|
||||
fn command <S, C: AtomCommand<S>, I: AtomInput> (&self, state: &S, input: &I) -> Option<C>;
|
||||
}
|
||||
impl KeyMap for TokenIter<'_> {
|
||||
fn command <S, C: AtomCommand<S>, I: AtomInput> (&self, state: &S, input: &I) -> Option<C> {
|
||||
for token in *self {
|
||||
if let Value::Exp(0, iter) = token.value() {
|
||||
if let Some((Token { value: Value::Sym(binding), .. }, _)) = iter.next() {
|
||||
if input.matches_atom(binding) {
|
||||
if let Some(command) = C::try_from_expr(state, iter.clone()) {
|
||||
return Some(command)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("invalid config: {token:?}")
|
||||
}
|
||||
_ => panic!("invalid config: {atom}")
|
||||
} else {
|
||||
panic!("invalid config: {token:?}")
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
/// [Input] state that can be matched against an [Atom].
|
||||
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 AtomCommand<C>: Command<C> {
|
||||
fn from_atom <'a> (
|
||||
state: &C,
|
||||
head: &impl Atom,
|
||||
tail: &'a [impl Atom]
|
||||
) -> Option<Self>;
|
||||
}
|
||||
/// A [Command] that can be constructed from a [Token].
|
||||
pub trait AtomCommand<C>: TryFromAtom<C> + Command<C> {}
|
||||
impl<C, T: TryFromAtom<C> + Command<C>> AtomCommand<C> for T {}
|
||||
/** Implement `AtomCommand` for given `State` and `Command` */
|
||||
#[macro_export] macro_rules! atom_command {
|
||||
($Command:ty : |$state:ident:<$T:ident: $Trait:path>| { $((
|
||||
($Command:ty : |$state:ident:<$State:ident: $Trait:path>| { $((
|
||||
// identifier
|
||||
$key:literal [
|
||||
// named parameters
|
||||
|
|
@ -106,22 +53,22 @@ pub trait AtomCommand<C>: Command<C> {
|
|||
// bound command:
|
||||
$command:expr
|
||||
))* }) => {
|
||||
impl<$T: $Trait> AtomCommand<$T> for $Command {
|
||||
fn from_atom <'a> (
|
||||
$state: &$T, head: &impl Atom, tail: &'a [impl Atom]
|
||||
) -> Option<Self> {
|
||||
$(if let (TokenKind::Key, $key, [ // if the identifier matches
|
||||
// bind argument ids
|
||||
$($arg),*
|
||||
// bind rest parameters
|
||||
$(, $rest @ ..)?
|
||||
]) = (head.kind(), head.text(), tail) {
|
||||
$(
|
||||
$(let $arg: Option<$type> = Context::<$type>::get($state, $arg);)?
|
||||
)*
|
||||
//$(atom_command!(@bind $state => $arg $(?)? : $type);)*
|
||||
return Some($command)
|
||||
})*
|
||||
impl<$State: $Trait> TryFromAtom<$State> for $Command {
|
||||
fn try_from_expr ($state: &$State, iter: TokenIter) -> Option<Self> {
|
||||
match $iter.next() {
|
||||
$(Some((Token { value: Value::Key($key), .. }, _)) => {
|
||||
let iter = iter.clone();
|
||||
$(
|
||||
let next = iter.next();
|
||||
if next.is_none() { panic!("no argument: {}", stringify!($arg)); }
|
||||
let ($arg, _) = next.unwrap();
|
||||
$(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)?
|
||||
)*
|
||||
$(let $rest = iter.clone();)?
|
||||
return Some($command)
|
||||
},)*
|
||||
_ => None
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -147,25 +94,22 @@ pub trait AtomCommand<C>: Command<C> {
|
|||
// bound command:
|
||||
$command:expr
|
||||
))* }) => {
|
||||
impl AtomCommand<$State> for $Command {
|
||||
fn from_atom <'a> (
|
||||
$state: &$State,
|
||||
head: &impl Atom,
|
||||
tail: &'a [impl Atom],
|
||||
) -> Option<Self> {
|
||||
$(if let (TokenKind::Key, $key, [ // if the identifier matches
|
||||
// bind argument ids
|
||||
$($arg),*
|
||||
// bind rest parameters
|
||||
$(, $rest @ ..)?
|
||||
]) = (head.kind(), head.text(), tail) {
|
||||
$(
|
||||
$(let $arg: Option<$type> = Context::<$type>::get($state, $arg);)?
|
||||
)*
|
||||
//$(atom_command!(@bind $state => $arg $(?)? : $type);)*
|
||||
return Some($command)
|
||||
})*
|
||||
None
|
||||
impl TryFromAtom<$State> for $Command {
|
||||
fn try_from_expr ($state: &$State, iter: TokenIter) -> Option<Self> {
|
||||
match iter.next() {
|
||||
$(Some((Token { value: Value::Key($key), .. }, _)) => {
|
||||
let iter = iter.clone();
|
||||
$(
|
||||
let next = iter.next();
|
||||
if next.is_none() { panic!("no argument: {}", stringify!($arg)); }
|
||||
let ($arg, _) = next.unwrap();
|
||||
$(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)?
|
||||
)*
|
||||
$(let $rest = iter.clone();)?
|
||||
return Some($command)
|
||||
}),*
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -176,6 +120,71 @@ pub trait AtomCommand<C>: Command<C> {
|
|||
let $arg: $type = Context::<$type>::get_or_fail($state, $arg);
|
||||
};
|
||||
}
|
||||
//pub struct SourceKeyMap<'a>(&'a str);
|
||||
//impl<'a> KeyMap for SourceKeyMap<'a> {
|
||||
//fn command <S, C: AtomCommand<S>> (&self, state: &S, input: &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: &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: &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 KeyMap for ArcKeyMap {
|
||||
//fn command <S, C: AtomCommand<S>> (&self, state: &S, input: &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_atom(key) {
|
||||
//let command = C::from_atom(state, command, args);
|
||||
//if command.is_some() {
|
||||
//return command
|
||||
//}
|
||||
//}
|
||||
//},
|
||||
//_ => panic!("invalid config: {atom}")
|
||||
//},
|
||||
//_ => panic!("invalid config: {atom}")
|
||||
//}
|
||||
//_ => panic!("invalid config: {atom}")
|
||||
//}
|
||||
//}
|
||||
//None
|
||||
//}
|
||||
//}
|
||||
#[cfg(test)] #[test] fn test_atom_keymap () -> Usually<()> {
|
||||
let keymap = KeyMap::new("")?;
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue