@@ -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<SmallVec<[Keystroke; 2]>> {
+ 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
@@ -30,9 +30,9 @@ pub struct Keymap {
}
pub struct Binding {
- keystrokes: Vec<Keystroke>,
+ keystrokes: SmallVec<[Keystroke; 2]>,
action: Box<dyn Action>,
- context: Option<ContextPredicate>,
+ context_predicate: Option<ContextPredicate>,
}
#[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<SmallVec<[Keystroke; 2]>> {
+ 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,
})
}