binding.rs

 1use crate::{Action, KeyBindingContextPredicate, KeyContext, KeyMatch, Keystroke};
 2use anyhow::Result;
 3use smallvec::SmallVec;
 4
 5pub struct KeyBinding {
 6    pub(crate) action: Box<dyn Action>,
 7    pub(crate) keystrokes: SmallVec<[Keystroke; 2]>,
 8    pub(crate) context_predicate: Option<KeyBindingContextPredicate>,
 9}
10
11impl Clone for KeyBinding {
12    fn clone(&self) -> Self {
13        KeyBinding {
14            action: self.action.boxed_clone(),
15            keystrokes: self.keystrokes.clone(),
16            context_predicate: self.context_predicate.clone(),
17        }
18    }
19}
20
21impl KeyBinding {
22    pub fn new<A: Action>(keystrokes: &str, action: A, context_predicate: Option<&str>) -> Self {
23        Self::load(keystrokes, Box::new(action), context_predicate).unwrap()
24    }
25
26    pub fn load(keystrokes: &str, action: Box<dyn Action>, context: Option<&str>) -> Result<Self> {
27        let context = if let Some(context) = context {
28            Some(KeyBindingContextPredicate::parse(context)?)
29        } else {
30            None
31        };
32
33        let keystrokes = keystrokes
34            .split_whitespace()
35            .map(Keystroke::parse)
36            .collect::<Result<_>>()?;
37
38        Ok(Self {
39            keystrokes,
40            action,
41            context_predicate: context,
42        })
43    }
44
45    pub fn matches_context(&self, contexts: &[KeyContext]) -> bool {
46        self.context_predicate
47            .as_ref()
48            .map(|predicate| predicate.eval(contexts))
49            .unwrap_or(true)
50    }
51
52    pub fn match_keystrokes(
53        &self,
54        pending_keystrokes: &[Keystroke],
55        contexts: &[KeyContext],
56    ) -> KeyMatch {
57        if self.keystrokes.as_ref().starts_with(&pending_keystrokes)
58            && self.matches_context(contexts)
59        {
60            // If the binding is completed, push it onto the matches list
61            if self.keystrokes.as_ref().len() == pending_keystrokes.len() {
62                KeyMatch::Some(self.action.boxed_clone())
63            } else {
64                KeyMatch::Pending
65            }
66        } else {
67            KeyMatch::None
68        }
69    }
70
71    pub fn keystrokes_for_action(
72        &self,
73        action: &dyn Action,
74        contexts: &[KeyContext],
75    ) -> Option<SmallVec<[Keystroke; 2]>> {
76        if self.action.partial_eq(action) && self.matches_context(contexts) {
77            Some(self.keystrokes.clone())
78        } else {
79            None
80        }
81    }
82
83    pub fn keystrokes(&self) -> &[Keystroke] {
84        self.keystrokes.as_slice()
85    }
86
87    pub fn action(&self) -> &dyn Action {
88        self.action.as_ref()
89    }
90}