1use std::collections::BTreeMap;
2use std::fmt::Display;
3use std::{collections::HashMap, fmt::Debug};
4
5use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
6use serde::de::Error as DeError;
7use serde::{Deserialize, Serialize, Serializer};
8
9use crate::error::TmsError;
10
11#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
12pub struct Key {
13 code: KeyCode,
14 modifiers: KeyModifiers,
15}
16
17impl PartialOrd for Key {
18 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
19 Some(self.cmp(other))
20 }
21}
22
23impl Ord for Key {
24 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
25 let a = self.to_string();
26 let b = other.to_string();
27 a.cmp(&b)
28 }
29}
30
31impl Display for Key {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 let modifiers = self
34 .modifiers
35 .iter()
36 .filter_map(modifier_to_string)
37 .collect::<Vec<&str>>()
38 .join("-");
39 let code = keycode_to_string(self.code).unwrap();
40 let formatted = if modifiers.is_empty() {
41 code
42 } else {
43 format!("{}-{}", modifiers, code)
44 };
45 write!(f, "{formatted}")
46 }
47}
48
49impl Serialize for Key {
50 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
51 where
52 S: serde::Serializer,
53 {
54 serializer.serialize_str(&self.to_string())
55 }
56}
57
58fn modifier_to_string<'a>(modifier: KeyModifiers) -> Option<&'a str> {
59 match modifier {
60 KeyModifiers::SHIFT => Some("shift"),
61 KeyModifiers::CONTROL => Some("ctrl"),
62 KeyModifiers::ALT => Some("alt"),
63 KeyModifiers::SUPER => Some("super"),
64 KeyModifiers::HYPER => Some("hyper"),
65 KeyModifiers::META => Some("meta"),
66 _ => None,
67 }
68}
69
70fn keycode_to_string(code: KeyCode) -> Option<String> {
71 match code {
72 KeyCode::Esc => Some("esc".to_owned()),
73 KeyCode::Enter => Some("enter".to_owned()),
74 KeyCode::Left => Some("left".to_owned()),
75 KeyCode::Right => Some("right".to_owned()),
76 KeyCode::Up => Some("up".to_owned()),
77 KeyCode::Down => Some("down".to_owned()),
78 KeyCode::Home => Some("home".to_owned()),
79 KeyCode::End => Some("end".to_owned()),
80 KeyCode::PageUp => Some("pageup".to_owned()),
81 KeyCode::PageDown => Some("pagedown".to_owned()),
82 KeyCode::BackTab => Some("backtab".to_owned()),
83 KeyCode::Backspace => Some("backspace".to_owned()),
84 KeyCode::Delete => Some("delete".to_owned()),
85 KeyCode::Insert => Some("insert".to_owned()),
86 KeyCode::F(1) => Some("f1".to_owned()),
87 KeyCode::F(2) => Some("f2".to_owned()),
88 KeyCode::F(3) => Some("f3".to_owned()),
89 KeyCode::F(4) => Some("f4".to_owned()),
90 KeyCode::F(5) => Some("f5".to_owned()),
91 KeyCode::F(6) => Some("f6".to_owned()),
92 KeyCode::F(7) => Some("f7".to_owned()),
93 KeyCode::F(8) => Some("f8".to_owned()),
94 KeyCode::F(9) => Some("f9".to_owned()),
95 KeyCode::F(10) => Some("f10".to_owned()),
96 KeyCode::F(11) => Some("f11".to_owned()),
97 KeyCode::F(12) => Some("f12".to_owned()),
98 KeyCode::Char(' ') => Some("space".to_owned()),
99 KeyCode::Tab => Some("tab".to_owned()),
100 KeyCode::Char(c) => Some(String::from(c)),
101 _ => None,
102 }
103}
104
105impl<'de> Deserialize<'de> for Key {
106 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
107 where
108 D: serde::Deserializer<'de>,
109 {
110 let value: String = Deserialize::deserialize(deserializer)?;
111 let tokens = value.split('-').collect::<Vec<&str>>();
112
113 let mut modifiers = KeyModifiers::empty();
114
115 for modifier in tokens.iter().take(tokens.len() - 1) {
116 match modifier.to_ascii_lowercase().as_ref() {
117 "shift" => modifiers.insert(KeyModifiers::SHIFT),
118 "ctrl" => modifiers.insert(KeyModifiers::CONTROL),
119 "alt" => modifiers.insert(KeyModifiers::ALT),
120 "super" => modifiers.insert(KeyModifiers::SUPER),
121 "hyper" => modifiers.insert(KeyModifiers::HYPER),
122 "meta" => modifiers.insert(KeyModifiers::META),
123 _ => {}
124 };
125 }
126
127 let last = tokens
128 .last()
129 .ok_or(TmsError::ConfigError)
130 .map_err(D::Error::custom)?;
131
132 let code = match last.to_ascii_lowercase().as_ref() {
133 "esc" => KeyCode::Esc,
134 "enter" => KeyCode::Enter,
135 "left" => KeyCode::Left,
136 "right" => KeyCode::Right,
137 "up" => KeyCode::Up,
138 "down" => KeyCode::Down,
139 "home" => KeyCode::Home,
140 "end" => KeyCode::End,
141 "pageup" => KeyCode::PageUp,
142 "pagedown" => KeyCode::PageDown,
143 "backtab" => KeyCode::BackTab,
144 "backspace" => KeyCode::Backspace,
145 "del" => KeyCode::Delete,
146 "delete" => KeyCode::Delete,
147 "insert" => KeyCode::Insert,
148 "ins" => KeyCode::Insert,
149 "f1" => KeyCode::F(1),
150 "f2" => KeyCode::F(2),
151 "f3" => KeyCode::F(3),
152 "f4" => KeyCode::F(4),
153 "f5" => KeyCode::F(5),
154 "f6" => KeyCode::F(6),
155 "f7" => KeyCode::F(7),
156 "f8" => KeyCode::F(8),
157 "f9" => KeyCode::F(9),
158 "f10" => KeyCode::F(10),
159 "f11" => KeyCode::F(11),
160 "f12" => KeyCode::F(12),
161 "space" => KeyCode::Char(' '),
162 "tab" => KeyCode::Tab,
163 c if c.len() == 1 => KeyCode::Char(c.chars().next().unwrap()),
164 _ => {
165 return Err(D::Error::custom(TmsError::ConfigError));
166 }
167 };
168 Ok(Key { code, modifiers })
169 }
170}
171
172impl From<KeyEvent> for Key {
173 fn from(value: KeyEvent) -> Self {
174 Self {
175 code: value.code,
176 modifiers: value.modifiers,
177 }
178 }
179}
180
181#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
182pub struct Keymap(#[serde(serialize_with = "sorted_map")] pub HashMap<Key, PickerAction>);
183
184fn sorted_map<S: Serializer, K: Serialize + Ord + Debug, V: Serialize + Debug>(
185 value: &HashMap<K, V>,
186 serializer: S,
187) -> Result<S::Ok, S::Error> {
188 let mut items: Vec<(_, _)> = value.iter().collect();
189 items.sort_by(|a, b| a.0.cmp(b.0));
190 BTreeMap::from_iter(items).serialize(serializer)
191}
192
193impl Default for Keymap {
194 fn default() -> Self {
195 Keymap(HashMap::from([
196 (
197 Key {
198 code: KeyCode::Char('c'),
199 modifiers: KeyModifiers::CONTROL,
200 },
201 PickerAction::Cancel,
202 ),
203 (
204 Key {
205 code: KeyCode::Esc,
206 modifiers: KeyModifiers::empty(),
207 },
208 PickerAction::Cancel,
209 ),
210 (
211 Key {
212 code: KeyCode::Enter,
213 modifiers: KeyModifiers::empty(),
214 },
215 PickerAction::Confirm,
216 ),
217 (
218 Key {
219 code: KeyCode::Delete,
220 modifiers: KeyModifiers::empty(),
221 },
222 PickerAction::Delete,
223 ),
224 (
225 Key {
226 code: KeyCode::Char('d'),
227 modifiers: KeyModifiers::CONTROL,
228 },
229 PickerAction::Delete,
230 ),
231 (
232 Key {
233 code: KeyCode::Backspace,
234 modifiers: KeyModifiers::empty(),
235 },
236 PickerAction::Backspace,
237 ),
238 (
239 Key {
240 code: KeyCode::Down,
241 modifiers: KeyModifiers::empty(),
242 },
243 PickerAction::MoveDown,
244 ),
245 (
246 Key {
247 code: KeyCode::Char('j'),
248 modifiers: KeyModifiers::CONTROL,
249 },
250 PickerAction::MoveDown,
251 ),
252 (
253 Key {
254 code: KeyCode::Char('n'),
255 modifiers: KeyModifiers::CONTROL,
256 },
257 PickerAction::MoveDown,
258 ),
259 (
260 Key {
261 code: KeyCode::Up,
262 modifiers: KeyModifiers::empty(),
263 },
264 PickerAction::MoveUp,
265 ),
266 (
267 Key {
268 code: KeyCode::Char('k'),
269 modifiers: KeyModifiers::CONTROL,
270 },
271 PickerAction::MoveUp,
272 ),
273 (
274 Key {
275 code: KeyCode::Char('p'),
276 modifiers: KeyModifiers::CONTROL,
277 },
278 PickerAction::MoveUp,
279 ),
280 (
281 Key {
282 code: KeyCode::Left,
283 modifiers: KeyModifiers::empty(),
284 },
285 PickerAction::CursorLeft,
286 ),
287 (
288 Key {
289 code: KeyCode::Right,
290 modifiers: KeyModifiers::empty(),
291 },
292 PickerAction::CursorRight,
293 ),
294 (
295 Key {
296 code: KeyCode::Char('w'),
297 modifiers: KeyModifiers::CONTROL,
298 },
299 PickerAction::DeleteWord,
300 ),
301 (
302 Key {
303 code: KeyCode::Char('u'),
304 modifiers: KeyModifiers::CONTROL,
305 },
306 PickerAction::DeleteToLineStart,
307 ),
308 (
309 Key {
310 code: KeyCode::Char('a'),
311 modifiers: KeyModifiers::CONTROL,
312 },
313 PickerAction::MoveToLineStart,
314 ),
315 (
316 Key {
317 code: KeyCode::Char('e'),
318 modifiers: KeyModifiers::CONTROL,
319 },
320 PickerAction::MoveToLineEnd,
321 ),
322 ]))
323 }
324}
325
326impl Keymap {
327 pub fn with_defaults(keymap: &Keymap) -> Self {
328 let mut default = Self::default();
329 keymap.0.iter().for_each(|(event, action)| {
330 default.0.insert(*event, *action);
331 });
332 default
333 }
334}
335
336#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
337pub enum PickerAction {
338 #[serde(rename = "")]
339 Noop,
340 #[serde(rename = "cancel")]
341 Cancel,
342 #[serde(rename = "confirm")]
343 Confirm,
344 #[serde(rename = "backspace")]
345 Backspace,
346 #[serde(rename = "delete")]
347 Delete,
348 #[serde(rename = "move_up")]
349 MoveUp,
350 #[serde(rename = "move_down")]
351 MoveDown,
352 #[serde(rename = "cursor_left")]
353 CursorLeft,
354 #[serde(rename = "cursor_right")]
355 CursorRight,
356 #[serde(rename = "delete_word")]
357 DeleteWord,
358 #[serde(rename = "delete_to_line_start")]
359 DeleteToLineStart,
360 #[serde(rename = "delete_to_line_end")]
361 DeleteToLineEnd,
362 #[serde(rename = "move_to_line_start")]
363 MoveToLineStart,
364 #[serde(rename = "move_to_line_end")]
365 MoveToLineEnd,
366}