lattice_ui_tui/
keymap_replace.rs1pub use lattice_host::keymap_replace::*;
8
9#[cfg(test)]
10mod tests {
11 #![allow(clippy::unwrap_used, clippy::panic, unused_imports)]
12 use super::*;
13 use crate::actions::ActionIds;
14 use crate::app::Action;
15 use crate::chord::KeyChord;
16 use crate::keymap_registry::KeymapHandle;
17 use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};
18
19 fn ev(code: KeyCode, mods: KeyModifiers) -> KeyChord {
20 let raw = KeyEvent {
21 code,
22 modifiers: mods,
23 kind: KeyEventKind::Press,
24 state: KeyEventState::NONE,
25 };
26 crate::chord::from_event(&raw).expect("test event converts to a chord")
27 }
28
29 fn shared_actions() -> &'static ActionIds {
30 use std::sync::OnceLock;
31 static A: OnceLock<ActionIds> = OnceLock::new();
32 A.get_or_init(|| {
33 let mut r = lattice_grammar::CommandRegistry::new();
34 let b = lattice_grammar::builtins::populate(&mut r);
35 let _ = lattice_grammar::ex_commands::populate(&mut r);
36 crate::actions::populate(&mut r, &b)
37 })
38 }
39
40 fn populated_handle() -> KeymapHandle {
41 let h = KeymapHandle::new();
42 register_replace_bindings(&h, shared_actions());
43 h
44 }
45
46 #[test]
47 fn esc_exits_to_normal() {
48 let h = populated_handle();
49 let a = shared_actions();
50 let r = dispatch_replace(&h, &ev(KeyCode::Esc, KeyModifiers::NONE));
51 match r {
52 Action::Invoke(inv) => assert_eq!(inv.command, a.enter_mode_normal),
53 other => panic!("expected Invoke(enter_mode_normal), got {other:?}"),
54 }
55 }
56
57 #[test]
58 fn backspace_undoes_last() {
59 let h = populated_handle();
60 let a = shared_actions();
61 let r = dispatch_replace(&h, &ev(KeyCode::Backspace, KeyModifiers::NONE));
62 match r {
63 Action::Invoke(inv) => assert_eq!(inv.command, a.replace_undo_last),
64 other => panic!("expected Invoke(replace_undo_last), got {other:?}"),
65 }
66 }
67
68 #[test]
69 fn enter_inserts_newline() {
70 let h = populated_handle();
71 let a = shared_actions();
72 let r = dispatch_replace(&h, &ev(KeyCode::Enter, KeyModifiers::NONE));
73 match r {
74 Action::Invoke(inv) => assert_eq!(inv.command, a.insert_newline),
75 other => panic!("expected Invoke(insert_newline), got {other:?}"),
76 }
77 }
78
79 #[test]
80 fn printable_char_overwrites_with_correct_char() {
81 let h = populated_handle();
82 let a = shared_actions();
83 for c in ['a', 'A', '$', '0', ' '] {
84 let r = dispatch_replace(&h, &ev(KeyCode::Char(c), KeyModifiers::NONE));
85 match r {
86 Action::Invoke(inv) => {
87 assert_eq!(inv.command, a.overwrite_char);
88 assert!(matches!(inv.args, lattice_grammar::args::Args::Char(got) if got == c));
89 }
90 other => panic!(
91 "char {c}: expected Invoke(overwrite_char, args=Char({c:?})), got {other:?}"
92 ),
93 }
94 }
95 }
96
97 #[test]
98 fn ctrl_modifier_yields_none() {
99 let h = populated_handle();
100 let r = dispatch_replace(&h, &ev(KeyCode::Char('c'), KeyModifiers::CONTROL));
101 assert!(matches!(r, Action::None));
102 }
103
104 #[test]
105 fn unhandled_special_keys_yield_none() {
106 let h = populated_handle();
108 for code in [KeyCode::Up, KeyCode::Tab, KeyCode::F(1)] {
109 let r = dispatch_replace(&h, &ev(code, KeyModifiers::NONE));
110 assert!(
111 matches!(r, Action::None),
112 "code {code:?}: expected None, got {r:?}"
113 );
114 }
115 }
116
117 #[test]
124 fn alt_modifier_falls_through_to_overwrite() {
125 let h = populated_handle();
126 let a = shared_actions();
127 let r = dispatch_replace(&h, &ev(KeyCode::Char('x'), KeyModifiers::ALT));
128 match r {
129 Action::Invoke(inv) => {
130 assert_eq!(inv.command, a.overwrite_char);
131 assert!(matches!(inv.args, lattice_grammar::args::Args::Char('x')));
132 }
133 other => panic!("expected Invoke(overwrite_char, Char('x')), got {other:?}"),
134 }
135 }
136
137 #[test]
141 fn shift_only_printable_overwrites() {
142 let h = populated_handle();
143 let a = shared_actions();
144 let r = dispatch_replace(&h, &ev(KeyCode::Char('A'), KeyModifiers::SHIFT));
145 match r {
146 Action::Invoke(inv) => {
147 assert_eq!(inv.command, a.overwrite_char);
148 assert!(matches!(inv.args, lattice_grammar::args::Args::Char('A')));
149 }
150 other => panic!("expected Invoke(overwrite_char, Char('A')), got {other:?}"),
151 }
152 }
153
154 #[test]
158 fn keykind_remains_pub_visible() {
159 let _ = crate::chord::KeyKind::Char('a');
160 }
161}