1use crate::{KeyBinding, KeyContext, Keymap, KeymapVersion, Keystroke};
2use parking_lot::Mutex;
3use smallvec::SmallVec;
4use std::sync::Arc;
5
6pub(crate) struct KeystrokeMatcher {
7 pending_keystrokes: Vec<Keystroke>,
8 keymap: Arc<Mutex<Keymap>>,
9 keymap_version: KeymapVersion,
10}
11
12pub struct KeymatchResult {
13 pub bindings: SmallVec<[KeyBinding; 1]>,
14 pub pending: bool,
15}
16
17impl KeystrokeMatcher {
18 pub fn new(keymap: Arc<Mutex<Keymap>>) -> Self {
19 let keymap_version = keymap.lock().version();
20 Self {
21 pending_keystrokes: Vec::new(),
22 keymap_version,
23 keymap,
24 }
25 }
26
27 pub fn has_pending_keystrokes(&self) -> bool {
28 !self.pending_keystrokes.is_empty()
29 }
30
31 /// Pushes a keystroke onto the matcher.
32 /// The result of the new keystroke is returned:
33 /// - KeyMatch::None =>
34 /// No match is valid for this key given any pending keystrokes.
35 /// - KeyMatch::Pending =>
36 /// There exist bindings which are still waiting for more keys.
37 /// - KeyMatch::Complete(matches) =>
38 /// One or more bindings have received the necessary key presses.
39 /// Bindings added later will take precedence over earlier bindings.
40 pub(crate) fn match_keystroke(
41 &mut self,
42 keystroke: &Keystroke,
43 context_stack: &[KeyContext],
44 ) -> KeymatchResult {
45 let keymap = self.keymap.lock();
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.len() == 0 && pending_key.is_none() && self.pending_keystrokes.len() > 0 {
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}