diff --git a/crates/gpui2/src/key_dispatch.rs b/crates/gpui2/src/key_dispatch.rs index f737c6e30b205d867133bd86561fbcd0dc10a3e6..962a0308445b48afc85dbc4492d19574917a2e9c 100644 --- a/crates/gpui2/src/key_dispatch.rs +++ b/crates/gpui2/src/key_dispatch.rs @@ -60,7 +60,7 @@ impl DispatchTree { self.keystroke_matchers.clear(); } - pub fn push_node(&mut self, context: KeyContext, old_dispatcher: &mut Self) { + pub fn push_node(&mut self, context: KeyContext) { let parent = self.node_stack.last().copied(); let node_id = DispatchNodeId(self.nodes.len()); self.nodes.push(DispatchNode { @@ -71,12 +71,6 @@ impl DispatchTree { if !context.is_empty() { self.active_node().context = context.clone(); self.context_stack.push(context); - if let Some((context_stack, matcher)) = old_dispatcher - .keystroke_matchers - .remove_entry(self.context_stack.as_slice()) - { - self.keystroke_matchers.insert(context_stack, matcher); - } } } @@ -87,6 +81,33 @@ impl DispatchTree { } } + pub fn clear_keystroke_matchers(&mut self) { + self.keystroke_matchers.clear(); + } + + /// Preserve keystroke matchers from previous frames to support multi-stroke + /// bindings across multiple frames. + pub fn preserve_keystroke_matchers(&mut self, old_tree: &mut Self, focus_id: Option) { + if let Some(node_id) = focus_id.and_then(|focus_id| self.focusable_node_id(focus_id)) { + let dispatch_path = self.dispatch_path(node_id); + + self.context_stack.clear(); + for node_id in dispatch_path { + let node = self.node(node_id); + if !node.context.is_empty() { + self.context_stack.push(node.context.clone()); + } + + if let Some((context_stack, matcher)) = old_tree + .keystroke_matchers + .remove_entry(self.context_stack.as_slice()) + { + self.keystroke_matchers.insert(context_stack, matcher); + } + } + } + } + pub fn on_key_event(&mut self, listener: KeyListener) { self.active_node().key_listeners.push(listener); } diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index c6361c8c6e4407916e2a9fe33f352d9803e386fd..0563c107c0b150fc8394acab0a4e3c2bbba4b2af 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -393,6 +393,10 @@ impl<'a> WindowContext<'a> { /// Move focus to the element associated with the given `FocusHandle`. pub fn focus(&mut self, handle: &FocusHandle) { + if self.window.focus == Some(handle.id) { + return; + } + let focus_id = handle.id; if self.window.last_blur.is_none() { @@ -400,6 +404,10 @@ impl<'a> WindowContext<'a> { } self.window.focus = Some(focus_id); + self.window + .current_frame + .dispatch_tree + .clear_keystroke_matchers(); self.app.push_effect(Effect::FocusChanged { window_handle: self.window.handle, focused: Some(focus_id), @@ -1091,6 +1099,14 @@ impl<'a> WindowContext<'a> { }); } + self.window + .current_frame + .dispatch_tree + .preserve_keystroke_matchers( + &mut self.window.previous_frame.dispatch_tree, + self.window.focus, + ); + self.window.root_view = Some(root_view); let scene = self.window.current_frame.scene_builder.build(); @@ -2093,7 +2109,7 @@ impl<'a, V: 'static> ViewContext<'a, V> { window .current_frame .dispatch_tree - .push_node(context.clone(), &mut window.previous_frame.dispatch_tree); + .push_node(context.clone()); if let Some(focus_handle) = focus_handle.as_ref() { window .current_frame