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    keystrokes: SmallVec<[Keystroke; 2]>,
11    context_predicate: Option<KeymapContextPredicate>,
12}
13
14impl Binding {
15    pub fn new<A: Action>(keystrokes: &str, action: A, context: Option<&str>) -> Self {
16        Self::load(keystrokes, Box::new(action), context).unwrap()
17    }
18
19    pub fn load(keystrokes: &str, action: Box<dyn Action>, context: Option<&str>) -> Result<Self> {
20        let context = if let Some(context) = context {
21            Some(KeymapContextPredicate::parse(context)?)
22        } else {
23            None
24        };
25
26        let keystrokes = keystrokes
27            .split_whitespace()
28            .map(Keystroke::parse)
29            .collect::<Result<_>>()?;
30
31        Ok(Self {
32            keystrokes,
33            action,
34            context_predicate: context,
35        })
36    }
37
38    pub fn match_context(&self, contexts: &[KeymapContext]) -> bool {
39        self.context_predicate
40            .as_ref()
41            .map(|predicate| predicate.eval(contexts))
42            .unwrap_or(true)
43    }
44
45    pub fn match_keys_and_context(
46        &self,
47        pending_keystrokes: &Vec<Keystroke>,
48        contexts: &[KeymapContext],
49    ) -> BindingMatchResult {
50        if self.keystrokes.as_ref().starts_with(&pending_keystrokes) && self.match_context(contexts)
51        {
52            // If the binding is completed, push it onto the matches list
53            if self.keystrokes.as_ref().len() == pending_keystrokes.len() {
54                BindingMatchResult::Complete(self.action.boxed_clone())
55            } else {
56                BindingMatchResult::Partial
57            }
58        } else {
59            BindingMatchResult::Fail
60        }
61    }
62
63    pub fn keystrokes_for_action(
64        &self,
65        action: &dyn Action,
66        contexts: &[KeymapContext],
67    ) -> Option<SmallVec<[Keystroke; 2]>> {
68        if self.action.eq(action) && self.match_context(contexts) {
69            Some(self.keystrokes.clone())
70        } else {
71            None
72        }
73    }
74
75    pub fn keystrokes(&self) -> &[Keystroke] {
76        self.keystrokes.as_slice()
77    }
78
79    pub fn action(&self) -> &dyn Action {
80        self.action.as_ref()
81    }
82}
83
84pub enum BindingMatchResult {
85    Complete(Box<dyn Action>),
86    Partial,
87    Fail,
88}