use crate::*; /// A control axis. /// /// ``` /// let axis = tek::ControlAxis::X; /// ``` #[derive(Debug, Copy, Clone)] pub enum ControlAxis { X, Y, Z, I } /// Collection of input bindings. pub type Binds = Arc, Bind>>>>; pub(crate) fn load_bind (binds: &Binds, name: &impl AsRef, body: &impl Language) -> Usually<()> { binds.write().unwrap().insert(name.as_ref().into(), Bind::load(body)?); Ok(()) } /// An map of input events (e.g. [TuiEvent]) to [Binding]s. /// /// ``` /// let lang = "(@x (nop)) (@y (nop) (nop))"; /// let bind = tek::Bind::>::load(&lang).unwrap(); /// assert_eq!(bind.query(&'x'.into()).map(|x|x.len()), Some(1)); /// //assert_eq!(bind.query(&'y'.into()).map(|x|x.len()), Some(2)); /// ``` #[derive(Debug)] pub struct Bind( /// Map of each event (e.g. key combination) to /// all command expressions bound to it by /// all loaded input layers. pub BTreeMap>> ); /// A sequence of zero or more commands (e.g. [AppCommand]), /// optionally filtered by [Condition] to form layers. /// /// ``` /// //FIXME: Why does it overflow? /// //let binding: Binding<()> = tek::Binding { ..Default::default() }; /// ``` #[derive(Debug, Clone)] pub struct Binding { pub commands: Arc<[C]>, pub condition: Option, pub description: Option>, pub source: Option>, } /// Condition that must evaluate to true in order to enable an input layer. /// /// ``` /// let condition = tek::Condition(std::sync::Arc::new(Box::new(||{true}))); /// ``` #[derive(Clone)] pub struct Condition( pub Arcbool + Send + Sync>> ); impl Bind> { pub fn load (lang: &impl Language) -> Usually { let mut map = Bind::new(); lang.each(|item|if item.expr().head() == Ok(Some("see")) { // TODO Ok(()) } else if let Ok(Some(_word)) = item.expr().head().word() { if let Some(key) = TuiEvent::from_dsl(item.expr()?.head()?)? { map.add(key, Binding { commands: [item.expr()?.tail()?.unwrap_or_default().into()].into(), condition: None, description: None, source: None }); Ok(()) } else if Some(":char") == item.expr()?.head()? { // TODO return Ok(()) } else { return Err(format!("Config::load_bind: invalid key: {:?}", item.expr()?.head()?).into()) } } else { return Err(format!("Config::load_bind: unexpected: {item:?}").into()) })?; Ok(map) } } /// Default is always empty map regardless if `E` and `C` implement [Default]. impl Default for Bind { fn default () -> Self { Self(Default::default()) } } impl Default for Binding { fn default () -> Self { Self { commands: Default::default(), condition: Default::default(), description: Default::default(), source: Default::default(), } } } impl Bind { /// Create a new event map pub fn new () -> Self { Default::default() } /// Add a binding to an owned event map. pub fn def (mut self, event: E, binding: Binding) -> Self { self.add(event, binding); self } /// Add a binding to an event map. pub fn add (&mut self, event: E, binding: Binding) -> &mut Self { if !self.0.contains_key(&event) { self.0.insert(event.clone(), Default::default()); } self.0.get_mut(&event).unwrap().push(binding); self } /// Return the binding(s) that correspond to an event. pub fn query (&self, event: &E) -> Option<&[Binding]> { self.0.get(event).map(|x|x.as_slice()) } /// Return the first binding that corresponds to an event, considering conditions. pub fn dispatch (&self, event: &E) -> Option<&Binding> { self.query(event) .map(|bb|bb.iter().filter(|b|b.condition.as_ref().map(|c|(c.0)()).unwrap_or(true)).next()) .flatten() } } impl_debug!(Condition |self, w| { write!(w, "*") });