1use crate::{KeyBinding, KeyContext, Keymap, KeymapVersion, Keystroke};
2use smallvec::SmallVec;
3use std::{cell::RefCell, rc::Rc};
4
5pub(crate) struct KeystrokeMatcher {
6 pending_keystrokes: Vec<Keystroke>,
7 keymap: Rc<RefCell<Keymap>>,
8 keymap_version: KeymapVersion,
9}
10
11pub struct KeymatchResult {
12 pub bindings: SmallVec<[KeyBinding; 1]>,
13 pub pending: bool,
14}
15
16impl KeystrokeMatcher {
17 pub fn new(keymap: Rc<RefCell<Keymap>>) -> Self {
18 let keymap_version = keymap.borrow().version();
19 Self {
20 pending_keystrokes: Vec::new(),
21 keymap_version,
22 keymap,
23 }
24 }
25
26 pub fn has_pending_keystrokes(&self) -> bool {
27 !self.pending_keystrokes.is_empty()
28 }
29
30 /// Pushes a keystroke onto the matcher.
31 /// The result of the new keystroke is returned:
32 /// - KeyMatch::None =>
33 /// No match is valid for this key given any pending keystrokes.
34 /// - KeyMatch::Pending =>
35 /// There exist bindings which are still waiting for more keys.
36 /// - KeyMatch::Complete(matches) =>
37 /// One or more bindings have received the necessary key presses.
38 /// Bindings added later will take precedence over earlier bindings.
39 pub(crate) fn match_keystroke(
40 &mut self,
41 keystroke: &Keystroke,
42 context_stack: &[KeyContext],
43 ) -> KeymatchResult {
44 let keymap = self.keymap.borrow();
45
46 // Clear pending keystrokes if the keymap has changed since the last matched keystroke.
47 if keymap.version() != self.keymap_version {
48 self.keymap_version = keymap.version();
49 self.pending_keystrokes.clear();
50 }
51
52 let mut pending_key = None;
53 let mut bindings = SmallVec::new();
54
55 for binding in keymap.bindings().rev() {
56 if !keymap.binding_enabled(binding, context_stack) {
57 continue;
58 }
59
60 for candidate in keystroke.match_candidates() {
61 self.pending_keystrokes.push(candidate.clone());
62 match binding.match_keystrokes(&self.pending_keystrokes) {
63 KeyMatch::Matched => {
64 bindings.push(binding.clone());
65 }
66 KeyMatch::Pending => {
67 pending_key.get_or_insert(candidate);
68 }
69 KeyMatch::None => {}
70 }
71 self.pending_keystrokes.pop();
72 }
73 }
74
75 if bindings.is_empty() && pending_key.is_none() && !self.pending_keystrokes.is_empty() {
76 drop(keymap);
77 self.pending_keystrokes.remove(0);
78 return self.match_keystroke(keystroke, context_stack);
79 }
80
81 let pending = if let Some(pending_key) = pending_key {
82 self.pending_keystrokes.push(pending_key);
83 true
84 } else {
85 self.pending_keystrokes.clear();
86 false
87 };
88
89 KeymatchResult { bindings, pending }
90 }
91}
92
93/// The result of matching a keystroke against a given keybinding.
94/// - KeyMatch::None => No match is valid for this key given any pending keystrokes.
95/// - KeyMatch::Pending => There exist bindings that is still waiting for more keys.
96/// - KeyMatch::Some(matches) => One or more bindings have received the necessary key presses.
97#[derive(Debug, PartialEq)]
98pub enum KeyMatch {
99 None,
100 Pending,
101 Matched,
102}