From dc45edf7e08f2617eca61c47b7c6abffb3330fb8 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Tue, 14 Jan 2025 21:07:25 +0100 Subject: [PATCH] special case numeric literals, and away we go! --- edn/src/edn_provide.rs | 18 +++++++- input/src/edn_command.rs | 58 ------------------------ input/src/edn_input.rs | 95 ++++++++++++++++++++++++++++++++++++++++ input/src/edn_keymap.rs | 67 ---------------------------- input/src/lib.rs | 5 +-- tek/src/lib.rs | 2 +- tui/src/tui_border.rs | 2 +- 7 files changed, 114 insertions(+), 133 deletions(-) delete mode 100644 input/src/edn_command.rs delete mode 100644 input/src/edn_keymap.rs diff --git a/edn/src/edn_provide.rs b/edn/src/edn_provide.rs index ee52b042..87a85fb7 100644 --- a/edn/src/edn_provide.rs +++ b/edn/src/edn_provide.rs @@ -1,6 +1,15 @@ use crate::*; /// Implement `EdnProvide` for a type and context #[macro_export] macro_rules! edn_provide { + // Provide a value to the EDN template + ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { + impl<'a> EdnProvide<'a, $type> for $State { + fn get > (&'a $self, edn: &'a EdnItem) -> Option<$type> { + Some(match edn.to_ref() { $(EdnItem::Sym($pat) => $expr,)* _ => return None }) + } + } + }; + // Provide a value more generically ($lt:lifetime: $type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { impl<$lt> EdnProvide<$lt, $type> for $State { fn get > (&$lt $self, edn: &$lt EdnItem) -> Option<$type> { @@ -8,10 +17,15 @@ use crate::*; } } }; - ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { + // Provide a value that may also be a numeric literal in the EDN + (# $type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { impl<'a> EdnProvide<'a, $type> for $State { fn get > (&'a $self, edn: &'a EdnItem) -> Option<$type> { - Some(match edn.to_ref() { $(EdnItem::Sym($pat) => $expr,)* _ => return None }) + Some(match edn.to_ref() { + $(EdnItem::Sym($pat) => $expr,)* + EdnItem::Num(n) => n as $type, + _ => return None + }) } } }; diff --git a/input/src/edn_command.rs b/input/src/edn_command.rs deleted file mode 100644 index c6830d87..00000000 --- a/input/src/edn_command.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::*; -/// Turns an EDN item sequence into a command enum variant. -pub trait EdnCommand: Command { - fn from_edn <'a> (state: &C, head: &EdnItem<&str>, tail: &'a [EdnItem<&'a str>]) - -> Option; -} -/** Implement `EdnCommand` for given `State` and `Command` */ -#[macro_export] macro_rules! edn_command { - ($Command:ty : |$state:ident:$State:ty| { $(( - // identifier - $key:literal [ - // named parameters - $( - // argument name - $arg:ident - // if type is not provided defaults to EdnItem - $( - // type:name separator - : - // argument type - $type:ty - )? - ),* - // rest of parameters - $(, ..$rest:ident)? - ] - // bound command: - $command:expr - ))* }) => { - impl EdnCommand<$State> for $Command { - fn from_edn <'a> ( - $state: &$State, - head: &EdnItem<&str>, - tail: &'a [EdnItem<&'a str>] - ) -> Option { - $(if let (EdnItem::Key($key), [ // if the identifier matches - // bind argument ids - $($arg),* - // bind rest parameters - $(, $rest @ ..)? - ]) = (head, tail) { - $( - $(let $arg: Option<$type> = EdnProvide::<$type>::get($state, $arg);)? - )* - //$(edn_command!(@bind $state => $arg $(?)? : $type);)* - return Some($command) - })* - None - } - } - }; - (@bind $state:ident =>$arg:ident ? : $type:ty) => { - let $arg: Option<$type> = EdnProvide::<$type>::get($state, $arg); - }; - (@bind $state:ident => $arg:ident : $type:ty) => { - let $arg: $type = EdnProvide::<$type>::get_or_fail($state, $arg); - }; -} diff --git a/input/src/edn_input.rs b/input/src/edn_input.rs index be91ce30..a5284f0e 100644 --- a/input/src/edn_input.rs +++ b/input/src/edn_input.rs @@ -6,3 +6,98 @@ pub trait EdnInput: Input { None } } + +/// Turns an EDN item sequence into a command enum variant. +pub trait EdnCommand: Command { + fn from_edn <'a> (state: &C, head: &EdnItem<&str>, tail: &'a [EdnItem<&'a str>]) + -> Option; +} + +/** Implement `EdnCommand` for given `State` and `Command` */ +#[macro_export] macro_rules! edn_command { + ($Command:ty : |$state:ident:$State:ty| { $(( + // identifier + $key:literal [ + // named parameters + $( + // argument name + $arg:ident + // if type is not provided defaults to EdnItem + $( + // type:name separator + : + // argument type + $type:ty + )? + ),* + // rest of parameters + $(, ..$rest:ident)? + ] + // bound command: + $command:expr + ))* }) => { + impl EdnCommand<$State> for $Command { + fn from_edn <'a> ( + $state: &$State, + head: &EdnItem<&str>, + tail: &'a [EdnItem<&'a str>] + ) -> Option { + $(if let (EdnItem::Key($key), [ // if the identifier matches + // bind argument ids + $($arg),* + // bind rest parameters + $(, $rest @ ..)? + ]) = (head, tail) { + $( + $(let $arg: Option<$type> = EdnProvide::<$type>::get($state, $arg);)? + )* + //$(edn_command!(@bind $state => $arg $(?)? : $type);)* + return Some($command) + })* + None + } + } + }; + (@bind $state:ident =>$arg:ident ? : $type:ty) => { + let $arg: Option<$type> = EdnProvide::<$type>::get($state, $arg); + }; + (@bind $state:ident => $arg:ident : $type:ty) => { + let $arg: $type = EdnProvide::<$type>::get_or_fail($state, $arg); + }; +} + +pub struct EdnKeyMapToCommand<'a>(Vec>); +impl<'a> EdnKeyMapToCommand<'a> { + /// Construct keymap from source text or fail + pub fn new (keymap: &'a str) -> Usually { + Ok(Self(EdnItem::<&str>::read_all(keymap)?)) + } + /// Try to find a binding matching the currently pressed key + pub fn from (&self, state: &T, input: &impl EdnInput) -> Option + where + C: Command + EdnCommand + { + use EdnItem::*; + let mut command: Option = None; + for item in self.0.iter() { + if let Exp(e) = item { + match e.as_slice() { + [Sym(key), c, args @ ..] if input.matches_edn(key) => { + command = C::from_edn(state, c, args); + if command.is_some() { + break + } + }, + _ => {} + } + } else { + panic!("invalid config") + } + } + command + } +} + +#[cfg(test)] #[test] fn test_edn_keymap () { + let keymap = EdnKeymapToCommand::new("")?; +} diff --git a/input/src/edn_keymap.rs b/input/src/edn_keymap.rs deleted file mode 100644 index 877801b7..00000000 --- a/input/src/edn_keymap.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::*; -use EdnItem::*; - -pub struct EdnKeyMapToCommand<'a>(Vec>); -impl<'a> EdnKeyMapToCommand<'a> { - /// Construct keymap from source text or fail - pub fn new (keymap: &'a str) -> Usually { - Ok(Self(EdnItem::<&str>::read_all(keymap)?)) - } - /// Try to find a binding matching the currently pressed key - pub fn from (&self, state: &T, input: &impl EdnInput) -> Option - where - C: Command + EdnCommand - { - use EdnItem::*; - let mut command: Option = None; - for item in self.0.iter() { - if let Exp(e) = item { - match e.as_slice() { - [Sym(key), c, args @ ..] if input.matches_edn(key) => { - command = C::from_edn(state, c, args); - if command.is_some() { - break - } - }, - _ => {} - } - } else { - panic!("invalid config") - } - } - command - } -} - -pub struct EdnKeymap<'a>(pub Vec>); - -impl<'a> EdnKeymap<'a> { - pub fn command , E: EdnCommand, I: EdnInput> ( - &self, state: &C, input: &I - ) -> Option { - for item in self.0.iter() { - if let Exp(items) = item { - match items.as_slice() { - [Sym(a), b, c @ ..] => if input.matches_edn(a) { - return E::from_edn(state, &b.to_ref(), c) - }, - _ => unreachable!() - } - } else { - unreachable!() - } - } - None - } -} - -impl<'a> From<&'a str> for EdnKeymap<'a> { - fn from (source: &'a str) -> Self { - let items = EdnItem::<&'a str>::read_all(source.as_ref()); - Self(items.expect("failed to load keymap")) - } -} - -#[cfg(test)] #[test] fn test_edn_keymap () { - let keymap = EdnKeymap::from(""); -} diff --git a/input/src/lib.rs b/input/src/lib.rs index 45eb82fc..994f635d 100644 --- a/input/src/lib.rs +++ b/input/src/lib.rs @@ -4,10 +4,7 @@ mod input; pub use self::input::*; mod command; pub use self::command::*; mod event_map; pub use self::event_map::*; - -mod edn_command; pub use self::edn_command::*; -mod edn_input; pub use self::edn_input::*; -mod edn_keymap; pub use self::edn_keymap::*; +mod edn_input; pub use self::edn_input::*; pub(crate) use ::tek_edn::EdnItem; /// Standard error trait. diff --git a/tek/src/lib.rs b/tek/src/lib.rs index 558224a1..809a68f3 100644 --- a/tek/src/lib.rs +++ b/tek/src/lib.rs @@ -68,9 +68,9 @@ has_editor!(|self: App|{ editor_h = 15; is_editing = self.editing.load(Relaxed); }); +edn_provide!(# usize: |self: App| {}); edn_view!(TuiOut: |self: App| self.size.of(EdnView::from_source(self, self.edn.as_ref())); { bool {}; - usize {}; isize {}; Color {}; Selection {}; diff --git a/tui/src/tui_border.rs b/tui/src/tui_border.rs index daac6c1a..b3c60744 100644 --- a/tui/src/tui_border.rs +++ b/tui/src/tui_border.rs @@ -139,7 +139,7 @@ macro_rules! border { #[derive(Copy, Clone)] pub struct $T(pub Style); impl Content for $T { - fn render (&self, to: &mut TuiOut) { self.draw(to); } + fn render (&self, to: &mut TuiOut) { let _ = self.draw(to); } } )+} }