binding.rs

 1use crate::{Action, KeyBindingContextPredicate, Keystroke};
 2use anyhow::Result;
 3use smallvec::SmallVec;
 4
 5/// A keybinding and its associated metadata, from the keymap.
 6pub struct KeyBinding {
 7    pub(crate) action: Box<dyn Action>,
 8    pub(crate) keystrokes: SmallVec<[Keystroke; 2]>,
 9    pub(crate) context_predicate: Option<KeyBindingContextPredicate>,
10}
11
12impl Clone for KeyBinding {
13    fn clone(&self) -> Self {
14        KeyBinding {
15            action: self.action.boxed_clone(),
16            keystrokes: self.keystrokes.clone(),
17            context_predicate: self.context_predicate.clone(),
18        }
19    }
20}
21
22impl KeyBinding {
23    /// Construct a new keybinding from the given data.
24    pub fn new<A: Action>(keystrokes: &str, action: A, context_predicate: Option<&str>) -> Self {
25        Self::load(keystrokes, Box::new(action), context_predicate).unwrap()
26    }
27
28    /// Load a keybinding from the given raw data.
29    pub fn load(keystrokes: &str, action: Box<dyn Action>, context: Option<&str>) -> Result<Self> {
30        let context = if let Some(context) = context {
31            Some(KeyBindingContextPredicate::parse(context)?)
32        } else {
33            None
34        };
35
36        let keystrokes = keystrokes
37            .split_whitespace()
38            .map(Keystroke::parse)
39            .collect::<Result<_>>()?;
40
41        Ok(Self {
42            keystrokes,
43            action,
44            context_predicate: context,
45        })
46    }
47
48    /// Check if the given keystrokes match this binding.
49    pub fn match_keystrokes(&self, typed: &[Keystroke]) -> Option<bool> {
50        if self.keystrokes.len() < typed.len() {
51            return None;
52        }
53
54        for (target, typed) in self.keystrokes.iter().zip(typed.iter()) {
55            if !typed.should_match(target) {
56                return None;
57            }
58        }
59
60        Some(self.keystrokes.len() > typed.len())
61    }
62
63    /// Get the keystrokes associated with this binding
64    pub fn keystrokes(&self) -> &[Keystroke] {
65        self.keystrokes.as_slice()
66    }
67
68    /// Get the action associated with this binding
69    pub fn action(&self) -> &dyn Action {
70        self.action.as_ref()
71    }
72
73    /// Get the predicate used to match this binding
74    pub fn predicate(&self) -> Option<&KeyBindingContextPredicate> {
75        self.context_predicate.as_ref()
76    }
77}
78
79impl std::fmt::Debug for KeyBinding {
80    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81        f.debug_struct("KeyBinding")
82            .field("keystrokes", &self.keystrokes)
83            .field("context_predicate", &self.context_predicate)
84            .field("action", &self.action.name())
85            .finish()
86    }
87}