matcher.rs

  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}