Skip to main content

gpui_authoring/keymap/
binding.rs

1use std::rc::Rc;
2
3use crate::{
4    Action, AsKeystroke, DummyKeyboardMapper, InvalidKeystrokeError, KeyBindingContextPredicate,
5    KeybindingKeystroke, Keystroke, PlatformKeyboardMapper, SharedString,
6};
7use smallvec::SmallVec;
8
9/// A keybinding and its associated metadata, from the keymap.
10pub struct KeyBinding {
11    pub(crate) action: Box<dyn Action>,
12    pub(crate) keystrokes: SmallVec<[KeybindingKeystroke; 2]>,
13    pub(crate) context_predicate: Option<Rc<KeyBindingContextPredicate>>,
14    pub(crate) meta: Option<KeyBindingMetaIndex>,
15    /// The json input string used when building the keybinding, if any
16    pub(crate) action_input: Option<SharedString>,
17}
18
19impl Clone for KeyBinding {
20    fn clone(&self) -> Self {
21        KeyBinding {
22            action: self.action.boxed_clone(),
23            keystrokes: self.keystrokes.clone(),
24            context_predicate: self.context_predicate.clone(),
25            meta: self.meta,
26            action_input: self.action_input.clone(),
27        }
28    }
29}
30
31impl KeyBinding {
32    /// Construct a new keybinding from the given data. Panics on parse error.
33    pub fn new<A: Action>(keystrokes: &str, action: A, context: Option<&str>) -> Self {
34        let context_predicate =
35            context.map(|context| KeyBindingContextPredicate::parse(context).unwrap().into());
36        Self::load(
37            keystrokes,
38            Box::new(action),
39            context_predicate,
40            false,
41            None,
42            &DummyKeyboardMapper,
43        )
44        .unwrap()
45    }
46
47    /// Load a keybinding from the given raw data.
48    pub fn load(
49        keystrokes: &str,
50        action: Box<dyn Action>,
51        context_predicate: Option<Rc<KeyBindingContextPredicate>>,
52        use_key_equivalents: bool,
53        action_input: Option<SharedString>,
54        keyboard_mapper: &dyn PlatformKeyboardMapper,
55    ) -> std::result::Result<Self, InvalidKeystrokeError> {
56        let keystrokes: SmallVec<[KeybindingKeystroke; 2]> = keystrokes
57            .split_whitespace()
58            .map(|source| {
59                let keystroke = Keystroke::parse(source)?;
60                Ok(keyboard_mapper.map_key_equivalent(keystroke, use_key_equivalents))
61            })
62            .collect::<std::result::Result<_, _>>()?;
63
64        Ok(Self {
65            keystrokes,
66            action,
67            context_predicate,
68            meta: None,
69            action_input,
70        })
71    }
72
73    /// Set the metadata for this binding.
74    pub fn with_meta(mut self, meta: KeyBindingMetaIndex) -> Self {
75        self.meta = Some(meta);
76        self
77    }
78
79    /// Set the metadata for this binding.
80    pub fn set_meta(&mut self, meta: KeyBindingMetaIndex) {
81        self.meta = Some(meta);
82    }
83
84    /// Check if the given keystrokes match this binding.
85    pub fn match_keystrokes(&self, typed: &[impl AsKeystroke]) -> Option<bool> {
86        if self.keystrokes.len() < typed.len() {
87            return None;
88        }
89
90        for (target, typed) in self.keystrokes.iter().zip(typed.iter()) {
91            if !typed.as_keystroke().should_match(target) {
92                return None;
93            }
94        }
95
96        Some(self.keystrokes.len() > typed.len())
97    }
98
99    /// Get the keystrokes associated with this binding
100    pub fn keystrokes(&self) -> &[KeybindingKeystroke] {
101        self.keystrokes.as_slice()
102    }
103
104    /// Get the action associated with this binding
105    pub fn action(&self) -> &dyn Action {
106        self.action.as_ref()
107    }
108
109    /// Get the predicate used to match this binding
110    pub fn predicate(&self) -> Option<Rc<KeyBindingContextPredicate>> {
111        self.context_predicate.as_ref().map(|rc| rc.clone())
112    }
113
114    /// Get the metadata for this binding
115    pub fn meta(&self) -> Option<KeyBindingMetaIndex> {
116        self.meta
117    }
118
119    /// Get the action input associated with the action for this binding
120    pub fn action_input(&self) -> Option<SharedString> {
121        self.action_input.clone()
122    }
123}
124
125impl std::fmt::Debug for KeyBinding {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        f.debug_struct("KeyBinding")
128            .field("keystrokes", &self.keystrokes)
129            .field("context_predicate", &self.context_predicate)
130            .field("action", &self.action.name())
131            .finish()
132    }
133}
134
135/// A unique identifier for retrieval of metadata associated with a key binding.
136/// Intended to be used as an index or key into a user-defined store of metadata
137/// associated with the binding, such as the source of the binding.
138#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
139pub struct KeyBindingMetaIndex(pub u32);