diff --git a/crates/gpui/src/key_dispatch.rs b/crates/gpui/src/key_dispatch.rs index 85a67168e5e1d89588b6d58088a8f381a195e0eb..1bb7feafeb730b4daf8e31f95ca7fada08972c11 100644 --- a/crates/gpui/src/key_dispatch.rs +++ b/crates/gpui/src/key_dispatch.rs @@ -275,27 +275,31 @@ impl DispatchTree { pub fn dispatch_key( &mut self, keystroke: &Keystroke, - context: &[KeyContext], - ) -> Vec> { - 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 { diff --git a/crates/gpui/src/keymap/binding.rs b/crates/gpui/src/keymap/binding.rs index 766e54f4734c0075e40a4ff4699a1735eb483c80..b0fa6f310024578a9d5df3207d84a19e997e21ff 100644 --- a/crates/gpui/src/keymap/binding.rs +++ b/crates/gpui/src/keymap/binding.rs @@ -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 } diff --git a/crates/gpui/src/keymap/matcher.rs b/crates/gpui/src/keymap/matcher.rs index be7204aa67932427a599385ea6d91c1d393c29e9..91eab4d3526601868c6d89a5fb9401f19db92c24 100644 --- a/crates/gpui/src/keymap/matcher.rs +++ b/crates/gpui/src/keymap/matcher.rs @@ -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>), -} - -impl KeyMatch { - pub fn is_some(&self) -> bool { - matches!(self, KeyMatch::Some(_)) - } - - pub fn matches(self) -> Option>> { - 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)] diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 9697d162aee3dc0e97f2dc5320653dcbc0fddb0f..10be2a5741962109f4ef42e075fd5cff4f2474d4 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -1784,44 +1784,24 @@ impl<'a> WindowContext<'a> { .dispatch_tree .dispatch_path(node_id); - let mut actions: Vec> = 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::() { + 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::() { - 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; } }