1#[derive(Debug, Copy, Clone, PartialEq, Eq)]
8pub enum InputState {
9 Normal,
11
12 EscapeStart,
14
15 EscapeSequence,
17}
18
19#[derive(Debug, Copy, Clone, PartialEq, Eq)]
21pub enum InputEvent {
22 None,
24
25 Char(char),
27
28 Backspace,
30
31 Enter,
33
34 Tab,
36
37 UpArrow,
39
40 DownArrow,
42
43 DoubleEsc,
45}
46
47#[derive(Debug)]
50pub struct InputDecoder {
51 state: InputState,
53}
54
55impl InputDecoder {
56 pub fn new() -> Self {
58 Self {
59 state: InputState::Normal,
60 }
61 }
62
63 pub fn decode_char(&mut self, c: char) -> InputEvent {
65 match self.state {
66 InputState::Normal => self.decode_normal(c),
67 InputState::EscapeStart => self.decode_escape_start(c),
68 InputState::EscapeSequence => self.decode_escape_sequence(c),
69 }
70 }
71
72 fn decode_normal(&mut self, c: char) -> InputEvent {
74 match c {
75 '\x1b' => {
77 self.state = InputState::EscapeStart;
78 InputEvent::None
79 }
80
81 '\n' | '\r' => InputEvent::Enter,
83
84 '\t' => InputEvent::Tab,
86
87 '\x08' | '\x7f' => InputEvent::Backspace,
89
90 c if c.is_control() => InputEvent::None,
92
93 _ => InputEvent::Char(c),
95 }
96 }
97
98 fn decode_escape_start(&mut self, c: char) -> InputEvent {
100 match c {
101 '\x1b' => {
103 self.state = InputState::Normal;
104 InputEvent::DoubleEsc
105 }
106
107 '[' => {
109 self.state = InputState::EscapeSequence;
110 InputEvent::None
111 }
112
113 _ => {
116 self.state = InputState::Normal;
117 InputEvent::Char(c)
118 }
119 }
120 }
121
122 fn decode_escape_sequence(&mut self, c: char) -> InputEvent {
124 self.state = InputState::Normal;
126
127 match c {
128 'A' => InputEvent::UpArrow,
130 'B' => InputEvent::DownArrow,
131
132 _ => InputEvent::None,
138 }
139 }
140
141 pub fn reset(&mut self) {
145 self.state = InputState::Normal;
146 }
147
148 #[cfg(test)]
150 pub fn state(&self) -> InputState {
151 self.state
152 }
153}
154
155impl Default for InputDecoder {
156 fn default() -> Self {
157 Self::new()
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
170 fn test_decoder_new() {
171 let decoder = InputDecoder::new();
172 assert_eq!(decoder.state(), InputState::Normal);
173 }
174
175 #[test]
176 fn test_decoder_default() {
177 let decoder = InputDecoder::default();
178 assert_eq!(decoder.state(), InputState::Normal);
179 }
180
181 #[test]
182 fn test_decoder_reset() {
183 let mut decoder = InputDecoder::new();
184 decoder.state = InputState::EscapeStart;
185 decoder.reset();
186 assert_eq!(decoder.state(), InputState::Normal);
187 }
188
189 #[test]
194 fn test_regular_characters() {
195 let mut decoder = InputDecoder::new();
196
197 let event = decoder.decode_char('h');
198 assert_eq!(event, InputEvent::Char('h'));
199
200 let event = decoder.decode_char('i');
201 assert_eq!(event, InputEvent::Char('i'));
202 }
203
204 #[test]
205 fn test_unicode_characters() {
206 let mut decoder = InputDecoder::new();
207
208 let event = decoder.decode_char('ø');
209 assert_eq!(event, InputEvent::Char('ø'));
210
211 let event = decoder.decode_char('£');
212 assert_eq!(event, InputEvent::Char('£'));
213 }
214
215 #[test]
216 fn test_spaces() {
217 let mut decoder = InputDecoder::new();
218
219 let event = decoder.decode_char(' ');
220 assert_eq!(event, InputEvent::Char(' '));
221 }
222
223 #[test]
228 fn test_enter_linefeed() {
229 let mut decoder = InputDecoder::new();
230
231 let event = decoder.decode_char('\n');
232 assert_eq!(event, InputEvent::Enter);
233 }
234
235 #[test]
236 fn test_enter_carriage_return() {
237 let mut decoder = InputDecoder::new();
238
239 let event = decoder.decode_char('\r');
240 assert_eq!(event, InputEvent::Enter);
241 }
242
243 #[test]
244 fn test_tab() {
245 let mut decoder = InputDecoder::new();
246
247 let event = decoder.decode_char('\t');
248 assert_eq!(event, InputEvent::Tab);
249 }
250
251 #[test]
256 fn test_backspace_ascii_bs() {
257 let mut decoder = InputDecoder::new();
258
259 let event = decoder.decode_char('\x08');
260 assert_eq!(event, InputEvent::Backspace);
261 }
262
263 #[test]
264 fn test_backspace_del() {
265 let mut decoder = InputDecoder::new();
266
267 let event = decoder.decode_char('\x7f');
268 assert_eq!(event, InputEvent::Backspace);
269 }
270
271 #[test]
276 fn test_single_esc_no_sequence() {
277 let mut decoder = InputDecoder::new();
278
279 let event = decoder.decode_char('\x1b');
281 assert_eq!(event, InputEvent::None);
282 assert_eq!(decoder.state(), InputState::EscapeStart);
283 }
284
285 #[test]
286 fn test_double_esc() {
287 let mut decoder = InputDecoder::new();
288
289 let event = decoder.decode_char('\x1b');
291 assert_eq!(event, InputEvent::None);
292
293 let event = decoder.decode_char('\x1b');
295 assert_eq!(event, InputEvent::DoubleEsc);
296 assert_eq!(decoder.state(), InputState::Normal);
297 }
298
299 #[test]
300 fn test_esc_bracket_starts_sequence() {
301 let mut decoder = InputDecoder::new();
302
303 decoder.decode_char('\x1b');
305 let event = decoder.decode_char('[');
306
307 assert_eq!(event, InputEvent::None);
308 assert_eq!(decoder.state(), InputState::EscapeSequence);
309 }
310
311 #[test]
312 fn test_up_arrow() {
313 let mut decoder = InputDecoder::new();
314
315 decoder.decode_char('\x1b');
317 decoder.decode_char('[');
318 let event = decoder.decode_char('A');
319
320 assert_eq!(event, InputEvent::UpArrow);
321 assert_eq!(decoder.state(), InputState::Normal);
322 }
323
324 #[test]
325 fn test_down_arrow() {
326 let mut decoder = InputDecoder::new();
327
328 decoder.decode_char('\x1b');
330 decoder.decode_char('[');
331 let event = decoder.decode_char('B');
332
333 assert_eq!(event, InputEvent::DownArrow);
334 assert_eq!(decoder.state(), InputState::Normal);
335 }
336
337 #[test]
338 fn test_unknown_escape_sequence() {
339 let mut decoder = InputDecoder::new();
340
341 decoder.decode_char('\x1b');
343 decoder.decode_char('[');
344 let event = decoder.decode_char('X');
345
346 assert_eq!(event, InputEvent::None);
347 assert_eq!(decoder.state(), InputState::Normal);
348 }
349
350 #[test]
351 fn test_esc_followed_by_regular_char() {
352 let mut decoder = InputDecoder::new();
353
354 decoder.decode_char('\x1b');
356 let event = decoder.decode_char('a');
357
358 assert_eq!(event, InputEvent::Char('a'));
359 assert_eq!(decoder.state(), InputState::Normal);
360 }
361
362 #[test]
367 fn test_control_characters_ignored() {
368 let mut decoder = InputDecoder::new();
369
370 for c in [
372 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
373 ] {
374 let event = decoder.decode_char(c);
375 assert_eq!(event, InputEvent::None);
376 }
377 }
378
379 #[test]
384 fn test_complex_input_sequence() {
385 let mut decoder = InputDecoder::new();
386
387 assert_eq!(decoder.decode_char('h'), InputEvent::Char('h'));
389 assert_eq!(decoder.decode_char('e'), InputEvent::Char('e'));
390 assert_eq!(decoder.decode_char('l'), InputEvent::Char('l'));
391 assert_eq!(decoder.decode_char('l'), InputEvent::Char('l'));
392 assert_eq!(decoder.decode_char('o'), InputEvent::Char('o'));
393
394 assert_eq!(decoder.decode_char('\x7f'), InputEvent::Backspace);
396
397 assert_eq!(decoder.decode_char(' '), InputEvent::Char(' '));
399 assert_eq!(decoder.decode_char('w'), InputEvent::Char('w'));
400 assert_eq!(decoder.decode_char('o'), InputEvent::Char('o'));
401 assert_eq!(decoder.decode_char('r'), InputEvent::Char('r'));
402 assert_eq!(decoder.decode_char('l'), InputEvent::Char('l'));
403 assert_eq!(decoder.decode_char('d'), InputEvent::Char('d'));
404 }
405
406 #[test]
407 fn test_double_esc_then_type() {
408 let mut decoder = InputDecoder::new();
409
410 decoder.decode_char('\x1b');
412 assert_eq!(decoder.decode_char('\x1b'), InputEvent::DoubleEsc);
413
414 assert_eq!(decoder.decode_char('n'), InputEvent::Char('n'));
416 assert_eq!(decoder.decode_char('e'), InputEvent::Char('e'));
417 assert_eq!(decoder.decode_char('w'), InputEvent::Char('w'));
418 }
419
420 #[test]
421 fn test_arrow_keys_sequence() {
422 let mut decoder = InputDecoder::new();
423
424 decoder.decode_char('\x1b');
426 decoder.decode_char('[');
427 assert_eq!(decoder.decode_char('A'), InputEvent::UpArrow);
428
429 decoder.decode_char('\x1b');
431 decoder.decode_char('[');
432 assert_eq!(decoder.decode_char('B'), InputEvent::DownArrow);
433 }
434}