1mod binding;
2mod keymap;
3mod keymap_context;
4mod keystroke;
5
6use std::{any::TypeId, fmt::Debug};
7
8use collections::HashMap;
9use serde::Deserialize;
10use smallvec::SmallVec;
11
12use crate::{impl_actions, Action};
13
14pub use binding::{Binding, BindingMatchResult};
15pub use keymap::Keymap;
16pub use keymap_context::{KeymapContext, KeymapContextPredicate};
17pub use keystroke::Keystroke;
18
19#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize)]
20pub struct KeyPressed {
21 #[serde(default)]
22 pub keystroke: Keystroke,
23}
24
25impl_actions!(gpui, [KeyPressed]);
26
27pub struct KeymapMatcher {
28 pub contexts: Vec<KeymapContext>,
29 pending_views: HashMap<usize, KeymapContext>,
30 pending_keystrokes: Vec<Keystroke>,
31 keymap: Keymap,
32}
33
34impl KeymapMatcher {
35 pub fn new(keymap: Keymap) -> Self {
36 Self {
37 contexts: Vec::new(),
38 pending_views: Default::default(),
39 pending_keystrokes: Vec::new(),
40 keymap,
41 }
42 }
43
44 pub fn set_keymap(&mut self, keymap: Keymap) {
45 self.clear_pending();
46 self.keymap = keymap;
47 }
48
49 pub fn add_bindings<T: IntoIterator<Item = Binding>>(&mut self, bindings: T) {
50 self.clear_pending();
51 self.keymap.add_bindings(bindings);
52 }
53
54 pub fn clear_bindings(&mut self) {
55 self.clear_pending();
56 self.keymap.clear();
57 }
58
59 pub fn bindings_for_action_type(&self, action_type: TypeId) -> impl Iterator<Item = &Binding> {
60 self.keymap.bindings_for_action_type(action_type)
61 }
62
63 pub fn clear_pending(&mut self) {
64 self.pending_keystrokes.clear();
65 self.pending_views.clear();
66 }
67
68 pub fn has_pending_keystrokes(&self) -> bool {
69 !self.pending_keystrokes.is_empty()
70 }
71
72 pub fn push_keystroke(
73 &mut self,
74 keystroke: Keystroke,
75 mut dispatch_path: Vec<(usize, KeymapContext)>,
76 ) -> MatchResult {
77 let mut any_pending = false;
78 let mut matched_bindings: Vec<(usize, Box<dyn Action>)> = Vec::new();
79
80 let first_keystroke = self.pending_keystrokes.is_empty();
81 self.pending_keystrokes.push(keystroke.clone());
82
83 self.contexts.clear();
84 self.contexts
85 .extend(dispatch_path.iter_mut().map(|e| std::mem::take(&mut e.1)));
86
87 for (i, (view_id, _)) in dispatch_path.into_iter().enumerate() {
88 // Don't require pending view entry if there are no pending keystrokes
89 if !first_keystroke && !self.pending_views.contains_key(&view_id) {
90 continue;
91 }
92
93 // If there is a previous view context, invalidate that view if it
94 // has changed
95 if let Some(previous_view_context) = self.pending_views.remove(&view_id) {
96 if previous_view_context != self.contexts[i] {
97 continue;
98 }
99 }
100
101 // Find the bindings which map the pending keystrokes and current context
102 for binding in self.keymap.bindings().iter().rev() {
103 match binding.match_keys_and_context(&self.pending_keystrokes, &self.contexts[i..])
104 {
105 BindingMatchResult::Complete(mut action) => {
106 // Swap in keystroke for special KeyPressed action
107 if action.name() == "KeyPressed" && action.namespace() == "gpui" {
108 action = Box::new(KeyPressed {
109 keystroke: keystroke.clone(),
110 });
111 }
112 matched_bindings.push((view_id, action))
113 }
114 BindingMatchResult::Partial => {
115 self.pending_views.insert(view_id, self.contexts[i].clone());
116 any_pending = true;
117 }
118 _ => {}
119 }
120 }
121 }
122
123 if !any_pending {
124 self.clear_pending();
125 }
126
127 if !matched_bindings.is_empty() {
128 MatchResult::Matches(matched_bindings)
129 } else if any_pending {
130 MatchResult::Pending
131 } else {
132 MatchResult::None
133 }
134 }
135
136 pub fn keystrokes_for_action(
137 &self,
138 action: &dyn Action,
139 contexts: &[KeymapContext],
140 ) -> Option<SmallVec<[Keystroke; 2]>> {
141 self.keymap
142 .bindings()
143 .iter()
144 .rev()
145 .find_map(|binding| binding.keystrokes_for_action(action, contexts))
146 }
147}
148
149impl Default for KeymapMatcher {
150 fn default() -> Self {
151 Self::new(Keymap::default())
152 }
153}
154
155pub enum MatchResult {
156 None,
157 Pending,
158 Matches(Vec<(usize, Box<dyn Action>)>),
159}
160
161impl Debug for MatchResult {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 match self {
164 MatchResult::None => f.debug_struct("MatchResult::None").finish(),
165 MatchResult::Pending => f.debug_struct("MatchResult::Pending").finish(),
166 MatchResult::Matches(matches) => f
167 .debug_list()
168 .entries(
169 matches
170 .iter()
171 .map(|(view_id, action)| format!("{view_id}, {}", action.name())),
172 )
173 .finish(),
174 }
175 }
176}
177
178impl PartialEq for MatchResult {
179 fn eq(&self, other: &Self) -> bool {
180 match (self, other) {
181 (MatchResult::None, MatchResult::None) => true,
182 (MatchResult::Pending, MatchResult::Pending) => true,
183 (MatchResult::Matches(matches), MatchResult::Matches(other_matches)) => {
184 matches.len() == other_matches.len()
185 && matches.iter().zip(other_matches.iter()).all(
186 |((view_id, action), (other_view_id, other_action))| {
187 view_id == other_view_id && action.eq(other_action.as_ref())
188 },
189 )
190 }
191 _ => false,
192 }
193 }
194}
195
196impl Eq for MatchResult {}
197
198impl Clone for MatchResult {
199 fn clone(&self) -> Self {
200 match self {
201 MatchResult::None => MatchResult::None,
202 MatchResult::Pending => MatchResult::Pending,
203 MatchResult::Matches(matches) => MatchResult::Matches(
204 matches
205 .iter()
206 .map(|(view_id, action)| (*view_id, Action::boxed_clone(action.as_ref())))
207 .collect(),
208 ),
209 }
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use anyhow::Result;
216 use serde::Deserialize;
217
218 use crate::{actions, impl_actions, keymap_matcher::KeymapContext};
219
220 use super::*;
221
222 #[test]
223 fn test_push_keystroke() -> Result<()> {
224 actions!(test, [B, AB, C, D, DA]);
225
226 let mut context1 = KeymapContext::default();
227 context1.set.insert("1".into());
228
229 let mut context2 = KeymapContext::default();
230 context2.set.insert("2".into());
231
232 let dispatch_path = vec![(2, context2), (1, context1)];
233
234 let keymap = Keymap::new(vec![
235 Binding::new("a b", AB, Some("1")),
236 Binding::new("b", B, Some("2")),
237 Binding::new("c", C, Some("2")),
238 Binding::new("d", D, Some("1")),
239 Binding::new("d", D, Some("2")),
240 Binding::new("d a", DA, Some("2")),
241 ]);
242
243 let mut matcher = KeymapMatcher::new(keymap);
244
245 // Binding with pending prefix always takes precedence
246 assert_eq!(
247 matcher.push_keystroke(Keystroke::parse("a")?, dispatch_path.clone()),
248 MatchResult::Pending,
249 );
250 // B alone doesn't match because a was pending, so AB is returned instead
251 assert_eq!(
252 matcher.push_keystroke(Keystroke::parse("b")?, dispatch_path.clone()),
253 MatchResult::Matches(vec![(1, Box::new(AB))]),
254 );
255 assert!(!matcher.has_pending_keystrokes());
256
257 // Without an a prefix, B is dispatched like expected
258 assert_eq!(
259 matcher.push_keystroke(Keystroke::parse("b")?, dispatch_path.clone()),
260 MatchResult::Matches(vec![(2, Box::new(B))]),
261 );
262 assert!(!matcher.has_pending_keystrokes());
263
264 // If a is prefixed, C will not be dispatched because there
265 // was a pending binding for it
266 assert_eq!(
267 matcher.push_keystroke(Keystroke::parse("a")?, dispatch_path.clone()),
268 MatchResult::Pending,
269 );
270 assert_eq!(
271 matcher.push_keystroke(Keystroke::parse("c")?, dispatch_path.clone()),
272 MatchResult::None,
273 );
274 assert!(!matcher.has_pending_keystrokes());
275
276 // If a single keystroke matches multiple bindings in the tree
277 // all of them are returned so that we can fallback if the action
278 // handler decides to propagate the action
279 assert_eq!(
280 matcher.push_keystroke(Keystroke::parse("d")?, dispatch_path.clone()),
281 MatchResult::Matches(vec![(2, Box::new(D)), (1, Box::new(D))]),
282 );
283 // If none of the d action handlers consume the binding, a pending
284 // binding may then be used
285 assert_eq!(
286 matcher.push_keystroke(Keystroke::parse("a")?, dispatch_path.clone()),
287 MatchResult::Matches(vec![(2, Box::new(DA))]),
288 );
289 assert!(!matcher.has_pending_keystrokes());
290
291 Ok(())
292 }
293
294 #[test]
295 fn test_keystroke_parsing() -> Result<()> {
296 assert_eq!(
297 Keystroke::parse("ctrl-p")?,
298 Keystroke {
299 key: "p".into(),
300 ctrl: true,
301 alt: false,
302 shift: false,
303 cmd: false,
304 function: false,
305 }
306 );
307
308 assert_eq!(
309 Keystroke::parse("alt-shift-down")?,
310 Keystroke {
311 key: "down".into(),
312 ctrl: false,
313 alt: true,
314 shift: true,
315 cmd: false,
316 function: false,
317 }
318 );
319
320 assert_eq!(
321 Keystroke::parse("shift-cmd--")?,
322 Keystroke {
323 key: "-".into(),
324 ctrl: false,
325 alt: false,
326 shift: true,
327 cmd: true,
328 function: false,
329 }
330 );
331
332 Ok(())
333 }
334
335 #[test]
336 fn test_context_predicate_parsing() -> Result<()> {
337 use KeymapContextPredicate::*;
338
339 assert_eq!(
340 KeymapContextPredicate::parse("a && (b == c || d != e)")?,
341 And(
342 Box::new(Identifier("a".into())),
343 Box::new(Or(
344 Box::new(Equal("b".into(), "c".into())),
345 Box::new(NotEqual("d".into(), "e".into())),
346 ))
347 )
348 );
349
350 assert_eq!(
351 KeymapContextPredicate::parse("!a")?,
352 Not(Box::new(Identifier("a".into())),)
353 );
354
355 Ok(())
356 }
357
358 #[test]
359 fn test_context_predicate_eval() {
360 let predicate = KeymapContextPredicate::parse("a && b || c == d").unwrap();
361
362 let mut context = KeymapContext::default();
363 context.set.insert("a".into());
364 assert!(!predicate.eval(&[context]));
365
366 let mut context = KeymapContext::default();
367 context.set.insert("a".into());
368 context.set.insert("b".into());
369 assert!(predicate.eval(&[context]));
370
371 let mut context = KeymapContext::default();
372 context.set.insert("a".into());
373 context.map.insert("c".into(), "x".into());
374 assert!(!predicate.eval(&[context]));
375
376 let mut context = KeymapContext::default();
377 context.set.insert("a".into());
378 context.map.insert("c".into(), "d".into());
379 assert!(predicate.eval(&[context]));
380
381 let predicate = KeymapContextPredicate::parse("!a").unwrap();
382 assert!(predicate.eval(&[KeymapContext::default()]));
383 }
384
385 #[test]
386 fn test_context_child_predicate_eval() {
387 let predicate = KeymapContextPredicate::parse("a && b > c").unwrap();
388 let contexts = [
389 context_set(&["e", "f"]),
390 context_set(&["c", "d"]), // match this context
391 context_set(&["a", "b"]),
392 ];
393
394 assert!(!predicate.eval(&contexts[0..]));
395 assert!(predicate.eval(&contexts[1..]));
396 assert!(!predicate.eval(&contexts[2..]));
397
398 let predicate = KeymapContextPredicate::parse("a && b > c && !d > e").unwrap();
399 let contexts = [
400 context_set(&["f"]),
401 context_set(&["e"]), // only match this context
402 context_set(&["c"]),
403 context_set(&["a", "b"]),
404 context_set(&["e"]),
405 context_set(&["c", "d"]),
406 context_set(&["a", "b"]),
407 ];
408
409 assert!(!predicate.eval(&contexts[0..]));
410 assert!(predicate.eval(&contexts[1..]));
411 assert!(!predicate.eval(&contexts[2..]));
412 assert!(!predicate.eval(&contexts[3..]));
413 assert!(!predicate.eval(&contexts[4..]));
414 assert!(!predicate.eval(&contexts[5..]));
415 assert!(!predicate.eval(&contexts[6..]));
416
417 fn context_set(names: &[&str]) -> KeymapContext {
418 KeymapContext {
419 set: names.iter().copied().map(str::to_string).collect(),
420 ..Default::default()
421 }
422 }
423 }
424
425 #[test]
426 fn test_matcher() -> Result<()> {
427 #[derive(Clone, Deserialize, PartialEq, Eq, Debug)]
428 pub struct A(pub String);
429 impl_actions!(test, [A]);
430 actions!(test, [B, Ab]);
431
432 #[derive(Clone, Debug, Eq, PartialEq)]
433 struct ActionArg {
434 a: &'static str,
435 }
436
437 let keymap = Keymap::new(vec![
438 Binding::new("a", A("x".to_string()), Some("a")),
439 Binding::new("b", B, Some("a")),
440 Binding::new("a b", Ab, Some("a || b")),
441 ]);
442
443 let mut context_a = KeymapContext::default();
444 context_a.set.insert("a".into());
445
446 let mut context_b = KeymapContext::default();
447 context_b.set.insert("b".into());
448
449 let mut matcher = KeymapMatcher::new(keymap);
450
451 // Basic match
452 assert_eq!(
453 matcher.push_keystroke(Keystroke::parse("a")?, vec![(1, context_a.clone())]),
454 MatchResult::Matches(vec![(1, Box::new(A("x".to_string())))])
455 );
456 matcher.clear_pending();
457
458 // Multi-keystroke match
459 assert_eq!(
460 matcher.push_keystroke(Keystroke::parse("a")?, vec![(1, context_b.clone())]),
461 MatchResult::Pending
462 );
463 assert_eq!(
464 matcher.push_keystroke(Keystroke::parse("b")?, vec![(1, context_b.clone())]),
465 MatchResult::Matches(vec![(1, Box::new(Ab))])
466 );
467 matcher.clear_pending();
468
469 // Failed matches don't interfere with matching subsequent keys
470 assert_eq!(
471 matcher.push_keystroke(Keystroke::parse("x")?, vec![(1, context_a.clone())]),
472 MatchResult::None
473 );
474 assert_eq!(
475 matcher.push_keystroke(Keystroke::parse("a")?, vec![(1, context_a.clone())]),
476 MatchResult::Matches(vec![(1, Box::new(A("x".to_string())))])
477 );
478 matcher.clear_pending();
479
480 // Pending keystrokes are cleared when the context changes
481 assert_eq!(
482 matcher.push_keystroke(Keystroke::parse("a")?, vec![(1, context_b.clone())]),
483 MatchResult::Pending
484 );
485 assert_eq!(
486 matcher.push_keystroke(Keystroke::parse("b")?, vec![(1, context_a.clone())]),
487 MatchResult::None
488 );
489 matcher.clear_pending();
490
491 let mut context_c = KeymapContext::default();
492 context_c.set.insert("c".into());
493
494 // Pending keystrokes are maintained per-view
495 assert_eq!(
496 matcher.push_keystroke(
497 Keystroke::parse("a")?,
498 vec![(1, context_b.clone()), (2, context_c.clone())]
499 ),
500 MatchResult::Pending
501 );
502 assert_eq!(
503 matcher.push_keystroke(Keystroke::parse("b")?, vec![(1, context_b.clone())]),
504 MatchResult::Matches(vec![(1, Box::new(Ab))])
505 );
506
507 Ok(())
508 }
509}