1use serde::{Deserialize, Serialize};
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "snake_case")]
13pub enum Key {
14 Enter,
15 Tab,
16 Escape,
17 Up,
18 Down,
19 Left,
20 Right,
21 Home,
22 End,
23 PageUp,
24 PageDown,
25 Backspace,
26 CtrlC,
27 CtrlD,
28 CtrlZ,
29 CtrlL,
30}
31
32impl Key {
33 pub const fn bytes(self) -> &'static [u8] {
35 match self {
36 Self::Enter => b"\r",
37 Self::Tab => b"\t",
38 Self::Escape => b"\x1b",
39 Self::Up => b"\x1b[A",
40 Self::Down => b"\x1b[B",
41 Self::Right => b"\x1b[C",
42 Self::Left => b"\x1b[D",
43 Self::Home => b"\x1b[H",
44 Self::End => b"\x1b[F",
45 Self::PageUp => b"\x1b[5~",
46 Self::PageDown => b"\x1b[6~",
47 Self::Backspace => b"\x7f",
48 Self::CtrlC => b"\x03",
49 Self::CtrlD => b"\x04",
50 Self::CtrlZ => b"\x1a",
51 Self::CtrlL => b"\x0c",
52 }
53 }
54
55 pub fn parse(name: &str) -> Option<Self> {
57 Some(match name {
58 "enter" => Self::Enter,
59 "tab" => Self::Tab,
60 "escape" => Self::Escape,
61 "up" => Self::Up,
62 "down" => Self::Down,
63 "left" => Self::Left,
64 "right" => Self::Right,
65 "home" => Self::Home,
66 "end" => Self::End,
67 "page_up" => Self::PageUp,
68 "page_down" => Self::PageDown,
69 "backspace" => Self::Backspace,
70 "ctrl_c" => Self::CtrlC,
71 "ctrl_d" => Self::CtrlD,
72 "ctrl_z" => Self::CtrlZ,
73 "ctrl_l" => Self::CtrlL,
74 _ => return None,
75 })
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
87 fn enter_is_a_carriage_return() {
88 assert_eq!(Key::Enter.bytes(), b"\r");
89 assert_ne!(Key::Enter.bytes(), b"\n");
90 }
91
92 #[test]
95 fn the_control_keys_are_their_own_bytes() {
96 assert_eq!(Key::CtrlC.bytes(), b"\x03");
97 assert_eq!(Key::CtrlD.bytes(), b"\x04");
98 assert_eq!(Key::CtrlZ.bytes(), b"\x1a");
99 assert_eq!(Key::CtrlL.bytes(), b"\x0c");
100 }
101
102 #[test]
105 fn every_wire_spelling_parses() {
106 for (name, key) in [
107 ("enter", Key::Enter),
108 ("tab", Key::Tab),
109 ("escape", Key::Escape),
110 ("up", Key::Up),
111 ("down", Key::Down),
112 ("left", Key::Left),
113 ("right", Key::Right),
114 ("home", Key::Home),
115 ("end", Key::End),
116 ("page_up", Key::PageUp),
117 ("page_down", Key::PageDown),
118 ("backspace", Key::Backspace),
119 ("ctrl_c", Key::CtrlC),
120 ("ctrl_d", Key::CtrlD),
121 ("ctrl_z", Key::CtrlZ),
122 ("ctrl_l", Key::CtrlL),
123 ] {
124 assert_eq!(Key::parse(name), Some(key), "{name}");
125 }
126 assert_eq!(Key::parse("ctrl_q"), None, "an unknown key is refused");
127 }
128}