1#[cfg(feature = "crossterm_0_29_0")]
2use crossterm_0_29_0::event::{KeyCode, KeyEvent, KeyModifiers, MediaKeyCode};
3#[cfg(feature = "crossterm_0_28_1")]
4use crossterm_0_28_1::event::{KeyCode, KeyEvent, KeyModifiers, MediaKeyCode};
5
6use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
7use std::fmt;
8#[cfg(feature = "case_ignore")]
9use str_utils::StartsWithIgnoreAsciiCase;
10
11#[derive(Default, PartialEq)]
12pub enum DisplayFormat {
13 #[default]
15 Symbols,
16
17 Debug,
19
20 Full,
22
23 Abbreviation
25}
26
27#[derive(PartialEq)]
28pub struct KeyBinding {
29 pub code: KeyCode,
30 pub modifiers: KeyModifiers,
31}
32
33impl Serialize for KeyBinding {
34 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
35 where
36 S: Serializer,
37 {
38 let mut s = match self.modifiers {
39 KeyModifiers::SHIFT => "Shift+".to_string(),
40 KeyModifiers::CONTROL => "Control+".to_string(),
41 KeyModifiers::ALT => "Alternate+".to_string(),
42 KeyModifiers::SUPER => "Super+".to_string(),
43 KeyModifiers::HYPER => "Hyper+".to_string(),
44 KeyModifiers::META => "Meta+".to_string(),
45 _ => String::new(),
47 };
48 match self.code {
49 KeyCode::Char(c) => s.push(c),
50 KeyCode::Backspace => s.push_str("Backspace"),
51 KeyCode::Enter => s.push_str("Enter"),
52 KeyCode::Left => s.push_str("Left"),
53 KeyCode::Right => s.push_str("Right"),
54 KeyCode::Up => s.push_str("Up"),
55 KeyCode::Down => s.push_str("Down"),
56 KeyCode::Home => s.push_str("Home"),
57 KeyCode::End => s.push_str("End"),
58 KeyCode::PageUp => s.push_str("PageUp"),
59 KeyCode::PageDown => s.push_str("PageDown"),
60 KeyCode::Tab => s.push_str("Tab"),
61 KeyCode::BackTab => s.push_str("BackTab"),
62 KeyCode::Delete => s.push_str("Delete"),
63 KeyCode::Insert => s.push_str("Insert"),
64 KeyCode::F(n) => s.push_str(&format!("F{n}")),
65 KeyCode::Esc => s.push_str("Esc"),
66 KeyCode::CapsLock => s.push_str("CapsLock"),
67 KeyCode::ScrollLock => s.push_str("ScrollLock"),
68 KeyCode::NumLock => s.push_str("NumLock"),
69 KeyCode::PrintScreen => s.push_str("PrintScreen"),
70 KeyCode::Pause => s.push_str("Pause"),
71 KeyCode::Menu => s.push_str("Menu"),
72 KeyCode::KeypadBegin => s.push_str("KeypadBegin"),
73 KeyCode::Media(media_keycode) => s.push_str(&media_keycode.to_string()),
74 _ => {
75 return Err(ser::Error::custom(format!(
76 "Unsupported KeyCode: {:}",
77 self.code
78 )))
79 }
80 }
81 serializer.serialize_str(&s)
82 }
83}
84
85fn str_to_keycode(s: &str) -> KeyCode {
86 if s == " " {
88 return KeyCode::Char(' ');
89 }
90 let s = s.trim();
91 if s.len() == 1 {
92 KeyCode::Char(s.chars().next().unwrap())
93 } else if s == "Backspace" {
94 KeyCode::Backspace
95 } else if s == "Enter" {
96 KeyCode::Enter
97 } else if s == "Left" {
98 KeyCode::Left
99 } else if s == "Right" {
100 KeyCode::Right
101 } else if s == "Up" {
102 KeyCode::Up
103 } else if s == "Down" {
104 KeyCode::Down
105 } else if s == "Home" {
106 KeyCode::Home
107 } else if s == "End" {
108 KeyCode::End
109 } else if s == "PageUp" {
110 KeyCode::PageUp
111 } else if s == "PageDown" {
112 KeyCode::PageDown
113 } else if s == "Tab" {
114 KeyCode::Tab
115 } else if s == "BackTab" {
116 KeyCode::BackTab
117 } else if s == "Delete" {
118 KeyCode::Delete
119 } else if s == "Insert" {
120 KeyCode::Insert
121 } else if s == "F1" {
122 KeyCode::F(1)
123 } else if s == "F2" {
124 KeyCode::F(2)
125 } else if s == "F3" {
126 KeyCode::F(3)
127 } else if s == "F4" {
128 KeyCode::F(4)
129 } else if s == "F5" {
130 KeyCode::F(5)
131 } else if s == "F6" {
132 KeyCode::F(6)
133 } else if s == "F7" {
134 KeyCode::F(7)
135 } else if s == "F8" {
136 KeyCode::F(8)
137 } else if s == "F9" {
138 KeyCode::F(9)
139 } else if s == "F10" {
140 KeyCode::F(10)
141 } else if s == "F11" {
142 KeyCode::F(11)
143 } else if s == "F12" {
144 KeyCode::F(12)
145 } else if s == "Esc" {
146 KeyCode::Esc
147 } else if s == "CapsLock" {
148 KeyCode::CapsLock
149 } else if s == "ScrollLock" {
150 KeyCode::ScrollLock
151 } else if s == "NumLock" {
152 KeyCode::NumLock
153 } else if s == "PrintScreen" {
154 KeyCode::PrintScreen
155 } else if s == "Pause" {
156 KeyCode::Pause
157 } else if s == "Menu" {
158 KeyCode::Menu
159 } else if s == "KeypadBegin" {
160 KeyCode::KeypadBegin
161 } else if s == "Play" {
162 KeyCode::Media(MediaKeyCode::Play)
163 } else if s == "PlayPause" {
164 KeyCode::Media(MediaKeyCode::PlayPause)
165 } else if s == "Reverse" {
166 KeyCode::Media(MediaKeyCode::Reverse)
167 } else if s == "Stop" {
168 KeyCode::Media(MediaKeyCode::Stop)
169 } else if s == "FastForward" {
170 KeyCode::Media(MediaKeyCode::FastForward)
171 } else if s == "Rewind" {
172 KeyCode::Media(MediaKeyCode::Rewind)
173 } else if s == "TrackNext" {
174 KeyCode::Media(MediaKeyCode::TrackNext)
175 } else if s == "TrackPrevious" {
176 KeyCode::Media(MediaKeyCode::TrackPrevious)
177 } else if s == "Record" {
178 KeyCode::Media(MediaKeyCode::Record)
179 } else if s == "LowerVolume" {
180 KeyCode::Media(MediaKeyCode::LowerVolume)
181 } else if s == "RaiseVolume" {
182 KeyCode::Media(MediaKeyCode::RaiseVolume)
183 } else if s == "MuteVolume" {
184 KeyCode::Media(MediaKeyCode::MuteVolume)
185 } else {
186 KeyCode::Null
187 }
188}
189
190impl<'de> Deserialize<'de> for KeyBinding {
191 fn deserialize<D>(deserializer: D) -> Result<KeyBinding, D::Error>
192 where
193 D: Deserializer<'de>,
194 {
195 let mut key_bindings = KeyBinding {
196 code: KeyCode::Null,
197 modifiers: KeyModifiers::NONE,
198 };
199 let mut error = None;
200
201 <String as Deserialize>::deserialize(deserializer).map(|s| {
202 if s.contains('+') {
203 #[cfg(feature = "case_ignore")]
204 if s.starts_with_ignore_ascii_case("Shift") {
205 key_bindings.modifiers = KeyModifiers::SHIFT;
206 } else if s.starts_with_ignore_ascii_case("Control") || s.starts_with_ignore_ascii_case("Ctrl") {
207 key_bindings.modifiers = KeyModifiers::CONTROL;
208 } else if s.starts_with_ignore_ascii_case("Alternate") || s.starts_with_ignore_ascii_case("Alt") {
209 key_bindings.modifiers = KeyModifiers::ALT;
210 } else if s.starts_with_ignore_ascii_case("Super") {
211 key_bindings.modifiers = KeyModifiers::SUPER;
212 } else if s.starts_with_ignore_ascii_case("Hyper") {
213 key_bindings.modifiers = KeyModifiers::HYPER;
214 } else if s.starts_with_ignore_ascii_case("Meta") {
215 key_bindings.modifiers = KeyModifiers::META;
216 } else {
217 error = Some(de::Error::custom(
218 "Currently only support following KeyModifiers: Shift, Control, Alternate, Super, Hyper, Meta"
219 ));
220 }
221 #[cfg(not(feature = "case_ignore"))]
222 if s.starts_with("Shift") {
223 key_bindings.modifiers = KeyModifiers::SHIFT;
224 } else if s.starts_with("Control") || s.starts_with("Ctrl") {
225 key_bindings.modifiers = KeyModifiers::CONTROL;
226 } else if s.starts_with("Alternate") || s.starts_with("Alt") {
227 key_bindings.modifiers = KeyModifiers::ALT;
228 } else if s.starts_with("Super") {
229 key_bindings.modifiers = KeyModifiers::SUPER;
230 } else if s.starts_with("Hyper") {
231 key_bindings.modifiers = KeyModifiers::HYPER;
232 } else if s.starts_with("Meta") {
233 key_bindings.modifiers = KeyModifiers::META;
234 } else {
235 error = Some(de::Error::custom(
236 "Currently only support following KeyModifiers: Shift, Control, Alternate, Super, Hyper, Meta"
237 ));
238 }
239 let mut splitter = s.splitn(2, '+');
240 key_bindings.code = str_to_keycode(splitter.nth(1).unwrap());
241 } else {
242 key_bindings.code = str_to_keycode(&s);
243 }
244 })?;
245 if let Some(e) = error {
246 Err(e)
247 } else if key_bindings.code == KeyCode::Null {
248 Err(de::Error::custom(
249 r#"Can not load a KeyCode, please use a char or one of following KeyCodes:
250"Backspace", "Enter", "Left", "Right", "Up", "Down", "Home", "End", "PageUp", "PageDown", "Tab", "BackTab", "Delete",
251"Insert", "F1" ~ "F12", "Esc", "CapsLock", "ScrollLock", "NumLock", "PrintScreen", "Pause", "Menu", "KeypadBegin",
252"Play", "PlayPause", "Reverse", "Stop", "FastForward", "Rewind", "TrackNext", "TrackPrevious", "Record", "LowerVolume",
253"RaiseVolume", "MuteVolume""#,
254 ))
255 } else {
256 Ok(key_bindings)
257 }
258 }
259}
260
261impl fmt::Display for KeyBinding {
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 match self.modifiers {
267 KeyModifiers::SHIFT => write!(f, "\u{21e7}")?, KeyModifiers::CONTROL => write!(f, "^")?,
269 KeyModifiers::ALT => write!(f, "\u{2387}")?, KeyModifiers::SUPER => write!(f, "\u{2756}")?, KeyModifiers::HYPER => write!(f, "\u{2388}")?, KeyModifiers::META => write!(f, "\u{2318}")?, KeyModifiers::NONE => write!(f, "")?,
274 _ => write!(f, "?")?,
275 };
276 match self.code {
277 KeyCode::Char(c) => write!(f, "{}", c),
278 KeyCode::Backspace => write!(f, "\u{232b}"), KeyCode::Enter => write!(f, "\u{23ce}"), KeyCode::Left => write!(f, "\u{2190}"), KeyCode::Right => write!(f, "\u{2192}"), KeyCode::Up => write!(f, "\u{2191}"), KeyCode::Down => write!(f, "\u{2193}"), KeyCode::Home => write!(f, "\u{2912}"), KeyCode::End => write!(f, "\u{2913}"), KeyCode::PageUp => write!(f, "\u{21de}"), KeyCode::PageDown => write!(f, "\u{21df}"), KeyCode::Tab => write!(f, "\u{21e5}"), KeyCode::BackTab => write!(f, "\u{21e4}"), KeyCode::Delete => write!(f, "\u{2326}"), KeyCode::Insert => write!(f, "\u{2380}"), KeyCode::F(n) => write!(f, "F{}", n),
293 KeyCode::Esc => write!(f, "\u{238b}"), KeyCode::CapsLock => write!(f, "\u{1F130}"), KeyCode::ScrollLock => write!(f, "\u{1F4DC}"), KeyCode::NumLock => write!(f, "\u{2460}"), KeyCode::PrintScreen => write!(f, "\u{2399}"), KeyCode::Pause => write!(f, "\u{2389}"), KeyCode::Menu => write!(f, "\u{1F5C7}"), KeyCode::KeypadBegin => write!(f, "\u{1F5CA}"), KeyCode::Media(MediaKeyCode::Play) => write!(f, "\u{23F5}"), KeyCode::Media(MediaKeyCode::PlayPause) => write!(f, "\u{23EF}"), KeyCode::Media(MediaKeyCode::Reverse) => write!(f, "\u{2B6F}"), KeyCode::Media(MediaKeyCode::Stop) => write!(f, "\u{23F9}"), KeyCode::Media(MediaKeyCode::FastForward) => write!(f, "\u{23ED}"), KeyCode::Media(MediaKeyCode::Rewind) => write!(f, "\u{2B6E}"), KeyCode::Media(MediaKeyCode::TrackNext) => write!(f, "\u{29D0}"), KeyCode::Media(MediaKeyCode::TrackPrevious) => write!(f, "\u{29CF}"), KeyCode::Media(MediaKeyCode::Record) => write!(f, "\u{241E}"), KeyCode::Media(MediaKeyCode::LowerVolume) => write!(f, "\u{1F508}"), KeyCode::Media(MediaKeyCode::RaiseVolume) => write!(f, "\u{1F50A}"), KeyCode::Media(MediaKeyCode::MuteVolume) => write!(f, "\u{1F507}"), _ => write!(f, "?"),
314 }
315 }
316}
317
318impl fmt::Debug for KeyBinding {
319 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
320 write!(f,"\"")?;
321 match self.modifiers {
322 KeyModifiers::SHIFT => write!(f, "Shift+")?,
323 KeyModifiers::CONTROL => write!(f, "Control+")?,
324 KeyModifiers::ALT => write!(f, "Alternate+")?,
325 KeyModifiers::SUPER => write!(f, "Super+")?,
326 KeyModifiers::HYPER => write!(f, "Hyper+")?,
327 KeyModifiers::META => write!(f, "Meta+")?,
328 KeyModifiers::NONE => write!(f, "")?,
329 _ => write!(f, "UNKNOWN+")?,
330 };
331 match self.code {
332 KeyCode::Char(c) => write!(f, "{}", c)?,
333 KeyCode::Backspace => write!(f, "Backspace")?,
334 KeyCode::Enter => write!(f, "Enter")?,
335 KeyCode::Left => write!(f, "Left")?,
336 KeyCode::Right => write!(f, "Right")?,
337 KeyCode::Up => write!(f, "Up")?,
338 KeyCode::Down => write!(f, "Down")?,
339 KeyCode::Home => write!(f, "Home")?,
340 KeyCode::End => write!(f, "End")?,
341 KeyCode::PageUp => write!(f, "PageUp")?,
342 KeyCode::PageDown => write!(f, "PageDown")?,
343 KeyCode::Tab => write!(f, "Tab")?,
344 KeyCode::BackTab => write!(f, "BackTab")?,
345 KeyCode::Delete => write!(f, "Delete")?,
346 KeyCode::Insert => write!(f, "Insert")?,
347 KeyCode::F(n) => write!(f, "F{}", n)?,
348 KeyCode::Esc => write!(f, "Esc")?,
349 KeyCode::CapsLock => write!(f, "CapsLock")?,
350 KeyCode::ScrollLock => write!(f, "ScrollLock")?,
351 KeyCode::NumLock => write!(f, "NumLock")?,
352 KeyCode::PrintScreen => write!(f, "PrintScreen")?,
353 KeyCode::Pause => write!(f, "Pause")?,
354 KeyCode::Menu => write!(f, "Menu")?,
355 KeyCode::KeypadBegin => write!(f, "KeypadBegin")?,
356 KeyCode::Media(MediaKeyCode::Play) => write!(f, "Play")?,
357 KeyCode::Media(MediaKeyCode::PlayPause) => write!(f, "PlayPause")?,
358 KeyCode::Media(MediaKeyCode::Reverse) => write!(f, "Reverse")?,
359 KeyCode::Media(MediaKeyCode::Stop) => write!(f, "Stop")?,
360 KeyCode::Media(MediaKeyCode::FastForward) => write!(f, "FastForward")?,
361 KeyCode::Media(MediaKeyCode::Rewind) => write!(f, "Rewind")?,
362 KeyCode::Media(MediaKeyCode::TrackNext) => write!(f, "TrackNext")?,
363 KeyCode::Media(MediaKeyCode::TrackPrevious) => write!(f, "TrackPrevious")?,
364 KeyCode::Media(MediaKeyCode::Record) => write!(f, "Record")?,
365 KeyCode::Media(MediaKeyCode::LowerVolume) => write!(f, "LowerVolume")?,
366 KeyCode::Media(MediaKeyCode::RaiseVolume) => write!(f, "RaiseVolume")?,
367 KeyCode::Media(MediaKeyCode::MuteVolume) => write!(f, "MuteVolume")?,
368 _ => write!(f, "?")?,
369 }
370 write!(f,"\"")
371 }
372}
373
374impl KeyBinding {
375 pub fn display(&self, f: &DisplayFormat) -> String {
376 match f {
377 DisplayFormat::Symbols => format!("{}", self),
378 DisplayFormat::Debug => format!("{:?}", self),
379 DisplayFormat::Full | DisplayFormat::Abbreviation => {
380 let mut display = match (f, self.modifiers) {
381 (_, KeyModifiers::SHIFT) => "Shift+".to_string(),
382 (DisplayFormat::Full, KeyModifiers::CONTROL) => "Control+".to_string(),
383 (DisplayFormat::Abbreviation, KeyModifiers::CONTROL) => "Ctrl+".to_string(),
384 (DisplayFormat::Full, KeyModifiers::ALT) => "Alternate+".to_string(),
385 (DisplayFormat::Abbreviation, KeyModifiers::ALT) => "Alt+".to_string(),
386 (_, KeyModifiers::SUPER) => "Super+".to_string(),
387 (_, KeyModifiers::HYPER) => "Hyper+".to_string(),
388 (_, KeyModifiers::META) => "Meta+".to_string(),
389 (_, KeyModifiers::NONE) => String::new(),
390 (_, _) => "UNKNOWN+".to_string(),
391 };
392 match self.code {
393 KeyCode::Char(' ') => display.push_str("Space"),
394 KeyCode::Char(c) => display.push(c),
395 KeyCode::Backspace => display.push_str("Backspace"),
396 KeyCode::Enter => display.push_str("Enter"),
397 KeyCode::Left => display.push_str("Left"),
398 KeyCode::Right => display.push_str("Right"),
399 KeyCode::Up => display.push_str("Up"),
400 KeyCode::Down => display.push_str("Down"),
401 KeyCode::Home => display.push_str("Home"),
402 KeyCode::End => display.push_str("End"),
403 KeyCode::PageUp => display.push_str("PageUp"),
404 KeyCode::PageDown => display.push_str("PageDown"),
405 KeyCode::Tab => display.push_str("Tab"),
406 KeyCode::BackTab => display.push_str("BackTab"),
407 KeyCode::Delete => display.push_str("Delete"),
408 KeyCode::Insert => display.push_str("Insert"),
409 KeyCode::F(n) => display.push_str(&format!("F{}", n)),
410 KeyCode::Esc => display.push_str("Esc"),
411 KeyCode::CapsLock => display.push_str("CapsLock"),
412 KeyCode::ScrollLock => display.push_str("ScrollLock"),
413 KeyCode::NumLock => display.push_str("NumLock"),
414 KeyCode::PrintScreen => display.push_str("PrintScreen"),
415 KeyCode::Pause => display.push_str("Pause"),
416 KeyCode::Menu => display.push_str("Menu"),
417 KeyCode::KeypadBegin => display.push_str("KeypadBegin"),
418 KeyCode::Media(MediaKeyCode::Play) => display.push_str("Play"),
419 KeyCode::Media(MediaKeyCode::PlayPause) => display.push_str("PlayPause"),
420 KeyCode::Media(MediaKeyCode::Reverse) => display.push_str("Reverse"),
421 KeyCode::Media(MediaKeyCode::Stop) => display.push_str("Stop"),
422 KeyCode::Media(MediaKeyCode::FastForward) => display.push_str("FastForward"),
423 KeyCode::Media(MediaKeyCode::Rewind) => display.push_str("Rewind"),
424 KeyCode::Media(MediaKeyCode::TrackNext) => display.push_str("TrackNext"),
425 KeyCode::Media(MediaKeyCode::TrackPrevious) => display.push_str("TrackPrevious"),
426 KeyCode::Media(MediaKeyCode::Record) => display.push_str("Record"),
427 KeyCode::Media(MediaKeyCode::LowerVolume) => display.push_str("LowerVolume"),
428 KeyCode::Media(MediaKeyCode::RaiseVolume) => display.push_str("RaiseVolume"),
429 KeyCode::Media(MediaKeyCode::MuteVolume) => display.push_str("MuteVolume"),
430 _ => display.push('?'),
431 }
432 display
433 }
434 }
435 }
436}
437
438#[derive(Serialize, Deserialize, PartialEq)]
440pub struct KeyBindings(Vec<KeyBinding>);
441
442impl KeyBindings {
443 pub fn match_any(&self, key_event: &KeyEvent) -> bool {
445 for key_bind in self.0.iter() {
446 if key_bind.code == key_event.code && key_bind.modifiers == key_event.modifiers {
447 return true;
448 }
449 }
450 false
451 }
452}
453
454impl fmt::Display for KeyBindings {
455 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
456 for (i, kb) in self.0.iter().enumerate() {
457 if i > 0 {
458 write!(f, "|{}", kb)?; } else {
460 write!(f, "{}", kb)?;
461 }
462 }
463 Ok(())
464 }
465}
466
467impl fmt::Debug for KeyBindings {
468 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469 write!(f, "[")?;
470 for (i, kb) in self.0.iter().enumerate() {
471 if i > 0 {
472 write!(f, ", {:?}", kb)?;
473 } else {
474 write!(f, "{:?}", kb)?;
475 }
476 }
477 write!(f, "]")?;
478 Ok(())
479 }
480}
481impl KeyBindings {
482 pub fn display(&self, f: &DisplayFormat) -> String {
483 match f {
484 DisplayFormat::Symbols => format!("{}", self),
485 DisplayFormat::Debug => format!("{:?}", self),
486 _ => {
487 let mut display = String::new();
488 for (i, kb) in self.0.iter().enumerate() {
489 if i > 0 {
490 display.push_str(" | ");
491 display.push_str(&kb.display(f));
492 } else {
493 display.push_str(&kb.display(f));
494 }
495 }
496 display
497 }
498 }
499 }
500}
501
502#[cfg(test)]
503mod tests {
504 use super::*;
505
506 #[derive(Serialize, Deserialize)]
507 struct T {
508 kb: KeyBinding,
509 }
510 #[derive(Serialize, Deserialize)]
511 struct U {
512 kbs: KeyBindings,
513 }
514
515 #[test]
516 fn ser_keybinding_config() {
517 let (t_with_ctrl_modifier, t_with_alt_modifier,t, only_modifiers, t_with_esc) = keybinding_configs();
518
519 let serialized = toml::to_string(&t_with_ctrl_modifier).unwrap();
520 assert_eq!(serialized, "kb = \"Control+c\"\n");
521
522 let serialized = toml::to_string(&t_with_alt_modifier).unwrap();
523 assert_eq!(serialized, "kb = \"Alternate+c\"\n");
524
525 let serialized = toml::to_string(&t).unwrap();
526 assert_eq!(serialized, "kb = \"Q\"\n");
527
528 let serialized = toml::to_string(&only_modifiers);
529 assert_eq!(
530 serialized,
531 Err(ser::Error::custom("Unsupported KeyCode: Null"))
532 );
533
534 let serialized = toml::to_string(&t_with_esc).unwrap();
535 assert_eq!(serialized, "kb = \"Esc\"\n");
536 }
537
538 #[test]
539 #[cfg(feature = "case_ignore")]
540 fn deserialize_with_wrong_config() {
541 let desered_t: T = toml::from_str("kb = \"control+c\"\n").unwrap();
542 assert_eq!(desered_t.kb.modifiers, KeyModifiers::CONTROL);
543 }
544
545 #[test]
546 fn de_keybinding_config() {
547 let (t_with_ctrl_modifier, t_with_alt_modifier, t, _only_modifiers, t_with_esc) = keybinding_configs();
548
549 let serialized = toml::to_string(&t_with_ctrl_modifier).unwrap();
550 let desered_t: T = toml::from_str(serialized.as_str()).unwrap();
551 assert_eq!(desered_t.kb.code, t_with_ctrl_modifier.kb.code);
552 assert_eq!(desered_t.kb.modifiers, t_with_ctrl_modifier.kb.modifiers);
553
554 let serialized = toml::to_string(&t_with_alt_modifier).unwrap();
555 let desered_t: T = toml::from_str(serialized.as_str()).unwrap();
556 assert_eq!(desered_t.kb.code, t_with_alt_modifier.kb.code);
557 assert_eq!(desered_t.kb.modifiers, t_with_alt_modifier.kb.modifiers);
558
559 let serialized = toml::to_string(&t).unwrap();
560 let desered_t: T = toml::from_str(serialized.as_str()).unwrap();
561 assert_eq!(desered_t.kb.code, t.kb.code);
562 assert_eq!(desered_t.kb.modifiers, t.kb.modifiers);
563
564 let serialized = toml::to_string(&t_with_esc).unwrap();
565 let desered_t: T = toml::from_str(serialized.as_str()).unwrap();
566 assert_eq!(desered_t.kb.code, t_with_esc.kb.code);
567 assert_eq!(desered_t.kb.modifiers, t_with_esc.kb.modifiers);
568 }
569
570 #[test]
571 fn fmt_keybinding_config() {
572 let (t_with_modifiers, _t_with_alt, _t, _only_modifiers, t_with_esc) = keybinding_configs();
573
574 assert_eq!(format!("{}", t_with_modifiers.kb), "^c");
575 assert_eq!(format!("{}", t_with_esc.kb), "⎋");
576
577 assert_eq!(t_with_modifiers.kb.display(&DisplayFormat::Full), "Control+c");
578 assert_eq!(t_with_modifiers.kb.display(&DisplayFormat::Abbreviation), "Ctrl+c");
579 assert_eq!(t_with_esc.kb.display(&DisplayFormat::Full), "Esc");
580 }
581
582 #[test]
583 fn ser_keybindings_config() {
584 let config = keybindings_config();
585
586 let serialized = toml::to_string(&config).unwrap();
587 assert_eq!(serialized, "kbs = [\"Control+c\", \"Q\"]\n");
588 }
589
590 #[test]
591 fn fmt_keybindings_config() {
592 let config = keybindings_config();
593 assert_eq!(format!("{}", config.kbs), "^c|Q");
594 assert_eq!(config.kbs.display(&DisplayFormat::Full), "Control+c | Q");
595 assert_eq!(config.kbs.display(&DisplayFormat::Abbreviation), "Ctrl+c | Q");
596 }
597
598 fn keybinding_configs() -> (T, T, T, T, T) {
600 (
601 T {
602 kb: KeyBinding {
603 code: KeyCode::Char('c'),
604 modifiers: KeyModifiers::CONTROL,
605 },
606 },
607 T {
608 kb: KeyBinding {
609 code: KeyCode::Char('c'),
610 modifiers: KeyModifiers::ALT,
611 },
612 },
613 T {
614 kb: KeyBinding {
615 code: KeyCode::Char('Q'),
616 modifiers: KeyModifiers::NONE,
617 },
618 },
619 T {
620 kb: KeyBinding {
621 code: KeyCode::Null,
622 modifiers: KeyModifiers::ALT,
623 },
624 },
625 T {
626 kb: KeyBinding {
627 code: KeyCode::Esc,
628 modifiers: KeyModifiers::NONE,
629 },
630 },
631 )
632 }
633
634 fn keybindings_config() -> U {
636 U {
637 kbs: KeyBindings(vec![
638 KeyBinding {
639 code: KeyCode::Char('c'),
640 modifiers: KeyModifiers::CONTROL,
641 },
642 KeyBinding {
643 code: KeyCode::Char('Q'),
644 modifiers: KeyModifiers::NONE,
645 },
646 ]),
647 }
648 }
649}