Skip to main content

fresh/server/
input_parser.rs

1//! Server-side input parsing
2//!
3//! Parses raw bytes from the client into crossterm events.
4//! This allows the server to handle all input parsing, keeping the client ultra-light.
5
6use crossterm::event::{
7    Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind,
8};
9
10/// Parser state for incremental input parsing
11#[derive(Debug)]
12pub struct InputParser {
13    /// Buffer for incomplete escape sequences
14    buffer: Vec<u8>,
15    /// Maximum buffer size before we give up on an escape sequence
16    max_buffer_size: usize,
17    /// When the buffer last received a byte (for ESC timeout)
18    /// Buffer for bracketed paste content (between \x1b[200~ and \x1b[201~)
19    paste_buffer: Option<Vec<u8>>,
20}
21
22impl Default for InputParser {
23    fn default() -> Self {
24        Self::new()
25    }
26}
27
28impl InputParser {
29    pub fn new() -> Self {
30        Self {
31            buffer: Vec::with_capacity(32),
32            max_buffer_size: 256,
33            paste_buffer: None,
34        }
35    }
36
37    /// Suggests a timeout for the next input read (matching Microsoft Edit).
38    ///
39    /// Returns 100ms if the parser has a buffered ESC (might be standalone
40    /// Escape or the start of an escape sequence). Returns `Duration::MAX`
41    /// otherwise (no timeout needed — wait indefinitely for input).
42    ///
43    /// Parse input bytes and return any complete events.
44    ///
45    /// If called with empty input and the buffer contains a standalone ESC,
46    /// emits it as an Escape key event (matching Microsoft Edit's pattern:
47    /// timeout expired, no more input coming, so the ESC is standalone).
48    pub fn parse(&mut self, bytes: &[u8]) -> Vec<Event> {
49        let mut events = Vec::new();
50
51        if !bytes.is_empty() || !self.buffer.is_empty() {
52            tracing::trace!(
53                "InputParser.parse: input={} bytes, buffer={} bytes ({:02x?})",
54                bytes.len(),
55                self.buffer.len(),
56                &self.buffer,
57            );
58        }
59
60        // If buffer has a lone ESC and new bytes arrived, the next byte
61        // disambiguates: `[` means CSI sequence, anything else means the
62        // ESC was standalone. We never flush ESC on timeout — we always
63        // wait for the next byte. This prevents the bug where a mouse
64        // sequence split across ReadConsoleInput batches at the \x1b
65        // boundary gets its ESC flushed as standalone, causing the
66        // continuation `[<35;...M` to be dumped as literal text.
67        //
68        // Empty input (timeout) is a no-op when ESC is buffered — the
69        // ESC stays in the buffer until real bytes arrive.
70        if bytes.is_empty() {
71            return events;
72        }
73
74        for &byte in bytes {
75            // If we're inside a bracketed paste, buffer bytes until end marker
76            if let Some(ref mut paste_buf) = self.paste_buffer {
77                paste_buf.push(byte);
78                // Check for end marker: \x1b[201~
79                if paste_buf.len() >= 6 && paste_buf.ends_with(b"\x1b[201~") {
80                    // Remove the end marker from the paste content
81                    let content_len = paste_buf.len() - 6;
82                    let text = String::from_utf8_lossy(&paste_buf[..content_len]).into_owned();
83                    self.paste_buffer = None;
84                    events.push(Event::Paste(text));
85                }
86                continue;
87            }
88
89            self.buffer.push(byte);
90
91            // Try to parse the buffer
92            match self.try_parse() {
93                ParseResult::Complete(event) => {
94                    events.push(event);
95                    self.buffer.clear();
96                }
97                ParseResult::PasteStart => {
98                    // Enter bracketed paste mode
99                    self.paste_buffer = Some(Vec::new());
100                    self.buffer.clear();
101                }
102                ParseResult::Incomplete => {
103                    // Need more bytes
104                    if self.buffer.len() > self.max_buffer_size {
105                        // Buffer too large, discard and treat as raw bytes
106                        for &b in &self.buffer {
107                            if let Some(event) = self.byte_to_event(b) {
108                                events.push(event);
109                            }
110                        }
111                        self.buffer.clear();
112                    }
113                }
114                ParseResult::Invalid => {
115                    // Invalid sequence, treat first byte as raw and retry rest
116                    tracing::trace!(
117                        "InputParser: Invalid sequence, buffer={:02x?}",
118                        &self.buffer,
119                    );
120                    if !self.buffer.is_empty() {
121                        let first = self.buffer[0];
122                        if let Some(event) = self.byte_to_event(first) {
123                            events.push(event);
124                        }
125                        let rest: Vec<u8> = self.buffer[1..].to_vec();
126                        self.buffer.clear();
127                        // Re-parse the rest
128                        events.extend(self.parse(&rest));
129                    }
130                }
131            }
132        }
133
134        events
135    }
136
137    /// Try to parse the current buffer
138    fn try_parse(&self) -> ParseResult {
139        if self.buffer.is_empty() {
140            return ParseResult::Incomplete;
141        }
142
143        let bytes = &self.buffer;
144
145        // Check for escape sequences
146        if bytes[0] == 0x1b {
147            return self.parse_escape_sequence();
148        }
149
150        // UTF-8 multi-byte sequence
151        if is_utf8_start_byte(bytes[0]) {
152            return self.parse_utf8_sequence();
153        }
154
155        // Single byte - convert directly
156        if let Some(event) = self.byte_to_event(bytes[0]) {
157            return ParseResult::Complete(event);
158        }
159
160        ParseResult::Invalid
161    }
162
163    /// Parse a UTF-8 multi-byte character sequence
164    fn parse_utf8_sequence(&self) -> ParseResult {
165        let bytes = &self.buffer;
166        let needed = utf8_char_width(bytes[0]);
167        if needed == 0 {
168            return ParseResult::Invalid;
169        }
170        if bytes.len() < needed {
171            return ParseResult::Incomplete;
172        }
173        match std::str::from_utf8(&bytes[..needed]) {
174            Ok(s) => {
175                if let Some(c) = s.chars().next() {
176                    ParseResult::Complete(Event::Key(KeyEvent::new(
177                        KeyCode::Char(c),
178                        KeyModifiers::empty(),
179                    )))
180                } else {
181                    ParseResult::Invalid
182                }
183            }
184            Err(_) => ParseResult::Invalid,
185        }
186    }
187
188    /// Parse an escape sequence
189    fn parse_escape_sequence(&self) -> ParseResult {
190        let bytes = &self.buffer;
191
192        if bytes.len() < 2 {
193            return ParseResult::Incomplete;
194        }
195
196        match bytes[1] {
197            // CSI sequences: ESC [
198            b'[' => self.parse_csi_sequence(),
199            // SS3 sequences: ESC O (function keys on some terminals)
200            b'O' => self.parse_ss3_sequence(),
201            // ESC followed by another ESC: the first is standalone Escape,
202            // the second starts a new escape sequence. Return Invalid so the
203            // first byte is emitted as Escape and the second \x1b is re-parsed.
204            0x1b => ParseResult::Invalid,
205            // Alt + key: ESC + key
206            _ => {
207                let key = bytes[1];
208                let event = Event::Key(KeyEvent::new(byte_to_keycode(key), KeyModifiers::ALT));
209                ParseResult::Complete(event)
210            }
211        }
212    }
213
214    /// Parse CSI (Control Sequence Introducer) sequence: ESC [ ...
215    fn parse_csi_sequence(&self) -> ParseResult {
216        let bytes = &self.buffer;
217
218        if bytes.len() < 3 {
219            return ParseResult::Incomplete;
220        }
221
222        // Find the final byte (0x40-0x7E)
223        let final_idx = bytes[2..].iter().position(|&b| (0x40..=0x7E).contains(&b));
224
225        match final_idx {
226            None => {
227                // Check if we have parameter bytes (0x30-0x3F) or intermediate bytes (0x20-0x2F)
228                let all_valid = bytes[2..].iter().all(|&b| (0x20..=0x3F).contains(&b));
229                if all_valid {
230                    ParseResult::Incomplete
231                } else {
232                    ParseResult::Invalid
233                }
234            }
235            Some(idx) => {
236                let final_byte = bytes[2 + idx];
237                let params = &bytes[2..2 + idx];
238
239                self.parse_csi_final(params, final_byte)
240            }
241        }
242    }
243
244    /// Parse CSI sequence with final byte
245    fn parse_csi_final(&self, params: &[u8], final_byte: u8) -> ParseResult {
246        match final_byte {
247            // Cursor keys
248            b'A' => ParseResult::Complete(Event::Key(KeyEvent::new(
249                KeyCode::Up,
250                self.parse_modifiers(params),
251            ))),
252            b'B' => ParseResult::Complete(Event::Key(KeyEvent::new(
253                KeyCode::Down,
254                self.parse_modifiers(params),
255            ))),
256            b'C' => ParseResult::Complete(Event::Key(KeyEvent::new(
257                KeyCode::Right,
258                self.parse_modifiers(params),
259            ))),
260            b'D' => ParseResult::Complete(Event::Key(KeyEvent::new(
261                KeyCode::Left,
262                self.parse_modifiers(params),
263            ))),
264            b'H' => ParseResult::Complete(Event::Key(KeyEvent::new(
265                KeyCode::Home,
266                self.parse_modifiers(params),
267            ))),
268            b'F' => ParseResult::Complete(Event::Key(KeyEvent::new(
269                KeyCode::End,
270                self.parse_modifiers(params),
271            ))),
272
273            // Special keys with tilde
274            b'~' => self.parse_tilde_sequence(params),
275
276            // Mouse events (SGR format): CSI < Cb ; Cx ; Cy M/m
277            b'M' | b'm' => {
278                if !params.is_empty() && params[0] == b'<' {
279                    self.parse_sgr_mouse(params, final_byte == b'M')
280                } else {
281                    // X10 mouse format
282                    self.parse_x10_mouse()
283                }
284            }
285
286            // Shift+Tab (Back Tab): CSI Z
287            b'Z' => ParseResult::Complete(Event::Key(KeyEvent::new(
288                KeyCode::BackTab,
289                KeyModifiers::SHIFT,
290            ))),
291
292            // Focus events
293            b'I' => ParseResult::Complete(Event::FocusGained),
294            b'O' => ParseResult::Complete(Event::FocusLost),
295
296            // CSI u (fixterms / kitty keyboard protocol): CSI keycode ; modifiers u
297            b'u' => self.parse_csi_u_sequence(params),
298
299            _ => ParseResult::Invalid,
300        }
301    }
302
303    /// Parse tilde sequences: CSI number ~
304    fn parse_tilde_sequence(&self, params: &[u8]) -> ParseResult {
305        let params_str = std::str::from_utf8(params).unwrap_or("");
306        let parts: Vec<&str> = params_str.split(';').collect();
307
308        // xterm modifyOtherKeys mode 2: CSI 27 ; modifier ; keycode ~
309        if parts.len() == 3 && parts[0] == "27" {
310            let mods_param: u8 = parts[1].parse().unwrap_or(1);
311            let codepoint: u32 = parts[2].parse().unwrap_or(0);
312            let modifiers = modifiers_from_param(mods_param);
313
314            let keycode = match codepoint {
315                9 => KeyCode::Tab,
316                13 => KeyCode::Enter,
317                27 => KeyCode::Esc,
318                127 => KeyCode::Backspace,
319                cp => match char::from_u32(cp) {
320                    Some(c) => KeyCode::Char(c),
321                    None => return ParseResult::Invalid,
322                },
323            };
324
325            return ParseResult::Complete(Event::Key(KeyEvent::new(keycode, modifiers)));
326        }
327
328        let (num, modifiers) = self.parse_num_and_modifiers(params);
329
330        // Bracketed paste start: CSI 200 ~
331        if num == 200 {
332            return ParseResult::PasteStart;
333        }
334
335        // Bracketed paste end: CSI 201 ~ (shouldn't appear outside paste mode,
336        // but handle gracefully by ignoring)
337        if num == 201 {
338            return ParseResult::Complete(Event::Key(KeyEvent::new(
339                KeyCode::Null,
340                KeyModifiers::empty(),
341            )));
342        }
343
344        let keycode = match num {
345            1 => KeyCode::Home,
346            2 => KeyCode::Insert,
347            3 => KeyCode::Delete,
348            4 => KeyCode::End,
349            5 => KeyCode::PageUp,
350            6 => KeyCode::PageDown,
351            7 => KeyCode::Home,
352            8 => KeyCode::End,
353            11 => KeyCode::F(1),
354            12 => KeyCode::F(2),
355            13 => KeyCode::F(3),
356            14 => KeyCode::F(4),
357            15 => KeyCode::F(5),
358            17 => KeyCode::F(6),
359            18 => KeyCode::F(7),
360            19 => KeyCode::F(8),
361            20 => KeyCode::F(9),
362            21 => KeyCode::F(10),
363            23 => KeyCode::F(11),
364            24 => KeyCode::F(12),
365            _ => return ParseResult::Invalid,
366        };
367
368        ParseResult::Complete(Event::Key(KeyEvent::new(keycode, modifiers)))
369    }
370
371    /// Parse CSI u (fixterms / kitty keyboard protocol): CSI keycode ; modifiers u
372    ///
373    /// The keycode is a Unicode codepoint. Special codepoints map to functional
374    /// keys (Enter, Tab, Esc, Backspace, etc.); printable codepoints map to
375    /// Char. Modifiers use the same encoding as standard CSI sequences.
376    fn parse_csi_u_sequence(&self, params: &[u8]) -> ParseResult {
377        let params_str = std::str::from_utf8(params).unwrap_or("");
378        let parts: Vec<&str> = params_str.split(';').collect();
379
380        let codepoint: u32 = parts.first().and_then(|s| s.parse().ok()).unwrap_or(0);
381        let mods_param: u8 = parts.get(1).and_then(|s| s.parse().ok()).unwrap_or(1);
382        let modifiers = modifiers_from_param(mods_param);
383
384        let keycode = match codepoint {
385            9 => KeyCode::Tab,
386            13 => KeyCode::Enter,
387            27 => KeyCode::Esc,
388            127 => KeyCode::Backspace,
389            cp => match char::from_u32(cp) {
390                Some(c) => KeyCode::Char(c),
391                None => return ParseResult::Invalid,
392            },
393        };
394
395        ParseResult::Complete(Event::Key(KeyEvent::new(keycode, modifiers)))
396    }
397
398    /// Parse SGR mouse format: CSI < Cb ; Cx ; Cy M/m
399    fn parse_sgr_mouse(&self, params: &[u8], pressed: bool) -> ParseResult {
400        // Skip the '<'
401        let params_str = std::str::from_utf8(&params[1..]).unwrap_or("");
402        let parts: Vec<&str> = params_str.split(';').collect();
403
404        if parts.len() != 3 {
405            return ParseResult::Invalid;
406        }
407
408        let cb: u16 = parts[0].parse().unwrap_or(0);
409        let cx: u16 = parts[1].parse().unwrap_or(1);
410        let cy: u16 = parts[2].parse().unwrap_or(1);
411
412        let button_bits = cb & 0b11;
413        let button = match button_bits {
414            0 => MouseButton::Left,
415            1 => MouseButton::Middle,
416            2 => MouseButton::Right,
417            _ => MouseButton::Left, // 3 = no button (for motion)
418        };
419
420        let modifiers = KeyModifiers::from_bits_truncate(
421            if cb & 4 != 0 {
422                KeyModifiers::SHIFT.bits()
423            } else {
424                0
425            } | if cb & 8 != 0 {
426                KeyModifiers::ALT.bits()
427            } else {
428                0
429            } | if cb & 16 != 0 {
430                KeyModifiers::CONTROL.bits()
431            } else {
432                0
433            },
434        );
435
436        let kind = if cb & 32 != 0 {
437            // Motion event
438            if cb & 64 != 0 {
439                // Scroll while moving (unusual)
440                if cb & 1 != 0 {
441                    MouseEventKind::ScrollDown
442                } else {
443                    MouseEventKind::ScrollUp
444                }
445            } else if button_bits == 3 {
446                // Motion with no button pressed (hover)
447                MouseEventKind::Moved
448            } else {
449                // Motion with button pressed (drag)
450                MouseEventKind::Drag(button)
451            }
452        } else if cb & 64 != 0 {
453            // Scroll
454            if cb & 1 != 0 {
455                MouseEventKind::ScrollDown
456            } else {
457                MouseEventKind::ScrollUp
458            }
459        } else if pressed {
460            MouseEventKind::Down(button)
461        } else {
462            MouseEventKind::Up(button)
463        };
464
465        ParseResult::Complete(Event::Mouse(MouseEvent {
466            kind,
467            column: cx.saturating_sub(1),
468            row: cy.saturating_sub(1),
469            modifiers,
470        }))
471    }
472
473    /// Parse X10 mouse format (legacy)
474    fn parse_x10_mouse(&self) -> ParseResult {
475        let bytes = &self.buffer;
476
477        if bytes.len() < 6 {
478            return ParseResult::Incomplete;
479        }
480
481        let cb = bytes[3].wrapping_sub(32);
482        let cx = bytes[4].wrapping_sub(32);
483        let cy = bytes[5].wrapping_sub(32);
484
485        let button = match cb & 0b11 {
486            0 => MouseButton::Left,
487            1 => MouseButton::Middle,
488            2 => MouseButton::Right,
489            3 => {
490                // Release
491                return ParseResult::Complete(Event::Mouse(MouseEvent {
492                    kind: MouseEventKind::Up(MouseButton::Left),
493                    column: cx as u16,
494                    row: cy as u16,
495                    modifiers: KeyModifiers::empty(),
496                }));
497            }
498            _ => MouseButton::Left,
499        };
500
501        ParseResult::Complete(Event::Mouse(MouseEvent {
502            kind: MouseEventKind::Down(button),
503            column: cx as u16,
504            row: cy as u16,
505            modifiers: KeyModifiers::empty(),
506        }))
507    }
508
509    /// Parse SS3 sequence: ESC O ...
510    fn parse_ss3_sequence(&self) -> ParseResult {
511        let bytes = &self.buffer;
512
513        if bytes.len() < 3 {
514            return ParseResult::Incomplete;
515        }
516
517        let keycode = match bytes[2] {
518            b'P' => KeyCode::F(1),
519            b'Q' => KeyCode::F(2),
520            b'R' => KeyCode::F(3),
521            b'S' => KeyCode::F(4),
522            b'A' => KeyCode::Up,
523            b'B' => KeyCode::Down,
524            b'C' => KeyCode::Right,
525            b'D' => KeyCode::Left,
526            b'H' => KeyCode::Home,
527            b'F' => KeyCode::End,
528            _ => return ParseResult::Invalid,
529        };
530
531        ParseResult::Complete(Event::Key(KeyEvent::new(keycode, KeyModifiers::empty())))
532    }
533
534    /// Parse modifiers from CSI parameters
535    fn parse_modifiers(&self, params: &[u8]) -> KeyModifiers {
536        // Format: [num;modifiers] where modifiers = 1 + (shift) + 2*(alt) + 4*(ctrl)
537        let params_str = std::str::from_utf8(params).unwrap_or("");
538        if let Some(idx) = params_str.find(';') {
539            if let Ok(mods) = params_str[idx + 1..].parse::<u8>() {
540                return modifiers_from_param(mods);
541            }
542        }
543        KeyModifiers::empty()
544    }
545
546    /// Parse number and modifiers from CSI parameters
547    fn parse_num_and_modifiers(&self, params: &[u8]) -> (u8, KeyModifiers) {
548        let params_str = std::str::from_utf8(params).unwrap_or("");
549        let parts: Vec<&str> = params_str.split(';').collect();
550
551        let num = parts.first().and_then(|s| s.parse().ok()).unwrap_or(0);
552        let mods = parts.get(1).and_then(|s| s.parse().ok()).unwrap_or(1);
553
554        (num, modifiers_from_param(mods))
555    }
556
557    /// Convert a single byte to an event
558    fn byte_to_event(&self, byte: u8) -> Option<Event> {
559        let keycode = byte_to_keycode(byte);
560        let modifiers = if byte < 32 && byte != 9 && byte != 10 && byte != 13 && byte != 27 {
561            // Control character (but not Tab, LF, CR, or Esc)
562            KeyModifiers::CONTROL
563        } else {
564            KeyModifiers::empty()
565        };
566
567        Some(Event::Key(KeyEvent::new(keycode, modifiers)))
568    }
569}
570
571/// Returns true if `b` is the leading byte of a UTF-8 multi-byte sequence.
572/// 0xC0 and 0xC1 are excluded per RFC 3629 (overlong encodings).
573fn is_utf8_start_byte(b: u8) -> bool {
574    matches!(b, 0xC2..=0xDF | 0xE0..=0xEF | 0xF0..=0xF7)
575}
576
577/// Returns the total byte width of a UTF-8 sequence given its leading byte.
578/// Returns 0 for invalid leading bytes.
579fn utf8_char_width(first_byte: u8) -> usize {
580    match first_byte {
581        0xC2..=0xDF => 2,
582        0xE0..=0xEF => 3,
583        0xF0..=0xF7 => 4,
584        _ => 0,
585    }
586}
587
588/// Result of trying to parse the buffer
589enum ParseResult {
590    /// Successfully parsed a complete event
591    Complete(Event),
592    /// Bracketed paste start marker detected (\x1b[200~)
593    PasteStart,
594    /// Need more bytes to complete the sequence
595    Incomplete,
596    /// Invalid sequence
597    Invalid,
598}
599
600/// Convert a byte to a KeyCode
601fn byte_to_keycode(byte: u8) -> KeyCode {
602    match byte {
603        0 => KeyCode::Char('@'), // Ctrl+@
604        9 => KeyCode::Tab,
605        10 | 13 => KeyCode::Enter,                          // LF or CR
606        1..=26 => KeyCode::Char((b'a' + byte - 1) as char), // Ctrl+A through Ctrl+Z
607        27 => KeyCode::Esc,
608        28..=31 => KeyCode::Char((b'\\' + byte - 28) as char),
609        32 => KeyCode::Char(' '),
610        127 => KeyCode::Backspace,
611        b if (32..127).contains(&b) => KeyCode::Char(b as char),
612        _ => KeyCode::Null,
613    }
614}
615
616/// Convert modifier parameter to KeyModifiers
617fn modifiers_from_param(param: u8) -> KeyModifiers {
618    let param = param.saturating_sub(1);
619    KeyModifiers::from_bits_truncate(
620        if param & 1 != 0 {
621            KeyModifiers::SHIFT.bits()
622        } else {
623            0
624        } | if param & 2 != 0 {
625            KeyModifiers::ALT.bits()
626        } else {
627            0
628        } | if param & 4 != 0 {
629            KeyModifiers::CONTROL.bits()
630        } else {
631            0
632        },
633    )
634}
635
636#[cfg(test)]
637mod tests {
638    use super::*;
639
640    #[test]
641    fn test_simple_characters() {
642        let mut parser = InputParser::new();
643        let events = parser.parse(b"abc");
644        assert_eq!(events.len(), 3);
645        match &events[0] {
646            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Char('a')),
647            _ => panic!("Expected key event"),
648        }
649    }
650
651    #[test]
652    fn test_control_characters_have_ctrl_modifier() {
653        let mut parser = InputParser::new();
654        // Ctrl+C = 0x03
655        let events = parser.parse(&[0x03]);
656        match &events[0] {
657            Event::Key(ke) => {
658                assert_eq!(ke.code, KeyCode::Char('c'));
659                assert!(ke.modifiers.contains(KeyModifiers::CONTROL));
660            }
661            _ => panic!("Expected key event"),
662        }
663    }
664
665    #[test]
666    fn test_escape_buffers_until_complete() {
667        let mut parser = InputParser::new();
668        // ESC alone should buffer
669        assert!(parser.parse(&[0x1b]).is_empty());
670        // Adding more should still buffer
671        assert!(parser.parse(b"[").is_empty());
672        // Final byte completes the sequence
673        let events = parser.parse(b"A");
674        assert_eq!(events.len(), 1);
675        match &events[0] {
676            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Up),
677            _ => panic!("Expected Up key"),
678        }
679    }
680
681    #[test]
682    fn test_csi_sequences_parse_arrow_keys() {
683        let mut parser = InputParser::new();
684        // CSI format: ESC [ <final>
685        let events = parser.parse(b"\x1b[A");
686        match &events[0] {
687            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Up),
688            _ => panic!("Expected key event"),
689        }
690    }
691
692    #[test]
693    fn test_ss3_sequences_parse_function_keys() {
694        let mut parser = InputParser::new();
695        // SS3 format: ESC O <letter>
696        let events = parser.parse(b"\x1bOP");
697        match &events[0] {
698            Event::Key(ke) => assert_eq!(ke.code, KeyCode::F(1)),
699            _ => panic!("Expected key event"),
700        }
701    }
702
703    #[test]
704    fn test_alt_key_via_esc_prefix() {
705        let mut parser = InputParser::new();
706        // Alt+a: ESC a (ESC followed by non-sequence char)
707        let events = parser.parse(b"\x1ba");
708        match &events[0] {
709            Event::Key(ke) => {
710                assert_eq!(ke.code, KeyCode::Char('a'));
711                assert!(ke.modifiers.contains(KeyModifiers::ALT));
712            }
713            _ => panic!("Expected key event"),
714        }
715    }
716
717    #[test]
718    fn test_csi_modifiers_parsed_correctly() {
719        let mut parser = InputParser::new();
720        // Shift+Up: ESC [ 1 ; 2 A (2 = shift)
721        let events = parser.parse(b"\x1b[1;2A");
722        match &events[0] {
723            Event::Key(ke) => {
724                assert_eq!(ke.code, KeyCode::Up);
725                assert!(ke.modifiers.contains(KeyModifiers::SHIFT));
726            }
727            _ => panic!("Expected Shift+Up"),
728        }
729    }
730
731    #[test]
732    fn test_sgr_mouse_events_are_1_indexed() {
733        let mut parser = InputParser::new();
734        // SGR mouse: CSI < button ; x ; y M
735        // Terminal sends 1-indexed, we convert to 0-indexed
736        let events = parser.parse(b"\x1b[<0;10;5M");
737        match &events[0] {
738            Event::Mouse(me) => {
739                assert_eq!(me.column, 9); // 10-1
740                assert_eq!(me.row, 4); // 5-1
741            }
742            _ => panic!("Expected mouse event"),
743        }
744    }
745
746    #[test]
747    fn test_focus_events() {
748        let mut parser = InputParser::new();
749        let events = parser.parse(b"\x1b[I");
750        assert!(matches!(&events[0], Event::FocusGained));
751
752        let events = parser.parse(b"\x1b[O");
753        assert!(matches!(&events[0], Event::FocusLost));
754    }
755
756    #[test]
757    fn test_mixed_input_preserves_order() {
758        let mut parser = InputParser::new();
759        let events = parser.parse(b"a\x1b[Ab");
760        assert_eq!(events.len(), 3);
761        // Order: 'a', Up, 'b'
762        assert!(matches!(&events[0], Event::Key(ke) if ke.code == KeyCode::Char('a')));
763        assert!(matches!(&events[1], Event::Key(ke) if ke.code == KeyCode::Up));
764        assert!(matches!(&events[2], Event::Key(ke) if ke.code == KeyCode::Char('b')));
765    }
766
767    #[test]
768    fn test_enter_key() {
769        let mut parser = InputParser::new();
770        // CR (carriage return) = 0x0D = 13
771        let events = parser.parse(&[0x0D]);
772        match &events[0] {
773            Event::Key(ke) => {
774                assert_eq!(ke.code, KeyCode::Enter);
775                assert!(ke.modifiers.is_empty());
776            }
777            _ => panic!("Expected Enter key event"),
778        }
779
780        // LF (line feed) = 0x0A = 10
781        let events = parser.parse(&[0x0A]);
782        match &events[0] {
783            Event::Key(ke) => {
784                assert_eq!(ke.code, KeyCode::Enter);
785                assert!(ke.modifiers.is_empty());
786            }
787            _ => panic!("Expected Enter key event"),
788        }
789    }
790
791    #[test]
792    fn test_tab_key() {
793        let mut parser = InputParser::new();
794        // Tab = 0x09 = 9
795        let events = parser.parse(&[0x09]);
796        match &events[0] {
797            Event::Key(ke) => {
798                assert_eq!(ke.code, KeyCode::Tab);
799                assert!(ke.modifiers.is_empty());
800            }
801            _ => panic!("Expected Tab key event"),
802        }
803    }
804
805    #[test]
806    fn test_mouse_motion_without_button() {
807        let mut parser = InputParser::new();
808        // SGR mouse motion with no button: CSI < 35 ; x ; y M
809        // 35 = 32 (motion) + 3 (no button)
810        let events = parser.parse(b"\x1b[<35;10;5M");
811        match &events[0] {
812            Event::Mouse(me) => {
813                assert!(matches!(me.kind, MouseEventKind::Moved));
814                assert_eq!(me.column, 9); // 10 - 1 (0-indexed)
815                assert_eq!(me.row, 4); // 5 - 1 (0-indexed)
816            }
817            _ => panic!("Expected mouse motion event"),
818        }
819    }
820
821    // ---- Regression tests for issue #1089 ----
822
823    #[test]
824    fn test_shift_tab_csi_z() {
825        let mut parser = InputParser::new();
826        // Shift+Tab sends CSI Z = ESC [ Z
827        let events = parser.parse(b"\x1b[Z");
828        assert_eq!(events.len(), 1);
829        match &events[0] {
830            Event::Key(ke) => {
831                assert_eq!(ke.code, KeyCode::BackTab);
832                assert!(ke.modifiers.contains(KeyModifiers::SHIFT));
833            }
834            _ => panic!("Expected BackTab key event, got {:?}", events[0]),
835        }
836    }
837
838    #[test]
839    fn test_esc_then_mouse_event_same_chunk() {
840        let mut parser = InputParser::new();
841        // User presses Escape, then moves mouse. Both arrive in one chunk:
842        // ESC (0x1b) followed by mouse event ESC [ < 35 ; 67 ; 18 M
843        let events = parser.parse(b"\x1b\x1b[<35;67;18M");
844        assert_eq!(
845            events.len(),
846            2,
847            "Expected Escape + mouse event, got: {:?}",
848            events
849        );
850
851        // First event: standalone Escape
852        match &events[0] {
853            Event::Key(ke) => {
854                assert_eq!(ke.code, KeyCode::Esc);
855                assert!(ke.modifiers.is_empty());
856            }
857            _ => panic!("Expected Esc key event, got {:?}", events[0]),
858        }
859
860        // Second event: mouse motion
861        match &events[1] {
862            Event::Mouse(me) => {
863                assert!(matches!(me.kind, MouseEventKind::Moved));
864                assert_eq!(me.column, 66); // 67 - 1
865                assert_eq!(me.row, 17); // 18 - 1
866            }
867            _ => panic!("Expected mouse motion event, got {:?}", events[1]),
868        }
869    }
870
871    #[test]
872    fn test_esc_then_mouse_event_separate_chunks() {
873        let mut parser = InputParser::new();
874
875        // First chunk: standalone ESC (buffered, waiting for more bytes)
876        let events = parser.parse(&[0x1b]);
877        assert!(events.is_empty(), "ESC should be buffered");
878
879        // Second chunk: mouse event arrives later
880        let events = parser.parse(b"\x1b[<35;67;18M");
881        assert_eq!(
882            events.len(),
883            2,
884            "Expected Escape + mouse event, got: {:?}",
885            events
886        );
887
888        // First event: standalone Escape (disambiguated by seeing another ESC)
889        match &events[0] {
890            Event::Key(ke) => {
891                assert_eq!(ke.code, KeyCode::Esc);
892                assert!(ke.modifiers.is_empty());
893            }
894            _ => panic!("Expected Esc key event, got {:?}", events[0]),
895        }
896
897        // Second event: mouse motion
898        match &events[1] {
899            Event::Mouse(me) => {
900                assert!(matches!(me.kind, MouseEventKind::Moved));
901            }
902            _ => panic!("Expected mouse motion event, got {:?}", events[1]),
903        }
904    }
905
906    #[test]
907    fn test_esc_then_csi_arrow_separate_chunks() {
908        let mut parser = InputParser::new();
909
910        // ESC buffered
911        let events = parser.parse(&[0x1b]);
912        assert!(events.is_empty());
913
914        // Arrow key sequence arrives (starts with another ESC)
915        let events = parser.parse(b"\x1b[A");
916        assert_eq!(events.len(), 2, "Expected Escape + Up, got: {:?}", events);
917
918        match &events[0] {
919            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Esc),
920            _ => panic!("Expected Esc"),
921        }
922        match &events[1] {
923            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Up),
924            _ => panic!("Expected Up"),
925        }
926    }
927
928    #[test]
929    fn test_esc_waits_for_next_byte() {
930        let mut parser = InputParser::new();
931
932        // ESC buffered
933        let events = parser.parse(&[0x1b]);
934        assert!(events.is_empty());
935
936        // Buffer still has the ESC
937        assert_eq!(parser.buffer.len(), 1);
938
939        // Next byte `[` disambiguates: it's a CSI sequence, not standalone ESC
940        let events = parser.parse(b"[A");
941        assert_eq!(events.len(), 1);
942        match &events[0] {
943            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Up),
944            _ => panic!("Expected Up"),
945        }
946    }
947
948    #[test]
949    fn test_esc_then_printable_byte_emits_alt_key() {
950        let mut parser = InputParser::new();
951
952        // ESC buffered
953        let events = parser.parse(&[0x1b]);
954        assert!(events.is_empty());
955
956        // Next byte `a` completes the sequence as Alt+a (standard terminal behavior)
957        let events = parser.parse(b"a");
958        assert_eq!(events.len(), 1);
959        match &events[0] {
960            Event::Key(ke) => {
961                assert_eq!(ke.code, KeyCode::Char('a'));
962                assert!(ke.modifiers.contains(KeyModifiers::ALT));
963            }
964            _ => panic!("Expected Alt+a"),
965        }
966    }
967
968    #[test]
969    fn test_esc_then_esc_emits_standalone_esc() {
970        let mut parser = InputParser::new();
971
972        // First ESC buffered
973        let events = parser.parse(&[0x1b]);
974        assert!(events.is_empty());
975
976        // Second ESC: first ESC is standalone, second starts new sequence
977        let events = parser.parse(&[0x1b]);
978        assert_eq!(events.len(), 1);
979        match &events[0] {
980            Event::Key(ke) => {
981                assert_eq!(ke.code, KeyCode::Esc);
982                assert!(ke.modifiers.is_empty());
983            }
984            _ => panic!("Expected standalone Esc"),
985        }
986        // Second ESC still buffered
987        assert_eq!(parser.buffer, vec![0x1b]);
988    }
989
990    #[test]
991    fn test_split_mouse_sequence_across_batches() {
992        let mut parser = InputParser::new();
993
994        // Batch 1: just the ESC byte (split at batch boundary)
995        let events = parser.parse(&[0x1b]);
996        assert!(events.is_empty());
997        assert_eq!(parser.buffer.len(), 1);
998
999        // Batch 2: rest of mouse sequence arrives
1000        let events = parser.parse(b"[<35;42;5M");
1001        assert_eq!(events.len(), 1);
1002        match &events[0] {
1003            Event::Mouse(_) => {} // Mouse event parsed correctly
1004            other => panic!("Expected mouse event, got {:?}", other),
1005        }
1006    }
1007
1008    #[test]
1009    fn test_partial_csi_sequence_not_flushed() {
1010        let mut parser = InputParser::new();
1011
1012        // Partial CSI mouse sequence (split across batches)
1013        let events = parser.parse(b"\x1b[<35;");
1014        assert!(events.is_empty());
1015        assert_eq!(parser.buffer.len(), 6);
1016
1017        // Now the rest of the sequence arrives
1018        let events = parser.parse(b"42;5M");
1019        assert_eq!(events.len(), 1);
1020        match &events[0] {
1021            Event::Mouse(me) => {
1022                assert_eq!(me.column, 41); // 42 - 1 (1-indexed to 0-indexed)
1023                assert_eq!(me.row, 4); // 5 - 1
1024            }
1025            _ => panic!("Expected mouse event, got {:?}", events[0]),
1026        }
1027    }
1028
1029    #[test]
1030    fn test_esc_then_mouse_click() {
1031        let mut parser = InputParser::new();
1032        // ESC followed by mouse button press: ESC [ < 0 ; 10 ; 5 M
1033        let events = parser.parse(b"\x1b\x1b[<0;10;5M");
1034        assert_eq!(
1035            events.len(),
1036            2,
1037            "Expected Escape + mouse click, got: {:?}",
1038            events
1039        );
1040
1041        match &events[0] {
1042            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Esc),
1043            _ => panic!("Expected Esc"),
1044        }
1045        match &events[1] {
1046            Event::Mouse(me) => {
1047                assert!(matches!(me.kind, MouseEventKind::Down(MouseButton::Left)));
1048            }
1049            _ => panic!("Expected mouse down event, got {:?}", events[1]),
1050        }
1051    }
1052
1053    // ---- Bracketed paste tests ----
1054
1055    #[test]
1056    fn test_bracketed_paste_simple() {
1057        let mut parser = InputParser::new();
1058        // Bracketed paste: \x1b[200~ ... \x1b[201~
1059        let events = parser.parse(b"\x1b[200~Hello, world!\x1b[201~");
1060        assert_eq!(events.len(), 1, "Expected 1 paste event, got: {:?}", events);
1061        match &events[0] {
1062            Event::Paste(text) => assert_eq!(text, "Hello, world!"),
1063            _ => panic!("Expected Paste event, got {:?}", events[0]),
1064        }
1065    }
1066
1067    #[test]
1068    fn test_bracketed_paste_with_newlines() {
1069        let mut parser = InputParser::new();
1070        let events = parser.parse(b"\x1b[200~line1\nline2\nline3\x1b[201~");
1071        assert_eq!(events.len(), 1);
1072        match &events[0] {
1073            Event::Paste(text) => assert_eq!(text, "line1\nline2\nline3"),
1074            _ => panic!("Expected Paste event"),
1075        }
1076    }
1077
1078    #[test]
1079    fn test_bracketed_paste_split_across_chunks() {
1080        let mut parser = InputParser::new();
1081
1082        // Start marker arrives
1083        let events = parser.parse(b"\x1b[200~Hello");
1084        assert!(events.is_empty(), "Paste not complete yet");
1085
1086        // More content
1087        let events = parser.parse(b", world!");
1088        assert!(events.is_empty(), "Paste not complete yet");
1089
1090        // End marker arrives
1091        let events = parser.parse(b"\x1b[201~");
1092        assert_eq!(events.len(), 1);
1093        match &events[0] {
1094            Event::Paste(text) => assert_eq!(text, "Hello, world!"),
1095            _ => panic!("Expected Paste event"),
1096        }
1097    }
1098
1099    #[test]
1100    fn test_bracketed_paste_followed_by_keypress() {
1101        let mut parser = InputParser::new();
1102        // Paste followed by a regular keypress
1103        let events = parser.parse(b"\x1b[200~pasted\x1b[201~a");
1104        assert_eq!(
1105            events.len(),
1106            2,
1107            "Expected paste + key event, got: {:?}",
1108            events
1109        );
1110        match &events[0] {
1111            Event::Paste(text) => assert_eq!(text, "pasted"),
1112            _ => panic!("Expected Paste event"),
1113        }
1114        match &events[1] {
1115            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Char('a')),
1116            _ => panic!("Expected key event"),
1117        }
1118    }
1119
1120    #[test]
1121    fn test_bracketed_paste_empty() {
1122        let mut parser = InputParser::new();
1123        let events = parser.parse(b"\x1b[200~\x1b[201~");
1124        assert_eq!(events.len(), 1);
1125        match &events[0] {
1126            Event::Paste(text) => assert_eq!(text, ""),
1127            _ => panic!("Expected empty Paste event"),
1128        }
1129    }
1130
1131    #[test]
1132    fn test_bracketed_paste_with_escape_sequences_inside() {
1133        let mut parser = InputParser::new();
1134        // Pasted text might contain escape sequences (e.g., colored text from another terminal)
1135        let events = parser.parse(b"\x1b[200~\x1b[31mred text\x1b[0m\x1b[201~");
1136        assert_eq!(events.len(), 1);
1137        match &events[0] {
1138            Event::Paste(text) => assert_eq!(text, "\x1b[31mred text\x1b[0m"),
1139            _ => panic!("Expected Paste event with escape sequences"),
1140        }
1141    }
1142
1143    #[test]
1144    fn test_keypress_then_bracketed_paste() {
1145        let mut parser = InputParser::new();
1146        let events = parser.parse(b"x\x1b[200~pasted\x1b[201~");
1147        assert_eq!(events.len(), 2);
1148        match &events[0] {
1149            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Char('x')),
1150            _ => panic!("Expected key event"),
1151        }
1152        match &events[1] {
1153            Event::Paste(text) => assert_eq!(text, "pasted"),
1154            _ => panic!("Expected Paste event"),
1155        }
1156    }
1157
1158    // ---- UTF-8 multi-byte character tests ----
1159
1160    #[test]
1161    fn test_utf8_three_byte_chinese_char() {
1162        let mut parser = InputParser::new();
1163        // '中' = U+4E2D = [0xE4, 0xB8, 0xAD]
1164        let events = parser.parse(&[0xE4, 0xB8, 0xAD]);
1165        assert_eq!(events.len(), 1);
1166        match &events[0] {
1167            Event::Key(ke) => {
1168                assert_eq!(ke.code, KeyCode::Char('中'));
1169                assert!(ke.modifiers.is_empty());
1170            }
1171            _ => panic!("Expected key event for '中'"),
1172        }
1173    }
1174
1175    #[test]
1176    fn test_utf8_two_byte_char() {
1177        let mut parser = InputParser::new();
1178        // 'é' = U+00E9 = [0xC3, 0xA9]
1179        let events = parser.parse(&[0xC3, 0xA9]);
1180        assert_eq!(events.len(), 1);
1181        match &events[0] {
1182            Event::Key(ke) => {
1183                assert_eq!(ke.code, KeyCode::Char('é'));
1184                assert!(ke.modifiers.is_empty());
1185            }
1186            _ => panic!("Expected key event for 'é'"),
1187        }
1188    }
1189
1190    #[test]
1191    fn test_utf8_four_byte_emoji() {
1192        let mut parser = InputParser::new();
1193        // '😀' = U+1F600 = [0xF0, 0x9F, 0x98, 0x80]
1194        let events = parser.parse(&[0xF0, 0x9F, 0x98, 0x80]);
1195        assert_eq!(events.len(), 1);
1196        match &events[0] {
1197            Event::Key(ke) => {
1198                assert_eq!(ke.code, KeyCode::Char('😀'));
1199                assert!(ke.modifiers.is_empty());
1200            }
1201            _ => panic!("Expected key event for '😀'"),
1202        }
1203    }
1204
1205    #[test]
1206    fn test_utf8_incomplete_sequence_returns_no_events() {
1207        let mut parser = InputParser::new();
1208        // Send only the leading byte of a 3-byte sequence
1209        let events = parser.parse(&[0xE4]);
1210        assert!(
1211            events.is_empty(),
1212            "Incomplete UTF-8 sequence should produce no events"
1213        );
1214    }
1215
1216    #[test]
1217    fn test_utf8_sequence_split_across_batches() {
1218        let mut parser = InputParser::new();
1219        // First batch: leading byte only
1220        let events = parser.parse(&[0xE4]);
1221        assert!(events.is_empty(), "Should buffer leading byte");
1222
1223        // Second batch: remaining bytes complete the character
1224        let events = parser.parse(&[0xB8, 0xAD]);
1225        assert_eq!(events.len(), 1);
1226        match &events[0] {
1227            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Char('中')),
1228            _ => panic!("Expected key event for '中'"),
1229        }
1230    }
1231
1232    #[test]
1233    fn test_utf8_invalid_continuation_byte_does_not_panic() {
1234        let mut parser = InputParser::new();
1235        // 0xE4 expects continuation bytes 0x80..=0xBF, but 0x00 is invalid
1236        let events = parser.parse(&[0xE4, 0x00, 0xAD]);
1237        // Should not panic; the invalid sequence produces some events (graceful recovery)
1238        assert!(
1239            !events.is_empty(),
1240            "Invalid sequence should emit events (graceful recovery)"
1241        );
1242    }
1243
1244    #[test]
1245    fn test_overlong_encoding_0xc0_rejected() {
1246        let mut parser = InputParser::new();
1247        // 0xC0 is a forbidden overlong encoding start byte (RFC 3629)
1248        // It should NOT be treated as a UTF-8 start byte
1249        let events = parser.parse(&[0xC0, 0x80]);
1250        // Both bytes handled as single bytes / Invalid, not as a 2-byte UTF-8 sequence
1251        let _ = events;
1252    }
1253
1254    #[test]
1255    fn test_overlong_encoding_0xc1_rejected() {
1256        let mut parser = InputParser::new();
1257        // 0xC1 is also a forbidden overlong encoding start byte (RFC 3629)
1258        let events = parser.parse(&[0xC1, 0xA0]);
1259        // Both bytes handled as single bytes / Invalid, not as a 2-byte UTF-8 sequence
1260        let _ = events;
1261    }
1262}