use crate::*; use std::marker::PhantomData; /// [Input] state that can be matched against a [Value]. pub trait DslInput: Input { fn matches_dsl (&self, token: &str) -> bool; } /// A pre-configured mapping of input events to commands. pub trait KeyMap + Command, I: DslInput> { /// Try to find a command that matches the current input event. fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps; } /// A [SourceIter] can be a [KeyMap]. impl<'source, S, C: Dsl + Command, I: DslInput> KeyMap for SourceIter<'source> { fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps { let mut iter = self.clone(); while let Some((token, rest)) = iter.next() { iter = rest; match token { Token { value: Value::Exp(0, exp_iter), .. } => { let mut exp_iter = exp_iter.clone(); match exp_iter.next() { Some(Token { value: Value::Sym(binding), .. }) => { if input.matches_dsl(binding) { if let Some(command) = Dsl::take_from(state, &mut exp_iter)? { return Ok(Some(command)) } } }, _ => panic!("invalid config (expected symbol)") } }, _ => panic!("invalid config (expected expression)") } } Ok(None) } } /// A [TokenIter] can be a [KeyMap]. impl<'source, S, C: Dsl + Command, I: DslInput> KeyMap for TokenIter<'source> { fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps { let mut iter = self.clone(); while let Some(next) = iter.next() { match next { Token { value: Value::Exp(0, exp_iter), .. } => { let mut e = exp_iter.clone(); match e.next() { Some(Token { value: Value::Sym(binding), .. }) => { if input.matches_dsl(binding) { if let Some(command) = C::take_from(state, &mut e)? { return Ok(Some(command)) } } }, _ => panic!("invalid config (expected symbol, got: {exp_iter:?})") } }, _ => panic!("invalid config (expected expression, got: {next:?})") } } Ok(None) } } pub type InputLayerCond = BoxUsually + Send + Sync>; /// A collection of pre-configured mappings of input events to commands, /// which may be made available subject to given conditions. pub struct InputMap where C: Dsl + Command, I: DslInput, M: KeyMap + Send + Sync { __: PhantomData<(S, C, I)>, pub layers: Vec<(InputLayerCond, M)>, } impl Default for InputMap where C: Dsl + Command, I: DslInput, M: KeyMap + Send + Sync { fn default () -> Self { Self { __: PhantomData, layers: vec![] } } } impl InputMap where C: Dsl + Command, I: DslInput, M: KeyMap + Send + Sync { pub fn new (keymap: M) -> Self { Self::default().layer(keymap) } pub fn layer (mut self, keymap: M) -> Self { self.add_layer(keymap); self } pub fn add_layer (&mut self, keymap: M) -> &mut Self { self.add_layer_if(Box::new(|_|Ok(true)), keymap); self } pub fn layer_if (mut self, condition: InputLayerCond, keymap: M) -> Self { self.add_layer_if(condition, keymap); self } pub fn add_layer_if (&mut self, condition: InputLayerCond, keymap: M) -> &mut Self { self.layers.push((Box::new(condition), keymap)); self } } impl std::fmt::Debug for InputMap where C: Dsl + Command, I: DslInput, M: KeyMap + Send + Sync { fn fmt (&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { write!(f, "[InputMap: {} layer(s)]", self.layers.len()) } } /// An [InputMap] can be a [KeyMap]. impl KeyMap for InputMap where C: Dsl + Command, I: DslInput, M: KeyMap + Send + Sync { fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps { for (condition, keymap) in self.layers.iter() { if !condition(state)? { continue } if let Some(command) = keymap.keybind_resolve(state, input)? { return Ok(Some(command)) } } Ok(None) } }