1use crate::{KeyBinding, KeyBindingContextPredicate, Keystroke};
2use collections::HashSet;
3use smallvec::SmallVec;
4use std::{any::TypeId, collections::HashMap};
5
6#[derive(Copy, Clone, Eq, PartialEq, Default)]
7pub struct KeymapVersion(usize);
8
9#[derive(Default)]
10pub struct Keymap {
11 bindings: Vec<KeyBinding>,
12 binding_indices_by_action_id: HashMap<TypeId, SmallVec<[usize; 3]>>,
13 disabled_keystrokes:
14 HashMap<SmallVec<[Keystroke; 2]>, HashSet<Option<KeyBindingContextPredicate>>>,
15 version: KeymapVersion,
16}
17
18impl Keymap {
19 pub fn new(bindings: Vec<KeyBinding>) -> Self {
20 let mut this = Self::default();
21 this.add_bindings(bindings);
22 this
23 }
24
25 pub fn version(&self) -> KeymapVersion {
26 self.version
27 }
28
29 pub fn bindings_for_action(&self, action_id: TypeId) -> impl Iterator<Item = &'_ KeyBinding> {
30 self.binding_indices_by_action_id
31 .get(&action_id)
32 .map(SmallVec::as_slice)
33 .unwrap_or(&[])
34 .iter()
35 .map(|ix| &self.bindings[*ix])
36 .filter(|binding| !self.binding_disabled(binding))
37 }
38
39 pub fn add_bindings<T: IntoIterator<Item = KeyBinding>>(&mut self, bindings: T) {
40 // todo!("no action")
41 // let no_action_id = (NoAction {}).id();
42 let mut new_bindings = Vec::new();
43 let has_new_disabled_keystrokes = false;
44 for binding in bindings {
45 // if binding.action().id() == no_action_id {
46 // has_new_disabled_keystrokes |= self
47 // .disabled_keystrokes
48 // .entry(binding.keystrokes)
49 // .or_default()
50 // .insert(binding.context_predicate);
51 // } else {
52 new_bindings.push(binding);
53 // }
54 }
55
56 if has_new_disabled_keystrokes {
57 self.binding_indices_by_action_id.retain(|_, indices| {
58 indices.retain(|ix| {
59 let binding = &self.bindings[*ix];
60 match self.disabled_keystrokes.get(&binding.keystrokes) {
61 Some(disabled_predicates) => {
62 !disabled_predicates.contains(&binding.context_predicate)
63 }
64 None => true,
65 }
66 });
67 !indices.is_empty()
68 });
69 }
70
71 for new_binding in new_bindings {
72 if !self.binding_disabled(&new_binding) {
73 self.binding_indices_by_action_id
74 .entry(new_binding.action().as_any().type_id())
75 .or_default()
76 .push(self.bindings.len());
77 self.bindings.push(new_binding);
78 }
79 }
80
81 self.version.0 += 1;
82 }
83
84 pub fn clear(&mut self) {
85 self.bindings.clear();
86 self.binding_indices_by_action_id.clear();
87 self.disabled_keystrokes.clear();
88 self.version.0 += 1;
89 }
90
91 pub fn bindings(&self) -> Vec<&KeyBinding> {
92 self.bindings
93 .iter()
94 .filter(|binding| !self.binding_disabled(binding))
95 .collect()
96 }
97
98 fn binding_disabled(&self, binding: &KeyBinding) -> bool {
99 match self.disabled_keystrokes.get(&binding.keystrokes) {
100 Some(disabled_predicates) => disabled_predicates.contains(&binding.context_predicate),
101 None => false,
102 }
103 }
104}
105
106// #[cfg(test)]
107// mod tests {
108// use crate::actions;
109
110// use super::*;
111
112// actions!(
113// keymap_test,
114// [Present1, Present2, Present3, Duplicate, Missing]
115// );
116
117// #[test]
118// fn regular_keymap() {
119// let present_1 = Binding::new("ctrl-q", Present1 {}, None);
120// let present_2 = Binding::new("ctrl-w", Present2 {}, Some("pane"));
121// let present_3 = Binding::new("ctrl-e", Present3 {}, Some("editor"));
122// let keystroke_duplicate_to_1 = Binding::new("ctrl-q", Duplicate {}, None);
123// let full_duplicate_to_2 = Binding::new("ctrl-w", Present2 {}, Some("pane"));
124// let missing = Binding::new("ctrl-r", Missing {}, None);
125// let all_bindings = [
126// &present_1,
127// &present_2,
128// &present_3,
129// &keystroke_duplicate_to_1,
130// &full_duplicate_to_2,
131// &missing,
132// ];
133
134// let mut keymap = Keymap::default();
135// assert_absent(&keymap, &all_bindings);
136// assert!(keymap.bindings().is_empty());
137
138// keymap.add_bindings([present_1.clone(), present_2.clone(), present_3.clone()]);
139// assert_absent(&keymap, &[&keystroke_duplicate_to_1, &missing]);
140// assert_present(
141// &keymap,
142// &[(&present_1, "q"), (&present_2, "w"), (&present_3, "e")],
143// );
144
145// keymap.add_bindings([
146// keystroke_duplicate_to_1.clone(),
147// full_duplicate_to_2.clone(),
148// ]);
149// assert_absent(&keymap, &[&missing]);
150// assert!(
151// !keymap.binding_disabled(&keystroke_duplicate_to_1),
152// "Duplicate binding 1 was added and should not be disabled"
153// );
154// assert!(
155// !keymap.binding_disabled(&full_duplicate_to_2),
156// "Duplicate binding 2 was added and should not be disabled"
157// );
158
159// assert_eq!(
160// keymap
161// .bindings_for_action(keystroke_duplicate_to_1.action().id())
162// .map(|binding| &binding.keystrokes)
163// .flatten()
164// .collect::<Vec<_>>(),
165// vec![&Keystroke {
166// ctrl: true,
167// alt: false,
168// shift: false,
169// cmd: false,
170// function: false,
171// key: "q".to_string(),
172// ime_key: None,
173// }],
174// "{keystroke_duplicate_to_1:?} should have the expected keystroke in the keymap"
175// );
176// assert_eq!(
177// keymap
178// .bindings_for_action(full_duplicate_to_2.action().id())
179// .map(|binding| &binding.keystrokes)
180// .flatten()
181// .collect::<Vec<_>>(),
182// vec![
183// &Keystroke {
184// ctrl: true,
185// alt: false,
186// shift: false,
187// cmd: false,
188// function: false,
189// key: "w".to_string(),
190// ime_key: None,
191// },
192// &Keystroke {
193// ctrl: true,
194// alt: false,
195// shift: false,
196// cmd: false,
197// function: false,
198// key: "w".to_string(),
199// ime_key: None,
200// }
201// ],
202// "{full_duplicate_to_2:?} should have a duplicated keystroke in the keymap"
203// );
204
205// let updated_bindings = keymap.bindings();
206// let expected_updated_bindings = vec![
207// &present_1,
208// &present_2,
209// &present_3,
210// &keystroke_duplicate_to_1,
211// &full_duplicate_to_2,
212// ];
213// assert_eq!(
214// updated_bindings.len(),
215// expected_updated_bindings.len(),
216// "Unexpected updated keymap bindings {updated_bindings:?}"
217// );
218// for (i, expected) in expected_updated_bindings.iter().enumerate() {
219// let keymap_binding = &updated_bindings[i];
220// assert_eq!(
221// keymap_binding.context_predicate, expected.context_predicate,
222// "Unexpected context predicate for keymap {i} element: {keymap_binding:?}"
223// );
224// assert_eq!(
225// keymap_binding.keystrokes, expected.keystrokes,
226// "Unexpected keystrokes for keymap {i} element: {keymap_binding:?}"
227// );
228// }
229
230// keymap.clear();
231// assert_absent(&keymap, &all_bindings);
232// assert!(keymap.bindings().is_empty());
233// }
234
235// #[test]
236// fn keymap_with_ignored() {
237// let present_1 = Binding::new("ctrl-q", Present1 {}, None);
238// let present_2 = Binding::new("ctrl-w", Present2 {}, Some("pane"));
239// let present_3 = Binding::new("ctrl-e", Present3 {}, Some("editor"));
240// let keystroke_duplicate_to_1 = Binding::new("ctrl-q", Duplicate {}, None);
241// let full_duplicate_to_2 = Binding::new("ctrl-w", Present2 {}, Some("pane"));
242// let ignored_1 = Binding::new("ctrl-q", NoAction {}, None);
243// let ignored_2 = Binding::new("ctrl-w", NoAction {}, Some("pane"));
244// let ignored_3_with_other_context =
245// Binding::new("ctrl-e", NoAction {}, Some("other_context"));
246
247// let mut keymap = Keymap::default();
248
249// keymap.add_bindings([
250// ignored_1.clone(),
251// ignored_2.clone(),
252// ignored_3_with_other_context.clone(),
253// ]);
254// assert_absent(&keymap, &[&present_3]);
255// assert_disabled(
256// &keymap,
257// &[
258// &present_1,
259// &present_2,
260// &ignored_1,
261// &ignored_2,
262// &ignored_3_with_other_context,
263// ],
264// );
265// assert!(keymap.bindings().is_empty());
266// keymap.clear();
267
268// keymap.add_bindings([
269// present_1.clone(),
270// present_2.clone(),
271// present_3.clone(),
272// ignored_1.clone(),
273// ignored_2.clone(),
274// ignored_3_with_other_context.clone(),
275// ]);
276// assert_present(&keymap, &[(&present_3, "e")]);
277// assert_disabled(
278// &keymap,
279// &[
280// &present_1,
281// &present_2,
282// &ignored_1,
283// &ignored_2,
284// &ignored_3_with_other_context,
285// ],
286// );
287// keymap.clear();
288
289// keymap.add_bindings([
290// present_1.clone(),
291// present_2.clone(),
292// present_3.clone(),
293// ignored_1.clone(),
294// ]);
295// assert_present(&keymap, &[(&present_2, "w"), (&present_3, "e")]);
296// assert_disabled(&keymap, &[&present_1, &ignored_1]);
297// assert_absent(&keymap, &[&ignored_2, &ignored_3_with_other_context]);
298// keymap.clear();
299
300// keymap.add_bindings([
301// present_1.clone(),
302// present_2.clone(),
303// present_3.clone(),
304// keystroke_duplicate_to_1.clone(),
305// full_duplicate_to_2.clone(),
306// ignored_1.clone(),
307// ignored_2.clone(),
308// ignored_3_with_other_context.clone(),
309// ]);
310// assert_present(&keymap, &[(&present_3, "e")]);
311// assert_disabled(
312// &keymap,
313// &[
314// &present_1,
315// &present_2,
316// &keystroke_duplicate_to_1,
317// &full_duplicate_to_2,
318// &ignored_1,
319// &ignored_2,
320// &ignored_3_with_other_context,
321// ],
322// );
323// keymap.clear();
324// }
325
326// #[track_caller]
327// fn assert_present(keymap: &Keymap, expected_bindings: &[(&Binding, &str)]) {
328// let keymap_bindings = keymap.bindings();
329// assert_eq!(
330// expected_bindings.len(),
331// keymap_bindings.len(),
332// "Unexpected keymap bindings {keymap_bindings:?}"
333// );
334// for (i, (expected, expected_key)) in expected_bindings.iter().enumerate() {
335// assert!(
336// !keymap.binding_disabled(expected),
337// "{expected:?} should not be disabled as it was added into keymap for element {i}"
338// );
339// assert_eq!(
340// keymap
341// .bindings_for_action(expected.action().id())
342// .map(|binding| &binding.keystrokes)
343// .flatten()
344// .collect::<Vec<_>>(),
345// vec![&Keystroke {
346// ctrl: true,
347// alt: false,
348// shift: false,
349// cmd: false,
350// function: false,
351// key: expected_key.to_string(),
352// ime_key: None,
353// }],
354// "{expected:?} should have the expected keystroke with key '{expected_key}' in the keymap for element {i}"
355// );
356
357// let keymap_binding = &keymap_bindings[i];
358// assert_eq!(
359// keymap_binding.context_predicate, expected.context_predicate,
360// "Unexpected context predicate for keymap {i} element: {keymap_binding:?}"
361// );
362// assert_eq!(
363// keymap_binding.keystrokes, expected.keystrokes,
364// "Unexpected keystrokes for keymap {i} element: {keymap_binding:?}"
365// );
366// }
367// }
368
369// #[track_caller]
370// fn assert_absent(keymap: &Keymap, bindings: &[&Binding]) {
371// for binding in bindings.iter() {
372// assert!(
373// !keymap.binding_disabled(binding),
374// "{binding:?} should not be disabled in the keymap where was not added"
375// );
376// assert_eq!(
377// keymap.bindings_for_action(binding.action().id()).count(),
378// 0,
379// "{binding:?} should have no actions in the keymap where was not added"
380// );
381// }
382// }
383
384// #[track_caller]
385// fn assert_disabled(keymap: &Keymap, bindings: &[&Binding]) {
386// for binding in bindings.iter() {
387// assert!(
388// keymap.binding_disabled(binding),
389// "{binding:?} should be disabled in the keymap"
390// );
391// assert_eq!(
392// keymap.bindings_for_action(binding.action().id()).count(),
393// 0,
394// "{binding:?} should have no actions in the keymap where it was disabled"
395// );
396// }
397// }
398// }