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.
This commit is contained in:
Nathan Sobo 2022-05-24 19:46:50 -06:00 committed by Antonio Scandurra
parent b110fd5fb7
commit 5b7825d5de
2 changed files with 48 additions and 4 deletions

View File

@ -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

View File

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