fast_fs/nav/
cls_key_map.rs1use super::action::Action;
11use super::key_input::KeyInput;
12use hashbrown::HashMap;
13
14#[derive(Debug, Clone)]
38pub struct KeyMap {
39 bindings: HashMap<KeyInput, Action>,
40}
41
42impl KeyMap {
43 pub fn empty() -> Self {
45 Self {
46 bindings: HashMap::new(),
47 }
48 }
49
50 pub fn bind(&mut self, key: KeyInput, action: Action) {
54 self.bindings.insert(key, action);
55 }
56
57 pub fn unbind(&mut self, key: &KeyInput) {
59 self.bindings.remove(key);
60 }
61
62 pub fn get(&self, key: &KeyInput) -> Option<Action> {
64 self.bindings.get(key).copied()
65 }
66
67 pub fn is_bound(&self, key: &KeyInput) -> bool {
69 self.bindings.contains_key(key)
70 }
71
72 pub fn bindings(&self) -> impl Iterator<Item = (&KeyInput, &Action)> {
74 self.bindings.iter()
75 }
76
77 pub fn len(&self) -> usize {
79 self.bindings.len()
80 }
81
82 pub fn is_empty(&self) -> bool {
84 self.bindings.is_empty()
85 }
86
87 pub fn keys_for(&self, action: Action) -> Vec<&KeyInput> {
89 self.bindings
90 .iter()
91 .filter(|(_, &a)| a == action)
92 .map(|(k, _)| k)
93 .collect()
94 }
95}
96
97impl Default for KeyMap {
98 fn default() -> Self {
100 let mut map = Self::empty();
101
102 map.bind(KeyInput::Up, Action::MoveUp);
104 map.bind(KeyInput::Down, Action::MoveDown);
105 map.bind(KeyInput::Char('k'), Action::MoveUp);
106 map.bind(KeyInput::Char('j'), Action::MoveDown);
107 map.bind(KeyInput::Char('g'), Action::MoveToTop);
108 map.bind(KeyInput::Shift('G'), Action::MoveToBottom);
109 map.bind(KeyInput::PageUp, Action::PageUp);
110 map.bind(KeyInput::PageDown, Action::PageDown);
111 map.bind(KeyInput::Enter, Action::Enter);
112 map.bind(KeyInput::Right, Action::Enter);
113 map.bind(KeyInput::Backspace, Action::GoParent);
114 map.bind(KeyInput::Left, Action::GoParent);
115 map.bind(KeyInput::Char('-'), Action::GoBack);
116 map.bind(KeyInput::Shift('_'), Action::GoForward);
117
118 map.bind(KeyInput::Char(' '), Action::ToggleSelect);
120 map.bind(KeyInput::Ctrl('a'), Action::SelectAll);
121 map.bind(KeyInput::Escape, Action::ClearSelection);
122 map.bind(KeyInput::ShiftUp, Action::MoveUpExtend);
123 map.bind(KeyInput::ShiftDown, Action::MoveDownExtend);
124
125 map.bind(KeyInput::Ctrl('x'), Action::Cut);
127 map.bind(KeyInput::Ctrl('c'), Action::Copy);
128
129 map.bind(KeyInput::Char('d'), Action::Delete);
131 map.bind(KeyInput::Char('r'), Action::Rename);
132 map.bind(KeyInput::Char('n'), Action::CreateDir);
133 map.bind(KeyInput::Shift('N'), Action::CreateFile);
134
135 map.bind(KeyInput::Char('.'), Action::ToggleHidden);
137 map.bind(KeyInput::Char('s'), Action::CycleSort);
138 map.bind(KeyInput::Shift('R'), Action::Refresh);
139
140 map.bind(KeyInput::Char('/'), Action::StartFilter);
142 map.bind(KeyInput::Char(':'), Action::StartPathInput);
143
144 map
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn test_empty_keymap() {
154 let map = KeyMap::empty();
155 assert!(map.is_empty());
156 assert_eq!(map.get(&KeyInput::Up), None);
157 }
158
159 #[test]
160 fn test_bind_and_get() {
161 let mut map = KeyMap::empty();
162 map.bind(KeyInput::Up, Action::MoveUp);
163 assert_eq!(map.get(&KeyInput::Up), Some(Action::MoveUp));
164 }
165
166 #[test]
167 fn test_unbind() {
168 let mut map = KeyMap::default();
169 assert!(map.is_bound(&KeyInput::Up));
170 map.unbind(&KeyInput::Up);
171 assert!(!map.is_bound(&KeyInput::Up));
172 }
173
174 #[test]
175 fn test_default_has_vim_bindings() {
176 let map = KeyMap::default();
177 assert_eq!(map.get(&KeyInput::Char('j')), Some(Action::MoveDown));
178 assert_eq!(map.get(&KeyInput::Char('k')), Some(Action::MoveUp));
179 assert_eq!(map.get(&KeyInput::Char('g')), Some(Action::MoveToTop));
180 }
181
182 #[test]
183 fn test_keys_for_action() {
184 let map = KeyMap::default();
185 let up_keys = map.keys_for(Action::MoveUp);
186 assert!(up_keys.contains(&&KeyInput::Up));
187 assert!(up_keys.contains(&&KeyInput::Char('k')));
188 }
189
190 #[test]
191 fn test_replace_binding() {
192 let mut map = KeyMap::empty();
193 map.bind(KeyInput::Char('x'), Action::Delete);
194 map.bind(KeyInput::Char('x'), Action::Refresh);
195 assert_eq!(map.get(&KeyInput::Char('x')), Some(Action::Refresh));
196 }
197}
198
199