@@ -275,27 +275,31 @@ impl DispatchTree {
pub fn dispatch_key(
&mut self,
keystroke: &Keystroke,
- context: &[KeyContext],
- ) -> Vec<Box<dyn Action>> {
- if !self.keystroke_matchers.contains_key(context) {
- let keystroke_contexts = context.iter().cloned().collect();
- self.keystroke_matchers.insert(
- keystroke_contexts,
- KeystrokeMatcher::new(self.keymap.clone()),
- );
- }
+ dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
+ ) -> SmallVec<[KeyBinding; 1]> {
+ let mut actions = SmallVec::new();
+
+ let mut context_stack: SmallVec<[KeyContext; 4]> = SmallVec::new();
+ for node_id in dispatch_path {
+ let node = self.node(*node_id);
- let keystroke_matcher = self.keystroke_matchers.get_mut(context).unwrap();
- if let KeyMatch::Some(actions) = keystroke_matcher.match_keystroke(keystroke, context) {
- // Clear all pending keystrokes when an action has been found.
- for keystroke_matcher in self.keystroke_matchers.values_mut() {
- keystroke_matcher.clear_pending();
+ if let Some(context) = node.context.clone() {
+ context_stack.push(context);
}
+ }
- actions
- } else {
- vec![]
+ while !context_stack.is_empty() {
+ let keystroke_matcher = self
+ .keystroke_matchers
+ .entry(context_stack.clone())
+ .or_insert_with(|| KeystrokeMatcher::new(self.keymap.clone()));
+
+ let mut matches = keystroke_matcher.match_keystroke(keystroke, &context_stack);
+ actions.append(&mut matches);
+ context_stack.pop();
}
+
+ actions
}
pub fn has_pending_keystrokes(&self) -> bool {
@@ -46,7 +46,7 @@ impl KeyBinding {
if self.keystrokes.as_ref().starts_with(pending_keystrokes) {
// If the binding is completed, push it onto the matches list
if self.keystrokes.as_ref().len() == pending_keystrokes.len() {
- KeyMatch::Some(vec![self.action.boxed_clone()])
+ KeyMatch::Matched
} else {
KeyMatch::Pending
}
@@ -1,5 +1,6 @@
-use crate::{Action, KeyContext, Keymap, KeymapVersion, Keystroke};
+use crate::{Action, KeyBinding, KeyContext, Keymap, KeymapVersion, Keystroke};
use parking_lot::Mutex;
+use smallvec::SmallVec;
use std::sync::Arc;
pub struct KeystrokeMatcher {
@@ -39,7 +40,7 @@ impl KeystrokeMatcher {
&mut self,
keystroke: &Keystroke,
context_stack: &[KeyContext],
- ) -> KeyMatch {
+ ) -> SmallVec<[KeyBinding; 1]> {
let keymap = self.keymap.lock();
// Clear pending keystrokes if the keymap has changed since the last matched keystroke.
if keymap.version() != self.keymap_version {
@@ -48,7 +49,7 @@ impl KeystrokeMatcher {
}
let mut pending_key = None;
- let mut found_actions = Vec::new();
+ let mut found = SmallVec::new();
for binding in keymap.bindings().rev() {
if !keymap.binding_enabled(binding, context_stack) {
@@ -58,8 +59,8 @@ impl KeystrokeMatcher {
for candidate in keystroke.match_candidates() {
self.pending_keystrokes.push(candidate.clone());
match binding.match_keystrokes(&self.pending_keystrokes) {
- KeyMatch::Some(mut actions) => {
- found_actions.append(&mut actions);
+ KeyMatch::Matched => {
+ found.push(binding.clone());
}
KeyMatch::Pending => {
pending_key.get_or_insert(candidate);
@@ -70,16 +71,15 @@ impl KeystrokeMatcher {
}
}
- if !found_actions.is_empty() {
+ if !found.is_empty() {
self.pending_keystrokes.clear();
- return KeyMatch::Some(found_actions);
} else if let Some(pending_key) = pending_key {
self.pending_keystrokes.push(pending_key);
- KeyMatch::Pending
} else {
self.pending_keystrokes.clear();
- KeyMatch::None
- }
+ };
+
+ found
}
}
@@ -87,43 +87,7 @@ impl KeystrokeMatcher {
pub enum KeyMatch {
None,
Pending,
- Some(Vec<Box<dyn Action>>),
-}
-
-impl KeyMatch {
- pub fn is_some(&self) -> bool {
- matches!(self, KeyMatch::Some(_))
- }
-
- pub fn matches(self) -> Option<Vec<Box<dyn Action>>> {
- match self {
- KeyMatch::Some(matches) => Some(matches),
- _ => None,
- }
- }
-}
-
-impl PartialEq for KeyMatch {
- fn eq(&self, other: &Self) -> bool {
- match (self, other) {
- (KeyMatch::None, KeyMatch::None) => true,
- (KeyMatch::Pending, KeyMatch::Pending) => true,
- (KeyMatch::Some(a), KeyMatch::Some(b)) => {
- if a.len() != b.len() {
- return false;
- }
-
- for (a, b) in a.iter().zip(b.iter()) {
- if !a.partial_eq(b.as_ref()) {
- return false;
- }
- }
-
- true
- }
- _ => false,
- }
- }
+ Matched,
}
#[cfg(test)]
@@ -1784,44 +1784,24 @@ impl<'a> WindowContext<'a> {
.dispatch_tree
.dispatch_path(node_id);
- let mut actions: Vec<Box<dyn Action>> = Vec::new();
-
- let mut context_stack: SmallVec<[KeyContext; 16]> = SmallVec::new();
- for node_id in &dispatch_path {
- let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
+ if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
+ let bindings = self
+ .window
+ .rendered_frame
+ .dispatch_tree
+ .dispatch_key(&key_down_event.keystroke, &dispatch_path);
- if let Some(context) = node.context.clone() {
- context_stack.push(context);
+ if !bindings.is_empty() {
+ self.clear_pending_keystrokes();
}
- }
- for node_id in dispatch_path.iter().rev() {
- // Match keystrokes
- let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
- if node.context.is_some() {
- if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
- let mut new_actions = self
- .window
- .rendered_frame
- .dispatch_tree
- .dispatch_key(&key_down_event.keystroke, &context_stack);
- actions.append(&mut new_actions);
+ self.propagate_event = true;
+ for binding in bindings {
+ self.dispatch_action_on_node(node_id, binding.action.boxed_clone());
+ if !self.propagate_event {
+ self.dispatch_keystroke_observers(event, Some(binding.action));
+ return;
}
-
- context_stack.pop();
- }
- }
-
- if !actions.is_empty() {
- self.clear_pending_keystrokes();
- }
-
- self.propagate_event = true;
- for action in actions {
- self.dispatch_action_on_node(node_id, action.boxed_clone());
- if !self.propagate_event {
- self.dispatch_keystroke_observers(event, Some(action));
- return;
}
}