1 use std::io;
2
3 use crate::{
4 event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind},
5 ErrorKind, Result,
6 };
7
8 use super::super::super::InternalEvent;
9
10 // Event parsing
11 //
12 // This code (& previous one) are kind of ugly. We have to think about this,
13 // because it's really not maintainable, no tests, etc.
14 //
15 // Every fn returns Result<Option<InputEvent>>
16 //
17 // Ok(None) -> wait for more bytes
18 // Err(_) -> failed to parse event, clear the buffer
19 // Ok(Some(event)) -> we have event, clear the buffer
20 //
21
could_not_parse_event_error() -> ErrorKind22 fn could_not_parse_event_error() -> ErrorKind {
23 io::Error::new(io::ErrorKind::Other, "Could not parse an event.")
24 }
25
parse_event(buffer: &[u8], input_available: bool) -> Result<Option<InternalEvent>>26 pub(crate) fn parse_event(buffer: &[u8], input_available: bool) -> Result<Option<InternalEvent>> {
27 if buffer.is_empty() {
28 return Ok(None);
29 }
30
31 match buffer[0] {
32 b'\x1B' => {
33 if buffer.len() == 1 {
34 if input_available {
35 // Possible Esc sequence
36 Ok(None)
37 } else {
38 Ok(Some(InternalEvent::Event(Event::Key(KeyCode::Esc.into()))))
39 }
40 } else {
41 match buffer[1] {
42 b'O' => {
43 if buffer.len() == 2 {
44 Ok(None)
45 } else {
46 match buffer[2] {
47 // F1-F4
48 val @ b'P'..=b'S' => Ok(Some(InternalEvent::Event(Event::Key(
49 KeyCode::F(1 + val - b'P').into(),
50 )))),
51 _ => Err(could_not_parse_event_error()),
52 }
53 }
54 }
55 b'[' => parse_csi(buffer),
56 b'\x1B' => Ok(Some(InternalEvent::Event(Event::Key(KeyCode::Esc.into())))),
57 _ => parse_event(&buffer[1..], input_available).map(|event_option| {
58 event_option.map(|event| {
59 if let InternalEvent::Event(Event::Key(key_event)) = event {
60 let mut alt_key_event = key_event;
61 alt_key_event.modifiers |= KeyModifiers::ALT;
62 InternalEvent::Event(Event::Key(alt_key_event))
63 } else {
64 event
65 }
66 })
67 }),
68 }
69 }
70 }
71 b'\r' => Ok(Some(InternalEvent::Event(Event::Key(
72 KeyCode::Enter.into(),
73 )))),
74 // Issue #371: \n = 0xA, which is also the keycode for Ctrl+J. The only reason we get
75 // newlines as input is because the terminal converts \r into \n for us. When we
76 // enter raw mode, we disable that, so \n no longer has any meaning - it's better to
77 // use Ctrl+J. Waiting to handle it here means it gets picked up later
78 b'\n' if !crate::terminal::sys::is_raw_mode_enabled() => Ok(Some(InternalEvent::Event(
79 Event::Key(KeyCode::Enter.into()),
80 ))),
81 b'\t' => Ok(Some(InternalEvent::Event(Event::Key(KeyCode::Tab.into())))),
82 b'\x7F' => Ok(Some(InternalEvent::Event(Event::Key(
83 KeyCode::Backspace.into(),
84 )))),
85 c @ b'\x01'..=b'\x1A' => Ok(Some(InternalEvent::Event(Event::Key(KeyEvent::new(
86 KeyCode::Char((c as u8 - 0x1 + b'a') as char),
87 KeyModifiers::CONTROL,
88 ))))),
89 c @ b'\x1C'..=b'\x1F' => Ok(Some(InternalEvent::Event(Event::Key(KeyEvent::new(
90 KeyCode::Char((c as u8 - 0x1C + b'4') as char),
91 KeyModifiers::CONTROL,
92 ))))),
93 b'\0' => Ok(Some(InternalEvent::Event(Event::Key(KeyEvent::new(
94 KeyCode::Char(' '),
95 KeyModifiers::CONTROL,
96 ))))),
97 _ => parse_utf8_char(buffer).map(|maybe_char| {
98 maybe_char
99 .map(KeyCode::Char)
100 .map(char_code_to_event)
101 .map(Event::Key)
102 .map(InternalEvent::Event)
103 }),
104 }
105 }
106
107 // converts KeyCode to KeyEvent (adds shift modifier in case of uppercase characters)
char_code_to_event(code: KeyCode) -> KeyEvent108 fn char_code_to_event(code: KeyCode) -> KeyEvent {
109 let modifiers = match code {
110 KeyCode::Char(c) if c.is_uppercase() => KeyModifiers::SHIFT,
111 _ => KeyModifiers::empty(),
112 };
113 KeyEvent::new(code, modifiers)
114 }
115
parse_csi(buffer: &[u8]) -> Result<Option<InternalEvent>>116 pub(crate) fn parse_csi(buffer: &[u8]) -> Result<Option<InternalEvent>> {
117 assert!(buffer.starts_with(&[b'\x1B', b'['])); // ESC [
118
119 if buffer.len() == 2 {
120 return Ok(None);
121 }
122
123 let input_event = match buffer[2] {
124 b'[' => {
125 if buffer.len() == 3 {
126 None
127 } else {
128 match buffer[3] {
129 // NOTE (@imdaveho): cannot find when this occurs;
130 // having another '[' after ESC[ not a likely scenario
131 val @ b'A'..=b'E' => Some(Event::Key(KeyCode::F(1 + val - b'A').into())),
132 _ => return Err(could_not_parse_event_error()),
133 }
134 }
135 }
136 b'D' => Some(Event::Key(KeyCode::Left.into())),
137 b'C' => Some(Event::Key(KeyCode::Right.into())),
138 b'A' => Some(Event::Key(KeyCode::Up.into())),
139 b'B' => Some(Event::Key(KeyCode::Down.into())),
140 b'H' => Some(Event::Key(KeyCode::Home.into())),
141 b'F' => Some(Event::Key(KeyCode::End.into())),
142 b'Z' => Some(Event::Key(KeyEvent {
143 code: KeyCode::BackTab,
144 modifiers: KeyModifiers::SHIFT,
145 })),
146 b'M' => return parse_csi_normal_mouse(buffer),
147 b'<' => return parse_csi_sgr_mouse(buffer),
148 b'0'..=b'9' => {
149 // Numbered escape code.
150 if buffer.len() == 3 {
151 None
152 } else {
153 // The final byte of a CSI sequence can be in the range 64-126, so
154 // let's keep reading anything else.
155 let last_byte = *buffer.last().unwrap();
156 if !(64..=126).contains(&last_byte) {
157 None
158 } else {
159 match buffer[buffer.len() - 1] {
160 b'M' => return parse_csi_rxvt_mouse(buffer),
161 b'~' => return parse_csi_special_key_code(buffer),
162 b'R' => return parse_csi_cursor_position(buffer),
163 _ => return parse_csi_modifier_key_code(buffer),
164 }
165 }
166 }
167 }
168 _ => return Err(could_not_parse_event_error()),
169 };
170
171 Ok(input_event.map(InternalEvent::Event))
172 }
173
next_parsed<T>(iter: &mut dyn Iterator<Item = &str>) -> Result<T> where T: std::str::FromStr,174 pub(crate) fn next_parsed<T>(iter: &mut dyn Iterator<Item = &str>) -> Result<T>
175 where
176 T: std::str::FromStr,
177 {
178 iter.next()
179 .ok_or_else(could_not_parse_event_error)?
180 .parse::<T>()
181 .map_err(|_| could_not_parse_event_error())
182 }
183
parse_csi_cursor_position(buffer: &[u8]) -> Result<Option<InternalEvent>>184 pub(crate) fn parse_csi_cursor_position(buffer: &[u8]) -> Result<Option<InternalEvent>> {
185 // ESC [ Cy ; Cx R
186 // Cy - cursor row number (starting from 1)
187 // Cx - cursor column number (starting from 1)
188 assert!(buffer.starts_with(&[b'\x1B', b'['])); // ESC [
189 assert!(buffer.ends_with(&[b'R']));
190
191 let s = std::str::from_utf8(&buffer[2..buffer.len() - 1])
192 .map_err(|_| could_not_parse_event_error())?;
193
194 let mut split = s.split(';');
195
196 let y = next_parsed::<u16>(&mut split)? - 1;
197 let x = next_parsed::<u16>(&mut split)? - 1;
198
199 Ok(Some(InternalEvent::CursorPosition(x, y)))
200 }
201
parse_modifiers(mask: u8) -> KeyModifiers202 fn parse_modifiers(mask: u8) -> KeyModifiers {
203 let modifier_mask = mask.saturating_sub(1);
204 let mut modifiers = KeyModifiers::empty();
205 if modifier_mask & 1 != 0 {
206 modifiers |= KeyModifiers::SHIFT;
207 }
208 if modifier_mask & 2 != 0 {
209 modifiers |= KeyModifiers::ALT;
210 }
211 if modifier_mask & 4 != 0 {
212 modifiers |= KeyModifiers::CONTROL;
213 }
214 modifiers
215 }
216
parse_csi_modifier_key_code(buffer: &[u8]) -> Result<Option<InternalEvent>>217 pub(crate) fn parse_csi_modifier_key_code(buffer: &[u8]) -> Result<Option<InternalEvent>> {
218 assert!(buffer.starts_with(&[b'\x1B', b'['])); // ESC [
219
220 let modifier_mask = buffer[buffer.len() - 2];
221 let key = buffer[buffer.len() - 1];
222
223 let modifiers = parse_modifiers(modifier_mask);
224
225 let keycode = match key {
226 b'A' => KeyCode::Up,
227 b'B' => KeyCode::Down,
228 b'C' => KeyCode::Right,
229 b'D' => KeyCode::Left,
230 b'F' => KeyCode::End,
231 b'H' => KeyCode::Home,
232 b'P' => KeyCode::F(1),
233 b'Q' => KeyCode::F(2),
234 b'R' => KeyCode::F(3),
235 b'S' => KeyCode::F(4),
236 _ => return Err(could_not_parse_event_error()),
237 };
238
239 let input_event = Event::Key(KeyEvent::new(keycode, modifiers));
240
241 Ok(Some(InternalEvent::Event(input_event)))
242 }
243
parse_csi_special_key_code(buffer: &[u8]) -> Result<Option<InternalEvent>>244 pub(crate) fn parse_csi_special_key_code(buffer: &[u8]) -> Result<Option<InternalEvent>> {
245 assert!(buffer.starts_with(&[b'\x1B', b'['])); // ESC [
246 assert!(buffer.ends_with(&[b'~']));
247
248 let s = std::str::from_utf8(&buffer[2..buffer.len() - 1])
249 .map_err(|_| could_not_parse_event_error())?;
250 let mut split = s.split(';');
251
252 // This CSI sequence can be a list of semicolon-separated numbers.
253 let first = next_parsed::<u8>(&mut split)?;
254
255 let modifiers = if let Ok(modifier_mask) = next_parsed::<u8>(&mut split) {
256 parse_modifiers(modifier_mask)
257 } else {
258 KeyModifiers::NONE
259 };
260
261 let keycode = match first {
262 1 | 7 => KeyCode::Home,
263 2 => KeyCode::Insert,
264 3 => KeyCode::Delete,
265 4 | 8 => KeyCode::End,
266 5 => KeyCode::PageUp,
267 6 => KeyCode::PageDown,
268 v @ 11..=15 => KeyCode::F(v - 10),
269 v @ 17..=21 => KeyCode::F(v - 11),
270 v @ 23..=26 => KeyCode::F(v - 12),
271 v @ 28..=29 => KeyCode::F(v - 15),
272 v @ 31..=34 => KeyCode::F(v - 17),
273 _ => return Err(could_not_parse_event_error()),
274 };
275
276 let input_event = Event::Key(KeyEvent::new(keycode, modifiers));
277
278 Ok(Some(InternalEvent::Event(input_event)))
279 }
280
parse_csi_rxvt_mouse(buffer: &[u8]) -> Result<Option<InternalEvent>>281 pub(crate) fn parse_csi_rxvt_mouse(buffer: &[u8]) -> Result<Option<InternalEvent>> {
282 // rxvt mouse encoding:
283 // ESC [ Cb ; Cx ; Cy ; M
284
285 assert!(buffer.starts_with(&[b'\x1B', b'['])); // ESC [
286 assert!(buffer.ends_with(&[b'M']));
287
288 let s = std::str::from_utf8(&buffer[2..buffer.len() - 1])
289 .map_err(|_| could_not_parse_event_error())?;
290 let mut split = s.split(';');
291
292 let cb = next_parsed::<u8>(&mut split)?
293 .checked_sub(32)
294 .ok_or_else(could_not_parse_event_error)?;
295 let (kind, modifiers) = parse_cb(cb)?;
296
297 let cx = next_parsed::<u16>(&mut split)? - 1;
298 let cy = next_parsed::<u16>(&mut split)? - 1;
299
300 Ok(Some(InternalEvent::Event(Event::Mouse(MouseEvent {
301 kind,
302 column: cx,
303 row: cy,
304 modifiers,
305 }))))
306 }
307
parse_csi_normal_mouse(buffer: &[u8]) -> Result<Option<InternalEvent>>308 pub(crate) fn parse_csi_normal_mouse(buffer: &[u8]) -> Result<Option<InternalEvent>> {
309 // Normal mouse encoding: ESC [ M CB Cx Cy (6 characters only).
310
311 assert!(buffer.starts_with(&[b'\x1B', b'[', b'M'])); // ESC [ M
312
313 if buffer.len() < 6 {
314 return Ok(None);
315 }
316
317 let cb = buffer[3]
318 .checked_sub(32)
319 .ok_or_else(could_not_parse_event_error)?;
320 let (kind, modifiers) = parse_cb(cb)?;
321
322 // See http://www.xfree86.org/current/ctlseqs.html#Mouse%20Tracking
323 // The upper left character position on the terminal is denoted as 1,1.
324 // Subtract 1 to keep it synced with cursor
325 let cx = u16::from(buffer[4].saturating_sub(32)) - 1;
326 let cy = u16::from(buffer[5].saturating_sub(32)) - 1;
327
328 Ok(Some(InternalEvent::Event(Event::Mouse(MouseEvent {
329 kind,
330 column: cx,
331 row: cy,
332 modifiers,
333 }))))
334 }
335
parse_csi_sgr_mouse(buffer: &[u8]) -> Result<Option<InternalEvent>>336 pub(crate) fn parse_csi_sgr_mouse(buffer: &[u8]) -> Result<Option<InternalEvent>> {
337 // ESC [ < Cb ; Cx ; Cy (;) (M or m)
338
339 assert!(buffer.starts_with(&[b'\x1B', b'[', b'<'])); // ESC [ <
340
341 if !buffer.ends_with(&[b'm']) && !buffer.ends_with(&[b'M']) {
342 return Ok(None);
343 }
344
345 let s = std::str::from_utf8(&buffer[3..buffer.len() - 1])
346 .map_err(|_| could_not_parse_event_error())?;
347 let mut split = s.split(';');
348
349 let cb = next_parsed::<u8>(&mut split)?;
350 let (kind, modifiers) = parse_cb(cb)?;
351
352 // See http://www.xfree86.org/current/ctlseqs.html#Mouse%20Tracking
353 // The upper left character position on the terminal is denoted as 1,1.
354 // Subtract 1 to keep it synced with cursor
355 let cx = next_parsed::<u16>(&mut split)? - 1;
356 let cy = next_parsed::<u16>(&mut split)? - 1;
357
358 // When button 3 in Cb is used to represent mouse release, you can't tell which button was
359 // released. SGR mode solves this by having the sequence end with a lowercase m if it's a
360 // button release and an uppercase M if it's a buton press.
361 //
362 // We've already checked that the last character is a lowercase or uppercase M at the start of
363 // this function, so we just need one if.
364 let kind = if buffer.last() == Some(&b'm') {
365 match kind {
366 MouseEventKind::Down(button) => MouseEventKind::Up(button),
367 other => other,
368 }
369 } else {
370 kind
371 };
372
373 Ok(Some(InternalEvent::Event(Event::Mouse(MouseEvent {
374 kind,
375 column: cx,
376 row: cy,
377 modifiers,
378 }))))
379 }
380
381 /// Cb is the byte of a mouse input that contains the button being used, the key modifiers being
382 /// held and whether the mouse is dragging or not.
383 ///
384 /// Bit layout of cb, from low to high:
385 ///
386 /// - button number
387 /// - button number
388 /// - shift
389 /// - meta (alt)
390 /// - control
391 /// - mouse is dragging
392 /// - button number
393 /// - button number
parse_cb(cb: u8) -> Result<(MouseEventKind, KeyModifiers)>394 fn parse_cb(cb: u8) -> Result<(MouseEventKind, KeyModifiers)> {
395 let button_number = (cb & 0b0000_0011) | ((cb & 0b1100_0000) >> 4);
396 let dragging = cb & 0b0010_0000 == 0b0010_0000;
397
398 let kind = match (button_number, dragging) {
399 (0, false) => MouseEventKind::Down(MouseButton::Left),
400 (1, false) => MouseEventKind::Down(MouseButton::Middle),
401 (2, false) => MouseEventKind::Down(MouseButton::Right),
402 (0, true) => MouseEventKind::Drag(MouseButton::Left),
403 (1, true) => MouseEventKind::Drag(MouseButton::Middle),
404 (2, true) => MouseEventKind::Drag(MouseButton::Right),
405 (3, false) => MouseEventKind::Up(MouseButton::Left),
406 (3, true) | (4, true) | (5, true) => MouseEventKind::Moved,
407 (4, false) => MouseEventKind::ScrollUp,
408 (5, false) => MouseEventKind::ScrollDown,
409 // We do not support other buttons.
410 _ => return Err(could_not_parse_event_error()),
411 };
412
413 let mut modifiers = KeyModifiers::empty();
414
415 if cb & 0b0000_0100 == 0b0000_0100 {
416 modifiers |= KeyModifiers::SHIFT;
417 }
418 if cb & 0b0000_1000 == 0b0000_1000 {
419 modifiers |= KeyModifiers::ALT;
420 }
421 if cb & 0b0001_0000 == 0b0001_0000 {
422 modifiers |= KeyModifiers::CONTROL;
423 }
424
425 Ok((kind, modifiers))
426 }
427
parse_utf8_char(buffer: &[u8]) -> Result<Option<char>>428 pub(crate) fn parse_utf8_char(buffer: &[u8]) -> Result<Option<char>> {
429 match std::str::from_utf8(buffer) {
430 Ok(s) => {
431 let ch = s.chars().next().ok_or_else(could_not_parse_event_error)?;
432
433 Ok(Some(ch))
434 }
435 Err(_) => {
436 // from_utf8 failed, but we have to check if we need more bytes for code point
437 // and if all the bytes we have no are valid
438
439 let required_bytes = match buffer[0] {
440 // https://en.wikipedia.org/wiki/UTF-8#Description
441 (0x00..=0x7F) => 1, // 0xxxxxxx
442 (0xC0..=0xDF) => 2, // 110xxxxx 10xxxxxx
443 (0xE0..=0xEF) => 3, // 1110xxxx 10xxxxxx 10xxxxxx
444 (0xF0..=0xF7) => 4, // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
445 (0x80..=0xBF) | (0xF8..=0xFF) => return Err(could_not_parse_event_error()),
446 };
447
448 // More than 1 byte, check them for 10xxxxxx pattern
449 if required_bytes > 1 && buffer.len() > 1 {
450 for byte in &buffer[1..] {
451 if byte & !0b0011_1111 != 0b1000_0000 {
452 return Err(could_not_parse_event_error());
453 }
454 }
455 }
456
457 if buffer.len() < required_bytes {
458 // All bytes looks good so far, but we need more of them
459 Ok(None)
460 } else {
461 Err(could_not_parse_event_error())
462 }
463 }
464 }
465 }
466
467 #[cfg(test)]
468 mod tests {
469 use crate::event::{KeyModifiers, MouseButton, MouseEvent};
470
471 use super::*;
472
473 #[test]
test_esc_key()474 fn test_esc_key() {
475 assert_eq!(
476 parse_event(b"\x1B", false).unwrap(),
477 Some(InternalEvent::Event(Event::Key(KeyCode::Esc.into()))),
478 );
479 }
480
481 #[test]
test_possible_esc_sequence()482 fn test_possible_esc_sequence() {
483 assert_eq!(parse_event(b"\x1B", true).unwrap(), None,);
484 }
485
486 #[test]
test_alt_key()487 fn test_alt_key() {
488 assert_eq!(
489 parse_event(b"\x1Bc", false).unwrap(),
490 Some(InternalEvent::Event(Event::Key(KeyEvent::new(
491 KeyCode::Char('c'),
492 KeyModifiers::ALT
493 )))),
494 );
495 }
496
497 #[test]
test_alt_shift()498 fn test_alt_shift() {
499 assert_eq!(
500 parse_event(b"\x1BH", false).unwrap(),
501 Some(InternalEvent::Event(Event::Key(KeyEvent::new(
502 KeyCode::Char('H'),
503 KeyModifiers::ALT | KeyModifiers::SHIFT
504 )))),
505 );
506 }
507
508 #[test]
test_alt_ctrl()509 fn test_alt_ctrl() {
510 assert_eq!(
511 parse_event(b"\x1B\x14", false).unwrap(),
512 Some(InternalEvent::Event(Event::Key(KeyEvent::new(
513 KeyCode::Char('t'),
514 KeyModifiers::ALT | KeyModifiers::CONTROL
515 )))),
516 );
517 }
518
519 #[test]
test_parse_event_subsequent_calls()520 fn test_parse_event_subsequent_calls() {
521 // The main purpose of this test is to check if we're passing
522 // correct slice to other parse_ functions.
523
524 // parse_csi_cursor_position
525 assert_eq!(
526 parse_event(b"\x1B[20;10R", false).unwrap(),
527 Some(InternalEvent::CursorPosition(9, 19))
528 );
529
530 // parse_csi
531 assert_eq!(
532 parse_event(b"\x1B[D", false).unwrap(),
533 Some(InternalEvent::Event(Event::Key(KeyCode::Left.into()))),
534 );
535
536 // parse_csi_modifier_key_code
537 assert_eq!(
538 parse_event(b"\x1B[2D", false).unwrap(),
539 Some(InternalEvent::Event(Event::Key(KeyEvent::new(
540 KeyCode::Left,
541 KeyModifiers::SHIFT
542 ))))
543 );
544
545 // parse_csi_special_key_code
546 assert_eq!(
547 parse_event(b"\x1B[3~", false).unwrap(),
548 Some(InternalEvent::Event(Event::Key(KeyCode::Delete.into()))),
549 );
550
551 // parse_csi_rxvt_mouse
552 assert_eq!(
553 parse_event(b"\x1B[32;30;40;M", false).unwrap(),
554 Some(InternalEvent::Event(Event::Mouse(MouseEvent {
555 kind: MouseEventKind::Down(MouseButton::Left),
556 column: 29,
557 row: 39,
558 modifiers: KeyModifiers::empty(),
559 })))
560 );
561
562 // parse_csi_normal_mouse
563 assert_eq!(
564 parse_event(b"\x1B[M0\x60\x70", false).unwrap(),
565 Some(InternalEvent::Event(Event::Mouse(MouseEvent {
566 kind: MouseEventKind::Down(MouseButton::Left),
567 column: 63,
568 row: 79,
569 modifiers: KeyModifiers::CONTROL,
570 })))
571 );
572
573 // parse_csi_sgr_mouse
574 assert_eq!(
575 parse_event(b"\x1B[<0;20;10;M", false).unwrap(),
576 Some(InternalEvent::Event(Event::Mouse(MouseEvent {
577 kind: MouseEventKind::Down(MouseButton::Left),
578 column: 19,
579 row: 9,
580 modifiers: KeyModifiers::empty(),
581 })))
582 );
583
584 // parse_utf8_char
585 assert_eq!(
586 parse_event("Ž".as_bytes(), false).unwrap(),
587 Some(InternalEvent::Event(Event::Key(KeyEvent::new(
588 KeyCode::Char('Ž'),
589 KeyModifiers::SHIFT
590 )))),
591 );
592 }
593
594 #[test]
test_parse_event()595 fn test_parse_event() {
596 assert_eq!(
597 parse_event(b"\t", false).unwrap(),
598 Some(InternalEvent::Event(Event::Key(KeyCode::Tab.into()))),
599 );
600 }
601
602 #[test]
test_parse_csi_cursor_position()603 fn test_parse_csi_cursor_position() {
604 assert_eq!(
605 parse_csi_cursor_position(b"\x1B[20;10R").unwrap(),
606 Some(InternalEvent::CursorPosition(9, 19))
607 );
608 }
609
610 #[test]
test_parse_csi()611 fn test_parse_csi() {
612 assert_eq!(
613 parse_csi(b"\x1B[D").unwrap(),
614 Some(InternalEvent::Event(Event::Key(KeyCode::Left.into()))),
615 );
616 }
617
618 #[test]
test_parse_csi_modifier_key_code()619 fn test_parse_csi_modifier_key_code() {
620 assert_eq!(
621 parse_csi_modifier_key_code(b"\x1B[2D").unwrap(),
622 Some(InternalEvent::Event(Event::Key(KeyEvent::new(
623 KeyCode::Left,
624 KeyModifiers::SHIFT
625 )))),
626 );
627 }
628
629 #[test]
test_parse_csi_special_key_code()630 fn test_parse_csi_special_key_code() {
631 assert_eq!(
632 parse_csi_special_key_code(b"\x1B[3~").unwrap(),
633 Some(InternalEvent::Event(Event::Key(KeyCode::Delete.into()))),
634 );
635 }
636
637 #[test]
test_parse_csi_special_key_code_multiple_values_not_supported()638 fn test_parse_csi_special_key_code_multiple_values_not_supported() {
639 assert_eq!(
640 parse_csi_special_key_code(b"\x1B[3;2~").unwrap(),
641 Some(InternalEvent::Event(Event::Key(KeyEvent::new(
642 KeyCode::Delete,
643 KeyModifiers::SHIFT
644 )))),
645 );
646 }
647
648 #[test]
test_parse_csi_rxvt_mouse()649 fn test_parse_csi_rxvt_mouse() {
650 assert_eq!(
651 parse_csi_rxvt_mouse(b"\x1B[32;30;40;M").unwrap(),
652 Some(InternalEvent::Event(Event::Mouse(MouseEvent {
653 kind: MouseEventKind::Down(MouseButton::Left),
654 column: 29,
655 row: 39,
656 modifiers: KeyModifiers::empty(),
657 })))
658 );
659 }
660
661 #[test]
test_parse_csi_normal_mouse()662 fn test_parse_csi_normal_mouse() {
663 assert_eq!(
664 parse_csi_normal_mouse(b"\x1B[M0\x60\x70").unwrap(),
665 Some(InternalEvent::Event(Event::Mouse(MouseEvent {
666 kind: MouseEventKind::Down(MouseButton::Left),
667 column: 63,
668 row: 79,
669 modifiers: KeyModifiers::CONTROL,
670 })))
671 );
672 }
673
674 #[test]
test_parse_csi_sgr_mouse()675 fn test_parse_csi_sgr_mouse() {
676 assert_eq!(
677 parse_csi_sgr_mouse(b"\x1B[<0;20;10;M").unwrap(),
678 Some(InternalEvent::Event(Event::Mouse(MouseEvent {
679 kind: MouseEventKind::Down(MouseButton::Left),
680 column: 19,
681 row: 9,
682 modifiers: KeyModifiers::empty(),
683 })))
684 );
685 assert_eq!(
686 parse_csi_sgr_mouse(b"\x1B[<0;20;10M").unwrap(),
687 Some(InternalEvent::Event(Event::Mouse(MouseEvent {
688 kind: MouseEventKind::Down(MouseButton::Left),
689 column: 19,
690 row: 9,
691 modifiers: KeyModifiers::empty(),
692 })))
693 );
694 assert_eq!(
695 parse_csi_sgr_mouse(b"\x1B[<0;20;10;m").unwrap(),
696 Some(InternalEvent::Event(Event::Mouse(MouseEvent {
697 kind: MouseEventKind::Up(MouseButton::Left),
698 column: 19,
699 row: 9,
700 modifiers: KeyModifiers::empty(),
701 })))
702 );
703 assert_eq!(
704 parse_csi_sgr_mouse(b"\x1B[<0;20;10m").unwrap(),
705 Some(InternalEvent::Event(Event::Mouse(MouseEvent {
706 kind: MouseEventKind::Up(MouseButton::Left),
707 column: 19,
708 row: 9,
709 modifiers: KeyModifiers::empty(),
710 })))
711 );
712 }
713
714 #[test]
test_utf8()715 fn test_utf8() {
716 // https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php#54805
717
718 // 'Valid ASCII' => "a",
719 assert_eq!(parse_utf8_char(b"a").unwrap(), Some('a'),);
720
721 // 'Valid 2 Octet Sequence' => "\xc3\xb1",
722 assert_eq!(parse_utf8_char(&[0xC3, 0xB1]).unwrap(), Some('ñ'),);
723
724 // 'Invalid 2 Octet Sequence' => "\xc3\x28",
725 assert!(parse_utf8_char(&[0xC3, 0x28]).is_err());
726
727 // 'Invalid Sequence Identifier' => "\xa0\xa1",
728 assert!(parse_utf8_char(&[0xA0, 0xA1]).is_err());
729
730 // 'Valid 3 Octet Sequence' => "\xe2\x82\xa1",
731 assert_eq!(
732 parse_utf8_char(&[0xE2, 0x81, 0xA1]).unwrap(),
733 Some('\u{2061}'),
734 );
735
736 // 'Invalid 3 Octet Sequence (in 2nd Octet)' => "\xe2\x28\xa1",
737 assert!(parse_utf8_char(&[0xE2, 0x28, 0xA1]).is_err());
738
739 // 'Invalid 3 Octet Sequence (in 3rd Octet)' => "\xe2\x82\x28",
740 assert!(parse_utf8_char(&[0xE2, 0x82, 0x28]).is_err());
741
742 // 'Valid 4 Octet Sequence' => "\xf0\x90\x8c\xbc",
743 assert_eq!(
744 parse_utf8_char(&[0xF0, 0x90, 0x8C, 0xBC]).unwrap(),
745 Some(''),
746 );
747
748 // 'Invalid 4 Octet Sequence (in 2nd Octet)' => "\xf0\x28\x8c\xbc",
749 assert!(parse_utf8_char(&[0xF0, 0x28, 0x8C, 0xBC]).is_err());
750
751 // 'Invalid 4 Octet Sequence (in 3rd Octet)' => "\xf0\x90\x28\xbc",
752 assert!(parse_utf8_char(&[0xF0, 0x90, 0x28, 0xBC]).is_err());
753
754 // 'Invalid 4 Octet Sequence (in 4th Octet)' => "\xf0\x28\x8c\x28",
755 assert!(parse_utf8_char(&[0xF0, 0x28, 0x8C, 0x28]).is_err());
756 }
757
758 #[test]
test_parse_char_event_lowercase()759 fn test_parse_char_event_lowercase() {
760 assert_eq!(
761 parse_event(b"c", false).unwrap(),
762 Some(InternalEvent::Event(Event::Key(KeyEvent::new(
763 KeyCode::Char('c'),
764 KeyModifiers::empty()
765 )))),
766 );
767 }
768
769 #[test]
test_parse_char_event_uppercase()770 fn test_parse_char_event_uppercase() {
771 assert_eq!(
772 parse_event(b"C", false).unwrap(),
773 Some(InternalEvent::Event(Event::Key(KeyEvent::new(
774 KeyCode::Char('C'),
775 KeyModifiers::SHIFT
776 )))),
777 );
778 }
779 }
780