matcher.rs

  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}