1use std::collections::HashMap;
13use std::sync::Arc;
14
15use super::thingy::Thingy;
16
17#[derive(Debug, Clone, Copy, Default)]
19pub struct KeymapNameFlags {
20 pub immortal: bool,
22}
23
24#[derive(Debug, Clone)]
26pub struct KeymapName {
27 pub name: String,
28 pub flags: KeymapNameFlags,
29 pub keymap: Arc<Keymap>,
30}
31
32#[derive(Debug, Clone, Copy, Default)]
34pub struct KeymapFlags {
35 pub immutable: bool,
37}
38
39#[derive(Debug, Clone)]
41pub struct Keymap {
42 pub first: [Option<Thingy>; 256],
44 pub multi: HashMap<Vec<u8>, KeyBinding>,
46 pub primary: Option<String>,
48 pub flags: KeymapFlags,
50}
51
52#[derive(Debug, Clone)]
54pub struct KeyBinding {
55 pub bind: Option<Thingy>,
57 pub str: Option<String>,
59 pub prefixct: i32,
61}
62
63#[derive(Debug, Clone, Default)]
65pub struct BindState {
66 pub flags: BindStateFlags,
67 pub kmname: String,
68 pub firstseq: Vec<u8>,
69 pub lastseq: Vec<u8>,
70 pub bind: Option<Thingy>,
71 pub str: Option<String>,
72 pub prefix: Vec<u8>,
73}
74
75bitflags::bitflags! {
76 #[derive(Debug, Clone, Copy, Default)]
77 pub struct BindStateFlags: u32 {
78 const LIST = 1 << 0;
79 const ALL = 1 << 1;
80 }
81}
82
83impl Default for Keymap {
84 fn default() -> Self {
85 Keymap {
86 first: std::array::from_fn(|_| None),
87 multi: HashMap::new(),
88 primary: None,
89 flags: KeymapFlags::default(),
90 }
91 }
92}
93
94impl Keymap {
95 pub fn new() -> Self {
96 Self::default()
97 }
98
99 pub fn bind_char(&mut self, c: u8, thingy: Thingy) {
101 self.first[c as usize] = Some(thingy);
102 }
103
104 pub fn unbind_char(&mut self, c: u8) {
106 self.first[c as usize] = None;
107 }
108
109 pub fn bind_seq(&mut self, seq: &[u8], thingy: Thingy) {
111 if seq.len() == 1 {
112 self.bind_char(seq[0], thingy);
113 } else {
114 for i in 1..seq.len() {
116 let prefix = &seq[..i];
117 self.multi
118 .entry(prefix.to_vec())
119 .and_modify(|kb| kb.prefixct += 1)
120 .or_insert(KeyBinding {
121 bind: None,
122 str: None,
123 prefixct: 1,
124 });
125 }
126
127 self.multi.insert(
129 seq.to_vec(),
130 KeyBinding {
131 bind: Some(thingy),
132 str: None,
133 prefixct: 0,
134 },
135 );
136 }
137 }
138
139 pub fn bind_str(&mut self, seq: &[u8], s: String) {
141 if seq.len() == 1 {
142 }
145
146 for i in 1..seq.len() {
148 let prefix = &seq[..i];
149 self.multi
150 .entry(prefix.to_vec())
151 .and_modify(|kb| kb.prefixct += 1)
152 .or_insert(KeyBinding {
153 bind: None,
154 str: None,
155 prefixct: 1,
156 });
157 }
158
159 self.multi.insert(
160 seq.to_vec(),
161 KeyBinding {
162 bind: None,
163 str: Some(s),
164 prefixct: 0,
165 },
166 );
167 }
168
169 pub fn unbind_seq(&mut self, seq: &[u8]) {
171 if seq.len() == 1 {
172 self.unbind_char(seq[0]);
173 } else {
174 if self.multi.remove(seq).is_some() {
175 for i in 1..seq.len() {
177 let prefix = &seq[..i];
178 if let Some(kb) = self.multi.get_mut(prefix) {
179 kb.prefixct -= 1;
180 if kb.prefixct == 0 && kb.bind.is_none() && kb.str.is_none() {
181 }
184 }
185 }
186 }
187 }
188 }
189
190 pub fn lookup_char(&self, c: u8) -> Option<&Thingy> {
192 self.first[c as usize].as_ref()
193 }
194
195 pub fn lookup_seq(&self, seq: &[u8]) -> Option<&KeyBinding> {
197 if seq.len() == 1 {
198 None
200 } else {
201 self.multi.get(seq)
202 }
203 }
204
205 pub fn is_prefix(&self, seq: &[u8]) -> bool {
207 if seq.len() == 1 {
208 self.multi.keys().any(|k| k.len() > 1 && k[0] == seq[0])
210 } else {
211 self.multi
212 .get(seq)
213 .map(|kb| kb.prefixct > 0)
214 .unwrap_or(false)
215 }
216 }
217}
218
219#[derive(Debug)]
221pub struct KeymapManager {
222 pub keymaps: HashMap<String, Arc<Keymap>>,
224 pub current: Option<Arc<Keymap>>,
226 pub current_name: String,
228 pub local: Option<Arc<Keymap>>,
230 pub keybuf: Vec<u8>,
232 pub lastnamed: Option<Thingy>,
234}
235
236impl Default for KeymapManager {
237 fn default() -> Self {
238 Self::new()
239 }
240}
241
242impl KeymapManager {
243 pub fn new() -> Self {
244 let mut mgr = KeymapManager {
245 keymaps: HashMap::new(),
246 current: None,
247 current_name: "main".to_string(),
248 local: None,
249 keybuf: Vec::with_capacity(20),
250 lastnamed: None,
251 };
252
253 mgr.create_default_keymaps();
255
256 mgr
257 }
258
259 fn create_default_keymaps(&mut self) {
261 let mut emacs = Keymap::new();
263 emacs.primary = Some("emacs".to_string());
264 self.setup_emacs_keymap(&mut emacs);
265 self.keymaps.insert("emacs".to_string(), Arc::new(emacs));
266
267 let mut viins = Keymap::new();
269 viins.primary = Some("viins".to_string());
270 self.setup_viins_keymap(&mut viins);
271 self.keymaps.insert("viins".to_string(), Arc::new(viins));
272
273 let mut vicmd = Keymap::new();
275 vicmd.primary = Some("vicmd".to_string());
276 self.setup_vicmd_keymap(&mut vicmd);
277 self.keymaps.insert("vicmd".to_string(), Arc::new(vicmd));
278
279 let isearch = Keymap::new();
281 self.keymaps
282 .insert("isearch".to_string(), Arc::new(isearch));
283
284 let command = Keymap::new();
286 self.keymaps
287 .insert("command".to_string(), Arc::new(command));
288
289 let emacs = self.keymaps.get("emacs").cloned();
291 if let Some(emacs) = emacs {
292 self.keymaps.insert("main".to_string(), Arc::clone(&emacs));
293 self.current = Some(emacs);
294 }
295 }
296
297 fn setup_emacs_keymap(&self, km: &mut Keymap) {
299 for c in 32u8..127 {
301 km.bind_char(c, Thingy::builtin("self-insert"));
302 }
303
304 km.bind_char(0x01, Thingy::builtin("beginning-of-line")); km.bind_char(0x02, Thingy::builtin("backward-char")); km.bind_char(0x04, Thingy::builtin("delete-char-or-list")); km.bind_char(0x05, Thingy::builtin("end-of-line")); km.bind_char(0x06, Thingy::builtin("forward-char")); km.bind_char(0x08, Thingy::builtin("backward-delete-char")); km.bind_char(0x0B, Thingy::builtin("kill-line")); km.bind_char(0x0C, Thingy::builtin("clear-screen")); km.bind_char(0x0D, Thingy::builtin("accept-line")); km.bind_char(0x0E, Thingy::builtin("down-line-or-history")); km.bind_char(0x10, Thingy::builtin("up-line-or-history")); km.bind_char(0x12, Thingy::builtin("history-incremental-search-backward")); km.bind_char(0x13, Thingy::builtin("history-incremental-search-forward")); km.bind_char(0x14, Thingy::builtin("transpose-chars")); km.bind_char(0x15, Thingy::builtin("kill-whole-line")); km.bind_char(0x17, Thingy::builtin("backward-kill-word")); km.bind_char(0x19, Thingy::builtin("yank")); km.bind_char(0x03, Thingy::builtin("send-break"));
327
328 km.bind_char(0x09, Thingy::builtin("expand-or-complete")); km.bind_char(0x7F, Thingy::builtin("backward-delete-char")); km.bind_seq(b"\x1bb", Thingy::builtin("backward-word")); km.bind_seq(b"\x1bf", Thingy::builtin("forward-word")); km.bind_seq(b"\x1bd", Thingy::builtin("kill-word")); km.bind_seq(b"\x1b\x7f", Thingy::builtin("backward-kill-word")); km.bind_seq(b"\x1b[A", Thingy::builtin("up-line-or-history")); km.bind_seq(b"\x1b[B", Thingy::builtin("down-line-or-history")); km.bind_seq(b"\x1b[C", Thingy::builtin("forward-char")); km.bind_seq(b"\x1b[D", Thingy::builtin("backward-char")); km.bind_seq(b"\x1b[H", Thingy::builtin("beginning-of-line")); km.bind_seq(b"\x1b[F", Thingy::builtin("end-of-line")); km.bind_seq(b"\x1b[3~", Thingy::builtin("delete-char")); km.bind_seq(b"\x1bOA", Thingy::builtin("up-line-or-history"));
352 km.bind_seq(b"\x1bOB", Thingy::builtin("down-line-or-history"));
353 km.bind_seq(b"\x1bOC", Thingy::builtin("forward-char"));
354 km.bind_seq(b"\x1bOD", Thingy::builtin("backward-char"));
355 }
356
357 fn setup_viins_keymap(&self, km: &mut Keymap) {
359 for c in 32u8..127 {
361 km.bind_char(c, Thingy::builtin("self-insert"));
362 }
363
364 km.bind_char(0x1B, Thingy::builtin("vi-cmd-mode")); km.bind_char(0x08, Thingy::builtin("vi-backward-delete-char")); km.bind_char(0x7F, Thingy::builtin("vi-backward-delete-char")); km.bind_char(0x0D, Thingy::builtin("accept-line")); km.bind_char(0x09, Thingy::builtin("expand-or-complete")); km.bind_char(0x03, Thingy::builtin("send-break"));
375
376 km.bind_char(0x17, Thingy::builtin("vi-backward-kill-word"));
378 }
379
380 fn setup_vicmd_keymap(&self, km: &mut Keymap) {
382 km.bind_char(b'h', Thingy::builtin("vi-backward-char"));
384 km.bind_char(b'l', Thingy::builtin("vi-forward-char"));
385 km.bind_char(b'j', Thingy::builtin("down-line-or-history"));
386 km.bind_char(b'k', Thingy::builtin("up-line-or-history"));
387 km.bind_char(b'w', Thingy::builtin("vi-forward-word"));
388 km.bind_char(b'W', Thingy::builtin("vi-forward-blank-word"));
389 km.bind_char(b'b', Thingy::builtin("vi-backward-word"));
390 km.bind_char(b'B', Thingy::builtin("vi-backward-blank-word"));
391 km.bind_char(b'e', Thingy::builtin("vi-forward-word-end"));
392 km.bind_char(b'E', Thingy::builtin("vi-forward-blank-word-end"));
393 km.bind_char(b'0', Thingy::builtin("vi-digit-or-beginning-of-line"));
394 km.bind_char(b'^', Thingy::builtin("vi-first-non-blank"));
395 km.bind_char(b'$', Thingy::builtin("vi-end-of-line"));
396
397 km.bind_char(b'i', Thingy::builtin("vi-insert"));
399 km.bind_char(b'I', Thingy::builtin("vi-insert-bol"));
400 km.bind_char(b'a', Thingy::builtin("vi-add-next"));
401 km.bind_char(b'A', Thingy::builtin("vi-add-eol"));
402 km.bind_char(b'o', Thingy::builtin("vi-open-line-below"));
403 km.bind_char(b'O', Thingy::builtin("vi-open-line-above"));
404
405 km.bind_char(b'x', Thingy::builtin("vi-delete-char"));
407 km.bind_char(b'X', Thingy::builtin("vi-backward-delete-char"));
408 km.bind_char(b'd', Thingy::builtin("vi-delete"));
409 km.bind_char(b'D', Thingy::builtin("vi-kill-eol"));
410 km.bind_char(b'c', Thingy::builtin("vi-change"));
411 km.bind_char(b'C', Thingy::builtin("vi-change-eol"));
412 km.bind_char(b'y', Thingy::builtin("vi-yank"));
413 km.bind_char(b'Y', Thingy::builtin("vi-yank-whole-line"));
414 km.bind_char(b'p', Thingy::builtin("vi-put-after"));
415 km.bind_char(b'P', Thingy::builtin("vi-put-before"));
416 km.bind_char(b'r', Thingy::builtin("vi-replace-chars"));
417 km.bind_char(b'R', Thingy::builtin("vi-replace"));
418 km.bind_char(b's', Thingy::builtin("vi-substitute"));
419 km.bind_char(b'S', Thingy::builtin("vi-change-whole-line"));
420
421 km.bind_char(b'/', Thingy::builtin("vi-history-search-forward"));
423 km.bind_char(b'?', Thingy::builtin("vi-history-search-backward"));
424 km.bind_char(b'n', Thingy::builtin("vi-repeat-search"));
425 km.bind_char(b'N', Thingy::builtin("vi-rev-repeat-search"));
426 km.bind_char(b'f', Thingy::builtin("vi-find-next-char"));
427 km.bind_char(b'F', Thingy::builtin("vi-find-prev-char"));
428 km.bind_char(b't', Thingy::builtin("vi-find-next-char-skip"));
429 km.bind_char(b'T', Thingy::builtin("vi-find-prev-char-skip"));
430 km.bind_char(b';', Thingy::builtin("vi-repeat-find"));
431 km.bind_char(b',', Thingy::builtin("vi-rev-repeat-find"));
432
433 km.bind_char(b'u', Thingy::builtin("undo"));
435 km.bind_char(0x12, Thingy::builtin("redo")); km.bind_char(b'.', Thingy::builtin("vi-repeat-change"));
439
440 for c in b'1'..=b'9' {
442 km.bind_char(c, Thingy::builtin("digit-argument"));
443 }
444
445 km.bind_char(0x0D, Thingy::builtin("accept-line"));
447
448 km.bind_char(0x03, Thingy::builtin("send-break"));
450
451 km.bind_char(b'J', Thingy::builtin("vi-join"));
453
454 km.bind_char(b'G', Thingy::builtin("vi-fetch-history"));
456 km.bind_char(b'g', Thingy::builtin("vi-goto-column")); }
458
459 pub fn get(&self, name: &str) -> Option<Arc<Keymap>> {
461 self.keymaps.get(name).cloned()
462 }
463
464 pub fn select(&mut self, name: &str) -> bool {
466 if let Some(km) = self.keymaps.get(name) {
467 self.current = Some(Arc::clone(km));
468 self.current_name = name.to_string();
469 true
470 } else {
471 false
472 }
473 }
474
475 pub fn link(&mut self, oldname: &str, newname: &str) -> bool {
477 if let Some(km) = self.keymaps.get(oldname) {
478 self.keymaps.insert(newname.to_string(), Arc::clone(km));
479 true
480 } else {
481 false
482 }
483 }
484
485 pub fn delete(&mut self, name: &str) -> bool {
487 if name == "main" || name == "emacs" || name == "viins" || name == "vicmd" {
489 return false;
490 }
491 self.keymaps.remove(name).is_some()
492 }
493
494 pub fn lookup_key(&self, c: char) -> Option<Thingy> {
496 let km = self.local.as_ref().or(self.current.as_ref())?;
497
498 if c as u32 <= 255 {
500 km.first[c as usize].clone()
501 } else {
502 None
503 }
504 }
505
506 pub fn lookup_seq(&self, seq: &[u8]) -> Option<&KeyBinding> {
508 let km = self.local.as_ref().or(self.current.as_ref())?;
509 km.lookup_seq(seq)
510 }
511
512 pub fn is_prefix(&self, seq: &[u8]) -> bool {
514 if let Some(km) = self.local.as_ref().or(self.current.as_ref()) {
515 km.is_prefix(seq)
516 } else {
517 false
518 }
519 }
520
521 pub fn list_names(&self) -> Vec<&String> {
524 self.keymaps.keys().collect()
525 }
526
527 pub fn new_keymap(&mut self, name: &str) -> bool {
530 if self.keymaps.contains_key(name) {
531 return false;
532 }
533
534 let mut km = Keymap::new();
535 km.primary = Some(name.to_string());
536 self.keymaps.insert(name.to_string(), Arc::new(km));
537 true
538 }
539
540 pub fn copy_keymap(&mut self, src: &str, dst: &str) -> bool {
543 if let Some(src_km) = self.keymaps.get(src) {
544 let new_km = (**src_km).clone();
545 self.keymaps.insert(dst.to_string(), Arc::new(new_km));
546 true
547 } else {
548 false
549 }
550 }
551
552 pub fn select_local_map(&mut self, name: Option<&str>) {
555 self.local = name.and_then(|n| self.keymaps.get(n).cloned());
556 }
557
558 pub fn reselect_keymap(&mut self) {
561 self.local = None;
562 }
563
564 pub fn read_command(&self, keys: &[u8]) -> Option<Thingy> {
567 let km = self.local.as_ref().or(self.current.as_ref())?;
568
569 if keys.len() == 1 {
570 km.first[keys[0] as usize].clone()
571 } else {
572 km.lookup_seq(keys).and_then(|kb| kb.bind.clone())
573 }
574 }
575
576 pub fn get_keybuf(&self) -> &[u8] {
579 &self.keybuf
580 }
581
582 pub fn add_keybuf(&mut self, c: u8) {
585 self.keybuf.push(c);
586 }
587
588 pub fn clear_keybuf(&mut self) {
590 self.keybuf.clear();
591 }
592
593 pub fn is_emacs(&self) -> bool {
595 self.current_name == "emacs" || self.current_name == "main"
596 }
597
598 pub fn is_vi_insert(&self) -> bool {
600 self.current_name == "viins"
601 }
602
603 pub fn is_vi_cmd(&self) -> bool {
605 self.current_name == "vicmd"
606 }
607
608 pub fn get_keymap_cmd(&self, km: &Keymap, key: u8) -> Option<Thingy> {
611 km.first[key as usize].clone()
612 }
613
614 pub fn key_is_prefix(&self, km: &Keymap, key: u8) -> bool {
617 km.multi.keys().any(|k| k.len() > 1 && k[0] == key)
618 }
619
620 pub fn keybind(&mut self, seq: &[u8], thingy: Thingy) -> bool {
623 if let Some(km) = self.keymaps.get_mut(&self.current_name) {
624 if let Some(km_mut) = Arc::get_mut(km) {
625 if seq.len() == 1 {
626 km_mut.bind_char(seq[0], thingy);
627 } else {
628 km_mut.bind_seq(seq, thingy);
629 }
630 return true;
631 }
632 }
633 false
634 }
635
636 pub fn keyunbind(&mut self, seq: &[u8]) -> bool {
638 if let Some(km) = self.keymaps.get_mut(&self.current_name) {
639 if let Some(km_mut) = Arc::get_mut(km) {
640 km_mut.unbind_seq(seq);
641 return true;
642 }
643 }
644 false
645 }
646
647 pub fn scan_keymap(&self, name: &str) -> Vec<(Vec<u8>, String)> {
650 let mut bindings = Vec::new();
651
652 if let Some(km) = self.keymaps.get(name) {
653 for (i, opt) in km.first.iter().enumerate() {
655 if let Some(t) = opt {
656 bindings.push((vec![i as u8], t.name.clone()));
657 }
658 }
659
660 for (seq, kb) in &km.multi {
662 if let Some(ref t) = kb.bind {
663 bindings.push((seq.clone(), t.name.clone()));
664 } else if let Some(ref s) = kb.str {
665 bindings.push((seq.clone(), format!("\"{}\"", s)));
666 }
667 }
668 }
669
670 bindings.sort_by(|a, b| a.0.cmp(&b.0));
671 bindings
672 }
673
674 pub fn zle_set_keymap(&mut self, name: &str) -> bool {
677 self.select(name)
678 }
679
680 pub fn ref_keymap_by_name(&self, name: &str) -> Option<Arc<Keymap>> {
683 self.keymaps.get(name).cloned()
684 }
685
686 pub fn init_keymaps(&mut self) {
689 self.create_default_keymaps();
690 }
691
692 pub fn cleanup_keymaps(&mut self) {
695 self.keymaps.clear();
696 self.current = None;
697 self.local = None;
698 }
699}
700
701pub fn bin_bindkey(args: &[String], opts: BindkeyOpts) -> i32 {
704 let _ = (args, opts);
707 0
708}
709
710#[derive(Debug, Default)]
712pub struct BindkeyOpts {
713 pub list: bool, pub list_all: bool, pub delete: bool, pub remove: bool, pub meta: bool, pub new_keymap: bool, pub keymap: Option<String>, pub prefix: Option<String>, }