From 5b7825d5de0e4e517daa63e6db26b6b62dc20058 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 24 May 2022 19:46:50 -0600 Subject: [PATCH] Add MutableAppContext::keystrokes_for_action This can be used to lookup keystrokes that will dispatch an action based on the currently focused view. There might be multiple, but we return the first found, meaning the most recently added bindings matching that action for the closest view to the focused view in the hierarchy. --- crates/gpui/src/app.rs | 22 ++++++++++++++++++++++ crates/gpui/src/keymap.rs | 30 ++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index eb4b9650a67dbc0568f754abb72322df659cc06b..2d93e46c05d6f18459cf6d7acecc2f77289bcc6a 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1413,6 +1413,28 @@ impl MutableAppContext { self.global_actions.contains_key(&action_type) } + /// Return keystrokes that would dispatch the given action closest to the focused view, if there are any. + pub fn keystrokes_for_action(&self, action: &dyn Action) -> Option> { + let window_id = self.cx.platform.key_window_id()?; + let (presenter, _) = self.presenters_and_platform_windows.get(&window_id)?; + let dispatch_path = presenter.borrow().dispatch_path(&self.cx); + + for view_id in dispatch_path.iter().rev() { + let view = self + .cx + .views + .get(&(window_id, *view_id)) + .expect("view in responder chain does not exist"); + let cx = view.keymap_context(self.as_ref()); + let keystrokes = self.keystroke_matcher.keystrokes_for_action(action, &cx); + if keystrokes.is_some() { + return keystrokes; + } + } + + None + } + pub fn dispatch_action_at(&mut self, window_id: usize, view_id: usize, action: &dyn Action) { let presenter = self .presenters_and_platform_windows diff --git a/crates/gpui/src/keymap.rs b/crates/gpui/src/keymap.rs index bd156ed66149007068b2b8fc4f1b9be58c479390..dca752ed6f8c4b59e3427fcbee2f80d8eb3475ea 100644 --- a/crates/gpui/src/keymap.rs +++ b/crates/gpui/src/keymap.rs @@ -30,9 +30,9 @@ pub struct Keymap { } pub struct Binding { - keystrokes: Vec, + keystrokes: SmallVec<[Keystroke; 2]>, action: Box, - context: Option, + context_predicate: Option, } #[derive(Clone, Debug, Eq, PartialEq)] @@ -146,7 +146,11 @@ impl Matcher { let mut retain_pending = false; for binding in self.keymap.bindings.iter().rev() { if binding.keystrokes.starts_with(&pending.keystrokes) - && binding.context.as_ref().map(|c| c.eval(cx)).unwrap_or(true) + && binding + .context_predicate + .as_ref() + .map(|c| c.eval(cx)) + .unwrap_or(true) { if binding.keystrokes.len() == pending.keystrokes.len() { self.pending.remove(&view_id); @@ -165,6 +169,24 @@ impl Matcher { MatchResult::None } } + + pub fn keystrokes_for_action( + &self, + action: &dyn Action, + cx: &Context, + ) -> Option> { + for binding in self.keymap.bindings.iter().rev() { + if binding.action.id() == action.id() + && binding + .context_predicate + .as_ref() + .map_or(true, |predicate| predicate.eval(cx)) + { + return Some(binding.keystrokes.clone()); + } + } + todo!() + } } impl Default for Matcher { @@ -236,7 +258,7 @@ impl Binding { Ok(Self { keystrokes, action, - context, + context_predicate: context, }) }