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