diff --git a/crates/app/src/api.rs b/crates/app/src/api.rs index 1790ddc1..bb1d067c 100644 --- a/crates/app/src/api.rs +++ b/crates/app/src/api.rs @@ -7,10 +7,11 @@ macro_rules! cmd_todo { ($msg:literal) => {{ println!($msg); None }}; } handle!(TuiIn: |self: App, input|self.handle_tui_key_with_history(input)); impl App { fn handle_tui_key_with_history (&mut self, input: &TuiIn) -> Perhaps { - Ok(if let Some(command) = self.config.keys.handle(self, input)? { - // FIXME failed commands not persisted in undo history - let undo = command.clone().execute(self)?; - self.history.push((command, undo)); + Ok(if let Some(binding) = self.config.keys.dispatch(input.event()) { + let binding = binding.clone(); + let undo = binding.command.clone().execute(self)?; + // FIXME failed commands are not persisted in undo history + //self.history.push((binding.command.clone(), undo)); Some(true) } else { None diff --git a/crates/app/src/model.rs b/crates/app/src/model.rs index 40d9b508..f90145da 100644 --- a/crates/app/src/model.rs +++ b/crates/app/src/model.rs @@ -1,5 +1,7 @@ use crate::*; use std::path::PathBuf; +use std::error::Error; +use Val::*; #[derive(Default, Debug)] pub struct App { /// Must not be dropped for the duration of the process @@ -329,26 +331,28 @@ pub struct Configuration { /// View definition pub view: T, // Input keymap - pub keys: EventMap, + pub keys: EventMap, } -impl Configuration { +impl> Configuration { pub fn from_path (path: &impl AsRef, _watch: bool) -> Usually where T: for<'a> From<&'a str> { let mut dsl = T::from(read_and_leak(path.as_ref())?); - let mut name: Option = None; - let mut info: Option = None; - let mut view: Option = None; - let mut keys: Option = None; - dsl.exp_each(|form|Ok(match form.exp_head().dsl() { - Val::Key(key) => match key.as_ref() { - "name" => name = Some(form.exp_tail()), - "info" => info = Some(form.exp_tail()), - "keys" => keys = Some(form.exp_tail()), - "view" => view = Some(form.exp_tail()), - _ => return Err(format!("(e3) unexpected key {key:?} in {form:?}").into()) - }, - _ => return Err(format!("(e2) unexpected exp {form :?}").into()) - }))?; + let mut name: Option = None; + let mut info: Option = None; + let mut view: Option = None; + let mut keys: Option = None; + while let Some(form) = dsl.exp_next() { + match form.head().val() { + Key(key) => match key.as_ref() { + "name" => name = Some(form.tail().into()), + "info" => info = Some(form.tail().into()), + "keys" => keys = Some(form.tail().into()), + "view" => view = Some(form.tail().into()), + _ => return Err(format!("(e3) unexpected key {key:?} in {form:?}").into()) + }, + _ => return Err(format!("(e2) unexpected exp {form :?}").into()) + } + } Ok(Self { path: path.as_ref().into(), info: info.map(Self::parse_info).flatten(), @@ -358,68 +362,18 @@ impl Configuration { }) } fn parse_name (dsl: T) -> Option> { - dsl.str().map(Into::into) + dsl.str().map(|x|x.as_ref().into()) } fn parse_info (dsl: T) -> Option> { - dsl.str().map(Into::into) + dsl.str().map(|x|x.as_ref().into()) } fn parse_view (dsl: Option) -> Usually { - match dsl { Some(view) => Ok(view), _ => Err(format!("missing view definition").into()) } + dsl.ok_or_else(||format!("missing view definition").into()) } - fn parse_keys (base: &impl AsRef, dsl: Option) -> Usually> { - let mut map = EventMap::default(); - let mut keys = if let Some(keys) = dsl { keys } else { - return Err(format!("missing keys definition").into()) - }; - keys.exp_each(|form|Ok(match form.exp_head().dsl() { - Val::Sym(s) if s.as_ref() == "layer" => - Self::parse_keys_layer(&mut map, base, form.exp_tail()), - Val::Sym(s) if s.as_ref() == "layer-if" => - Self::parse_keys_layer_if(&mut map, base, form.exp_tail()), - x => - return Err(format!("(e3) unexpected {x:?} in {form:?}").into()) - }))?; - Ok(map) - } - fn parse_keys_layer (map: &mut EventMap, base: &impl AsRef, exp: &T) { - let next = exp.peek().map(|x|x.val()); - if let Some(Val::Str(path)) = next { - let path = base.as_ref().parent().unwrap().join(unquote(path)); - if !std::fs::exists(&path)? { - return Err(format!("(e5) not found: {path:?}").into()) - } - map.add_layer(read_and_leak(path)?.into()); - print!("layer:\n path: {:?}...", exp.0.0.trim()); - println!("ok"); - } else { - return Err(format!("(e4) unexpected non-string {next:?}").into()) - } - } - fn parse_keys_layer_if (map: &mut EventMap, base: &impl AsRef, exp: &T) { - let next = exp.next().map(|x|x.val()); - let cond = if let Some(Val::Sym(sym)) = next { - leak(sym) - } else { - return Err(format!("(e4) unexpected non-symbol {next:?}").into()) - }; - - let next = exp.peek().map(|x|x.val()); - if let Some(Val::Str(path)) = next { - let path = base.as_ref().parent().unwrap().join(unquote(path)); - if !std::fs::exists(&path)? { - return Err(format!("(e5) not found: {path:?}").into()) - } - print!("layer-if:\n cond: {cond}\n path: {path:?}..."); - let keys = read_and_leak(path)?.into(); - println!("ok"); - //map.add_layer_if( - //Box::new(move |state: &App|Take::take_or_fail( - //state, exp, ||"missing input layer conditional" - //)), keys - //); - } else { - return Err(format!("(e4) unexpected non-symbol {next:?}").into()) - } + fn parse_keys (base: &impl AsRef, dsl: Option) -> Usually> { + EventMap::from_dsl(dsl.ok_or_else(||->Box{ + format!("missing keys definition").into() + })?) } } diff --git a/deps/tengri b/deps/tengri index 7b67d29c..d72a3b5b 160000 --- a/deps/tengri +++ b/deps/tengri @@ -1 +1 @@ -Subproject commit 7b67d29c012f2d39a5d9d2fcd840417c90256503 +Subproject commit d72a3b5b8f3f98573a194b45961b6dd5cc8f8e5f