use crate::*; /// Collection of UI modes. /// /// ``` /// # use tek::*; /// /// // Empty mode registry: /// let state: Config = Default::default(); /// assert_eq!(state.modes_count(), 0); /// assert!(state.modes_get("Foo").is_none()); /// /// // Add a mode: /// let _ = state.modes_add(&"Foo (name Foo) (info Bar)").unwrap(); /// assert_eq!(state.modes_count(), 1); /// assert!(state.modes_get("Foo").is_some()); /// ``` pub trait HasModes { fn modes (&self) -> &RwLock, Arc>>; /// Register a mode. /// /// ``` /// # use ::{std::sync::Arc, tek::*}; /// let config = Config::default(); /// config.modes_add(stringify!(Menu /// (name Menu) (info Mode selector.) (axis Y Index) (bind Confirm) /// (view (bg (g 30) (bar/s 7 Logo (full/xy Dialog)))) /// )).unwrap(); /// let _: Arc = config.modes_get("Menu").unwrap(); /// ``` fn modes_add <'a> (&self, expr: impl Language) -> UsuallyRef<'a, ()> { let name = expr.head()?.ok_or("mode: missing name")?; let body = expr.tail()?.ok_or("mode: missing body")?; let mut mode = Mode::default(); body.each(&mut mode, |c, s|c.add(s))?; self.modes().write().insert(name.into(), Arc::new(mode)); Ok(()) } /// Get a mode by name. fn modes_get (&self, name: impl AsRef) -> Option> { self.modes().read().get(name.as_ref()).cloned() } /// Run something for each mode. fn modes_for_each (&self, mut ator: impl FnMut(&str, &Mode)->T) { for (k, v) in self.modes().read().iter() { let _ = ator(k.as_ref(), v.as_ref()); } } /// Count modes. fn modes_count (&self) -> usize { self.modes().read().len() } /// Clear modes. fn modes_clear (&self) { *self.modes().write() = Default::default(); } } impl HasModes for App { fn modes (&self) -> &RwLock, Arc>> { &self.watch.config.modes } } impl HasModes for Config { fn modes (&self) -> &RwLock, Arc>> { &self.modes } } impl HasModes for Mode { fn modes (&self) -> &RwLock, Arc>> { &self.modes } } impl_as_mut!(Mode: |self: Mode| self); /// Group of view and keys definitions. /// /// ``` /// let mode = tek::Mode::default(); /// ``` #[derive(Default, Debug)] pub struct Mode { pub path: PathBuf, pub name: Vec>, pub info: Vec>, pub view: Vec>>, pub keys: Vec>, pub axis: BTreeMap, Arc>, pub data: BTreeMap, usize>, pub modes: Arc, Arc>>>, } impl Mode { /// Add a definition to the mode. /// /// Supported definitions: /// /// - (name ...) -> name /// - (info ...) -> description /// - (keys ...) -> key bindings /// - (mode ...) -> submode /// - ... -> view /// /// ``` /// let mut mode = tek::Mode::default().add("(name hello)").unwrap(); /// ``` pub fn add (&mut self, dsl: impl Language) -> Usually<&mut Self> { Ok(if let Ok(Some(expr)) = dsl.expr() && let Ok(Some(head)) = expr.head() { let tail = expr.tail()?.map(|x|x.trim()).unwrap_or(""); match head { "self" => self.add_mode(tail)?, "bind" => self.add_bind(tail)?, "axis" => self.add_axis(tail)?, "data" => self.add_data(tail)?, "name" => { self.name.push(tail.into()); self }, "info" => { self.info.push(tail.into()); self }, "view" => { self.view.push(View::new(tail)?.into()); self }, _ => { self.view.push(View::new(tail)?.into()); self }, } } else if let Ok(Some(word)) = dsl.word() { self.view.push(View::new(word)?.into()); self } else { return Err(format!("Mode::add: unexpected: {dsl:?}").into()); }) } fn add_mode (&mut self, tail: &str) -> Usually<&mut Self> { let name = tail.head()?.ok_or("submode: missing name")?; let body = tail.tail()?.ok_or("submode: missing body")?; let mut submode = Mode::default(); body.each(&mut submode, |c, s|c.add(s))?; self.modes.write().insert(name.into(), Arc::new(submode)); Ok(self) } fn add_bind (&mut self, tail: &str) -> Usually<&mut Self> { tail.each(self, |mode: &mut Self, expr: &str|{ mode.keys.push(expr.trim().into()); Ok(mode) }) } fn add_axis (&mut self, tail: &str) -> Usually<&mut Self> { let mut axis: Option> = None; let mut param: Option> = None; tail.each(0, |index: usize, src: &str|if index == 0 { axis = Some(src.into()); Ok(1) } else if index == 1 { param = Some(src.into()); Ok(2) } else { err!("mode: expected (axis Name Param), got: {tail}") })?; if let Some(axis) = axis && let Some(param) = param { self.axis.insert(axis.into(), param.into()); Ok(self) } else { err!("mode: expected (axis Name Param), got: {tail}") } } fn add_data (&mut self, tail: &str) -> Usually<&mut Self> { let mut param: Option> = None; let mut value: Option = None; tail.each(0, |index: usize, src: &str|if index == 0 { param = Some(src.into()); Ok(1) } else if index == 1 { value = Some(src.parse::()?); Ok(2) } else { err!("mode: expected (data Param Value), got: {tail}") })?; if let Some(param) = param && let Some(value) = value { self.data.insert(param.into(), value.into()); Ok(self) } else { err!("mode: expected (data Param Value), got: {tail}") } } } pub fn print_config_modes (config: &Config) { use ::ansi_term::Color::*; config.modes_for_each(|k, v|{ println!(); for v in v.name.iter() { print!("{}", Green.bold().paint(format!("{v} "))); } for v in v.info.iter() { print!("\n{}", Green.paint(format!("{v}"))); } print!("\n{} {}", Blue.paint("TOOL"), Green.bold().paint(format!("{k:<16}"))); print!("\n{}", Blue.paint("KEYS")); for v in v.keys.iter() { print!("{}", Green.paint(format!(" {v}"))); } println!(); v.modes_for_each(|k, v|{ print!("{} {} {:?}", Blue.paint("MODE"), Green.bold().paint(format!("{k:<16}")), v.name); print!( " INFO={:?}", v.info); print!( " VIEW={:?}", v.view); println!(" KEYS={:?}", v.keys); }); print!("{}", Blue.paint("VIEW")); for v in v.view.iter() { print!("{}", Green.paint(format!(" {v}"))); } println!(); }); }