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, }) }