Skip to main content

oo_ide/input/
key.rs

1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2pub enum Key {
3    Char(char),
4    ArrowUp,
5    ArrowDown,
6    ArrowLeft,
7    ArrowRight,
8    F(u8),
9    Enter,
10    Escape,
11    Tab,
12    BackTab,
13    Backspace,
14    Delete,
15    Home,
16    End,
17    PageUp,
18    PageDown,
19}
20
21use crossterm::event::KeyCode;
22
23impl TryFrom<KeyCode> for Key {
24    type Error = ();
25
26    fn try_from(code: KeyCode) -> Result<Self, Self::Error> {
27        Ok(match code {
28            KeyCode::Char(c) => Key::Char(c),
29
30            KeyCode::Up => Key::ArrowUp,
31            KeyCode::Down => Key::ArrowDown,
32            KeyCode::Left => Key::ArrowLeft,
33            KeyCode::Right => Key::ArrowRight,
34
35            KeyCode::Enter => Key::Enter,
36            KeyCode::Esc => Key::Escape,
37            KeyCode::Tab => Key::Tab,
38            KeyCode::BackTab => Key::BackTab,
39            KeyCode::Backspace => Key::Backspace,
40            KeyCode::Delete => Key::Delete,
41            KeyCode::Home => Key::Home,
42            KeyCode::End => Key::End,
43            KeyCode::PageUp => Key::PageUp,
44            KeyCode::PageDown => Key::PageDown,
45
46            KeyCode::F(n) => Key::F(n),
47
48            _ => return Err(()),
49        })
50    }
51}
52use std::fmt;
53
54impl fmt::Display for Key {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        match self {
57            Key::Char(c) => write!(f, "{}", c.to_ascii_lowercase()),
58            Key::ArrowUp => write!(f, "ArrowUp"),
59            Key::ArrowDown => write!(f, "ArrowDown"),
60            Key::ArrowLeft => write!(f, "ArrowLeft"),
61            Key::ArrowRight => write!(f, "ArrowRight"),
62            Key::F(n) => write!(f, "F{}", n),
63            Key::Enter => write!(f, "Enter"),
64            Key::Escape => write!(f, "Escape"),
65            Key::Tab => write!(f, "Tab"),
66            Key::BackTab => write!(f, "BackTab"),
67            Key::Backspace => write!(f, "Backspace"),
68            Key::Delete => write!(f, "Delete"),
69            Key::Home => write!(f, "Home"),
70            Key::End => write!(f, "End"),
71            Key::PageUp => write!(f, "PageUp"),
72            Key::PageDown => write!(f, "PageDown"),
73        }
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    // --- TryFrom<KeyCode> ---
82    #[test]
83    fn try_from_char() {
84        assert_eq!(Key::try_from(KeyCode::Char('a')), Ok(Key::Char('a')));
85    }
86
87    #[test]
88    fn try_from_up() {
89        assert_eq!(Key::try_from(KeyCode::Up), Ok(Key::ArrowUp));
90    }
91
92    #[test]
93    fn try_from_down() {
94        assert_eq!(Key::try_from(KeyCode::Down), Ok(Key::ArrowDown));
95    }
96
97    #[test]
98    fn try_from_left() {
99        assert_eq!(Key::try_from(KeyCode::Left), Ok(Key::ArrowLeft));
100    }
101
102    #[test]
103    fn try_from_right() {
104        assert_eq!(Key::try_from(KeyCode::Right), Ok(Key::ArrowRight));
105    }
106
107    #[test]
108    fn try_from_enter() {
109        assert_eq!(Key::try_from(KeyCode::Enter), Ok(Key::Enter));
110    }
111
112    #[test]
113    fn try_from_escape() {
114        assert_eq!(Key::try_from(KeyCode::Esc), Ok(Key::Escape));
115    }
116
117    #[test]
118    fn try_from_tab() {
119        assert_eq!(Key::try_from(KeyCode::Tab), Ok(Key::Tab));
120    }
121
122    #[test]
123    fn try_from_backtab() {
124        assert_eq!(Key::try_from(KeyCode::BackTab), Ok(Key::BackTab));
125    }
126
127    #[test]
128    fn try_from_backspace() {
129        assert_eq!(Key::try_from(KeyCode::Backspace), Ok(Key::Backspace));
130    }
131
132    #[test]
133    fn try_from_delete() {
134        assert_eq!(Key::try_from(KeyCode::Delete), Ok(Key::Delete));
135    }
136
137    #[test]
138    fn try_from_home() {
139        assert_eq!(Key::try_from(KeyCode::Home), Ok(Key::Home));
140    }
141
142    #[test]
143    fn try_from_end() {
144        assert_eq!(Key::try_from(KeyCode::End), Ok(Key::End));
145    }
146
147    #[test]
148    fn try_from_page_up() {
149        assert_eq!(Key::try_from(KeyCode::PageUp), Ok(Key::PageUp));
150    }
151
152    #[test]
153    fn try_from_page_down() {
154        assert_eq!(Key::try_from(KeyCode::PageDown), Ok(Key::PageDown));
155    }
156
157    #[test]
158    fn try_from_f_key() {
159        assert_eq!(Key::try_from(KeyCode::F(1)), Ok(Key::F(1)));
160    }
161
162    #[test]
163    fn try_from_f_key_12() {
164        assert_eq!(Key::try_from(KeyCode::F(12)), Ok(Key::F(12)));
165    }
166
167    #[test]
168    fn try_from_null_is_err() {
169        assert!(Key::try_from(KeyCode::Null).is_err());
170    }
171
172    // --- Display ---
173    #[test]
174    fn display_char_uppercase_lowercased() {
175        assert_eq!(Key::Char('A').to_string(), "a");
176    }
177
178    #[test]
179    fn display_char_already_lower() {
180        assert_eq!(Key::Char('z').to_string(), "z");
181    }
182
183    #[test]
184    fn display_char_digit() {
185        assert_eq!(Key::Char('5').to_string(), "5");
186    }
187
188    #[test]
189    fn display_arrow_up() {
190        assert_eq!(Key::ArrowUp.to_string(), "ArrowUp");
191    }
192
193    #[test]
194    fn display_arrow_down() {
195        assert_eq!(Key::ArrowDown.to_string(), "ArrowDown");
196    }
197
198    #[test]
199    fn display_arrow_left() {
200        assert_eq!(Key::ArrowLeft.to_string(), "ArrowLeft");
201    }
202
203    #[test]
204    fn display_arrow_right() {
205        assert_eq!(Key::ArrowRight.to_string(), "ArrowRight");
206    }
207
208    #[test]
209    fn display_enter() {
210        assert_eq!(Key::Enter.to_string(), "Enter");
211    }
212
213    #[test]
214    fn display_escape() {
215        assert_eq!(Key::Escape.to_string(), "Escape");
216    }
217
218    #[test]
219    fn display_tab() {
220        assert_eq!(Key::Tab.to_string(), "Tab");
221    }
222
223    #[test]
224    fn display_backtab() {
225        assert_eq!(Key::BackTab.to_string(), "BackTab");
226    }
227
228    #[test]
229    fn display_backspace() {
230        assert_eq!(Key::Backspace.to_string(), "Backspace");
231    }
232
233    #[test]
234    fn display_delete() {
235        assert_eq!(Key::Delete.to_string(), "Delete");
236    }
237
238    #[test]
239    fn display_home() {
240        assert_eq!(Key::Home.to_string(), "Home");
241    }
242
243    #[test]
244    fn display_end() {
245        assert_eq!(Key::End.to_string(), "End");
246    }
247
248    #[test]
249    fn display_page_up() {
250        assert_eq!(Key::PageUp.to_string(), "PageUp");
251    }
252
253    #[test]
254    fn display_page_down() {
255        assert_eq!(Key::PageDown.to_string(), "PageDown");
256    }
257
258    #[test]
259    fn display_f_key() {
260        assert_eq!(Key::F(12).to_string(), "F12");
261    }
262
263    // --- Derived trait smoke tests ---
264    #[test]
265    fn key_clone_eq() {
266        assert_eq!(Key::Enter.clone(), Key::Enter);
267    }
268
269    #[test]
270    fn key_ne() {
271        assert_ne!(Key::Enter, Key::Escape);
272    }
273
274    #[test]
275    fn key_hash() {
276        use std::collections::HashSet;
277        let mut s = HashSet::new();
278        s.insert(Key::Char('a'));
279        assert!(s.contains(&Key::Char('a')));
280        assert!(!s.contains(&Key::Char('b')));
281    }
282}