binding.rs

  1use anyhow::Result;
  2use smallvec::SmallVec;
  3
  4use crate::Action;
  5
  6use super::{KeymapContext, KeymapContextPredicate, Keystroke};
  7
  8pub struct Binding {
  9    action: Box<dyn Action>,
 10    pub(super) keystrokes: SmallVec<[Keystroke; 2]>,
 11    pub(super) context_predicate: Option<KeymapContextPredicate>,
 12}
 13
 14impl std::fmt::Debug for Binding {
 15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 16        write!(
 17            f,
 18            "Binding {{ keystrokes: {:?}, action: {}::{}, context_predicate: {:?} }}",
 19            self.keystrokes,
 20            self.action.namespace(),
 21            self.action.name(),
 22            self.context_predicate
 23        )
 24    }
 25}
 26
 27impl Clone for Binding {
 28    fn clone(&self) -> Self {
 29        Self {
 30            action: self.action.boxed_clone(),
 31            keystrokes: self.keystrokes.clone(),
 32            context_predicate: self.context_predicate.clone(),
 33        }
 34    }
 35}
 36
 37impl Binding {
 38    pub fn new<A: Action>(keystrokes: &str, action: A, context: Option<&str>) -> Self {
 39        Self::load(keystrokes, Box::new(action), context).unwrap()
 40    }
 41
 42    pub fn load(keystrokes: &str, action: Box<dyn Action>, context: Option<&str>) -> Result<Self> {
 43        let context = if let Some(context) = context {
 44            Some(KeymapContextPredicate::parse(context)?)
 45        } else {
 46            None
 47        };
 48
 49        let keystrokes = keystrokes
 50            .split_whitespace()
 51            .map(Keystroke::parse)
 52            .collect::<Result<_>>()?;
 53
 54        Ok(Self {
 55            keystrokes,
 56            action,
 57            context_predicate: context,
 58        })
 59    }
 60
 61    pub fn match_context(&self, contexts: &[KeymapContext]) -> bool {
 62        self.context_predicate
 63            .as_ref()
 64            .map(|predicate| predicate.eval(contexts))
 65            .unwrap_or(true)
 66    }
 67
 68    pub fn match_keys_and_context(
 69        &self,
 70        pending_keystrokes: &Vec<Keystroke>,
 71        contexts: &[KeymapContext],
 72    ) -> BindingMatchResult {
 73        if self.keystrokes.as_ref().starts_with(&pending_keystrokes) && self.match_context(contexts)
 74        {
 75            // If the binding is completed, push it onto the matches list
 76            if self.keystrokes.as_ref().len() == pending_keystrokes.len() {
 77                BindingMatchResult::Complete(self.action.boxed_clone())
 78            } else {
 79                BindingMatchResult::Partial
 80            }
 81        } else {
 82            BindingMatchResult::Fail
 83        }
 84    }
 85
 86    pub fn keystrokes_for_action(
 87        &self,
 88        action: &dyn Action,
 89        contexts: &[KeymapContext],
 90    ) -> Option<SmallVec<[Keystroke; 2]>> {
 91        if self.action.eq(action) && self.match_context(contexts) {
 92            Some(self.keystrokes.clone())
 93        } else {
 94            None
 95        }
 96    }
 97
 98    pub fn keystrokes(&self) -> &[Keystroke] {
 99        self.keystrokes.as_slice()
100    }
101
102    pub fn action(&self) -> &dyn Action {
103        self.action.as_ref()
104    }
105}
106
107pub enum BindingMatchResult {
108    Complete(Box<dyn Action>),
109    Partial,
110    Fail,
111}