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..113ec3b4 100644 --- a/crates/app/src/model.rs +++ b/crates/app/src/model.rs @@ -1,5 +1,6 @@ use crate::*; use std::path::PathBuf; +use std::error::Error; #[derive(Default, Debug)] pub struct App { /// Must not be dropped for the duration of the process @@ -9,7 +10,7 @@ pub struct App { /// Performance counter pub perf: PerfModel, // View and input definition - pub config: Configuration, + pub config: Configuration, /// Contains all recently created clips. pub pool: Pool, /// Contains the currently edited musical arrangement @@ -319,7 +320,7 @@ impl App { /// Configuration #[derive(Default, Debug)] -pub struct Configuration { +pub struct Configuration { /// Path of configuration entrypoint pub path: PathBuf, /// Name of configuration @@ -327,99 +328,39 @@ pub struct Configuration { /// Description of configuration pub info: Option>, /// View definition - pub view: T, + pub view: Arc, // Input keymap - pub keys: EventMap, + pub keys: EventMap, } -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()) - }))?; - Ok(Self { - path: path.as_ref().into(), - info: info.map(Self::parse_info).flatten(), - name: name.map(Self::parse_name).flatten(), - view: Self::parse_view(view)?.into(), - keys: Self::parse_keys(&path, keys)?.into(), - }) - } - fn parse_name (dsl: T) -> Option> { - dsl.str().map(Into::into) - } - fn parse_info (dsl: T) -> Option> { - dsl.str().map(Into::into) - } - fn parse_view (dsl: Option) -> Usually { - match dsl { Some(view) => Ok(view), _ => Err(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()) +impl Configuration { + pub fn from_path (path: &impl AsRef, _watch: bool) -> Usually { + let mut config = Self::default(); + config.path = path.as_ref().into(); + let mut dsl = read_and_leak(path.as_ref())?; + while let Some(mut exp) = dsl.exp_next()? { + match exp.exp_head()?.key()? { + Some("name") => match exp.text()? { + Some(name) => config.name = Some(name.into()), + _ => return Err(format!("missing name definition").into()) + }, + Some("info") => match exp.text()? { + Some(info) => config.info = Some(info.into()), + _ => return Err(format!("missing info definition").into()) + }, + Some("keys") => match exp.text()? { + Some(keys) => config.keys = EventMap::from_dsl(keys)?, + _ => return Err(format!("missing keys definition").into()) + }, + Some("view") => match exp.exp_tail()? { + Some(tail) => config.view = tail.src().into(), + _ => return Err(format!("missing view definition").into()) + }, + Some(k) => return Err(format!("(e3) unexpected key {k:?} in {exp:?}").into()), + None => return Err(format!("(e2) unexpected exp {exp:?}").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()) } + Ok(config) } } diff --git a/deps/tengri b/deps/tengri index 7b67d29c..360b404b 160000 --- a/deps/tengri +++ b/deps/tengri @@ -1 +1 @@ -Subproject commit 7b67d29c012f2d39a5d9d2fcd840417c90256503 +Subproject commit 360b404b69abb1ec4e0e9959667e08d4b99c6131