Add KeyContextView (#19872)

Release Notes:

- Added `cmd-shift-p debug: Open Key Context View` to help debug custom
key bindings



https://github.com/user-attachments/assets/de273c97-5b27-45aa-9ff1-f943b0ed7dfe
This commit is contained in:
Conrad Irwin 2024-10-30 11:26:54 -06:00 committed by GitHub
parent cf7b0c8971
commit ce5222f1df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 390 additions and 8 deletions

View file

@ -69,6 +69,11 @@ impl KeyBinding {
pub fn action(&self) -> &dyn Action {
self.action.as_ref()
}
/// Get the predicate used to match this binding
pub fn predicate(&self) -> Option<&KeyBindingContextPredicate> {
self.context_predicate.as_ref()
}
}
impl std::fmt::Debug for KeyBinding {

View file

@ -11,9 +11,12 @@ use std::fmt;
pub struct KeyContext(SmallVec<[ContextEntry; 1]>);
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
struct ContextEntry {
key: SharedString,
value: Option<SharedString>,
/// An entry in a KeyContext
pub struct ContextEntry {
/// The key (or name if no value)
pub key: SharedString,
/// The value
pub value: Option<SharedString>,
}
impl<'a> TryFrom<&'a str> for KeyContext {
@ -39,6 +42,17 @@ impl KeyContext {
context
}
/// Returns the primary context entry (usually the name of the component)
pub fn primary(&self) -> Option<&ContextEntry> {
self.0.iter().find(|p| p.value.is_none())
}
/// Returns everything except the primary context entry.
pub fn secondary(&self) -> impl Iterator<Item = &ContextEntry> {
let primary = self.primary();
self.0.iter().filter(move |&p| Some(p) != primary)
}
/// Parse a key context from a string.
/// The key context format is very simple:
/// - either a single identifier, such as `StatusBar`
@ -178,6 +192,20 @@ pub enum KeyBindingContextPredicate {
),
}
impl fmt::Display for KeyBindingContextPredicate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Identifier(name) => write!(f, "{}", name),
Self::Equal(left, right) => write!(f, "{} == {}", left, right),
Self::NotEqual(left, right) => write!(f, "{} != {}", left, right),
Self::Not(pred) => write!(f, "!{}", pred),
Self::Child(parent, child) => write!(f, "{} > {}", parent, child),
Self::And(left, right) => write!(f, "({} && {})", left, right),
Self::Or(left, right) => write!(f, "({} || {})", left, right),
}
}
}
impl KeyBindingContextPredicate {
/// Parse a string in the same format as the keymap's context field.
///