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        // Single byte - convert directly
151        if let Some(event) = self.byte_to_event(bytes[0]) {
152            return ParseResult::Complete(event);
153        }
154
155        ParseResult::Invalid
156    }
157
158    /// Parse an escape sequence
159    fn parse_escape_sequence(&self) -> ParseResult {
160        let bytes = &self.buffer;
161
162        if bytes.len() < 2 {
163            return ParseResult::Incomplete;
164        }
165
166        match bytes[1] {
167            // CSI sequences: ESC [
168            b'[' => self.parse_csi_sequence(),
169            // SS3 sequences: ESC O (function keys on some terminals)
170            b'O' => self.parse_ss3_sequence(),
171            // ESC followed by another ESC: the first is standalone Escape,
172            // the second starts a new escape sequence. Return Invalid so the
173            // first byte is emitted as Escape and the second \x1b is re-parsed.
174            0x1b => ParseResult::Invalid,
175            // Alt + key: ESC + key
176            _ => {
177                let key = bytes[1];
178                let event = Event::Key(KeyEvent::new(byte_to_keycode(key), KeyModifiers::ALT));
179                ParseResult::Complete(event)
180            }
181        }
182    }
183
184    /// Parse CSI (Control Sequence Introducer) sequence: ESC [ ...
185    fn parse_csi_sequence(&self) -> ParseResult {
186        let bytes = &self.buffer;
187
188        if bytes.len() < 3 {
189            return ParseResult::Incomplete;
190        }
191
192        // Find the final byte (0x40-0x7E)
193        let final_idx = bytes[2..].iter().position(|&b| (0x40..=0x7E).contains(&b));
194
195        match final_idx {
196            None => {
197                // Check if we have parameter bytes (0x30-0x3F) or intermediate bytes (0x20-0x2F)
198                let all_valid = bytes[2..].iter().all(|&b| (0x20..=0x3F).contains(&b));
199                if all_valid {
200                    ParseResult::Incomplete
201                } else {
202                    ParseResult::Invalid
203                }
204            }
205            Some(idx) => {
206                let final_byte = bytes[2 + idx];
207                let params = &bytes[2..2 + idx];
208
209                self.parse_csi_final(params, final_byte)
210            }
211        }
212    }
213
214    /// Parse CSI sequence with final byte
215    fn parse_csi_final(&self, params: &[u8], final_byte: u8) -> ParseResult {
216        match final_byte {
217            // Cursor keys
218            b'A' => ParseResult::Complete(Event::Key(KeyEvent::new(
219                KeyCode::Up,
220                self.parse_modifiers(params),
221            ))),
222            b'B' => ParseResult::Complete(Event::Key(KeyEvent::new(
223                KeyCode::Down,
224                self.parse_modifiers(params),
225            ))),
226            b'C' => ParseResult::Complete(Event::Key(KeyEvent::new(
227                KeyCode::Right,
228                self.parse_modifiers(params),
229            ))),
230            b'D' => ParseResult::Complete(Event::Key(KeyEvent::new(
231                KeyCode::Left,
232                self.parse_modifiers(params),
233            ))),
234            b'H' => ParseResult::Complete(Event::Key(KeyEvent::new(
235                KeyCode::Home,
236                self.parse_modifiers(params),
237            ))),
238            b'F' => ParseResult::Complete(Event::Key(KeyEvent::new(
239                KeyCode::End,
240                self.parse_modifiers(params),
241            ))),
242
243            // Special keys with tilde
244            b'~' => self.parse_tilde_sequence(params),
245
246            // Mouse events (SGR format): CSI < Cb ; Cx ; Cy M/m
247            b'M' | b'm' => {
248                if !params.is_empty() && params[0] == b'<' {
249                    self.parse_sgr_mouse(params, final_byte == b'M')
250                } else {
251                    // X10 mouse format
252                    self.parse_x10_mouse()
253                }
254            }
255
256            // Shift+Tab (Back Tab): CSI Z
257            b'Z' => ParseResult::Complete(Event::Key(KeyEvent::new(
258                KeyCode::BackTab,
259                KeyModifiers::SHIFT,
260            ))),
261
262            // Focus events
263            b'I' => ParseResult::Complete(Event::FocusGained),
264            b'O' => ParseResult::Complete(Event::FocusLost),
265
266            // CSI u (fixterms / kitty keyboard protocol): CSI keycode ; modifiers u
267            b'u' => self.parse_csi_u_sequence(params),
268
269            _ => ParseResult::Invalid,
270        }
271    }
272
273    /// Parse tilde sequences: CSI number ~
274    fn parse_tilde_sequence(&self, params: &[u8]) -> ParseResult {
275        let params_str = std::str::from_utf8(params).unwrap_or("");
276        let parts: Vec<&str> = params_str.split(';').collect();
277
278        // xterm modifyOtherKeys mode 2: CSI 27 ; modifier ; keycode ~
279        if parts.len() == 3 && parts[0] == "27" {
280            let mods_param: u8 = parts[1].parse().unwrap_or(1);
281            let codepoint: u32 = parts[2].parse().unwrap_or(0);
282            let modifiers = modifiers_from_param(mods_param);
283
284            let keycode = match codepoint {
285                9 => KeyCode::Tab,
286                13 => KeyCode::Enter,
287                27 => KeyCode::Esc,
288                127 => KeyCode::Backspace,
289                cp => match char::from_u32(cp) {
290                    Some(c) => KeyCode::Char(c),
291                    None => return ParseResult::Invalid,
292                },
293            };
294
295            return ParseResult::Complete(Event::Key(KeyEvent::new(keycode, modifiers)));
296        }
297
298        let (num, modifiers) = self.parse_num_and_modifiers(params);
299
300        // Bracketed paste start: CSI 200 ~
301        if num == 200 {
302            return ParseResult::PasteStart;
303        }
304
305        // Bracketed paste end: CSI 201 ~ (shouldn't appear outside paste mode,
306        // but handle gracefully by ignoring)
307        if num == 201 {
308            return ParseResult::Complete(Event::Key(KeyEvent::new(
309                KeyCode::Null,
310                KeyModifiers::empty(),
311            )));
312        }
313
314        let keycode = match num {
315            1 => KeyCode::Home,
316            2 => KeyCode::Insert,
317            3 => KeyCode::Delete,
318            4 => KeyCode::End,
319            5 => KeyCode::PageUp,
320            6 => KeyCode::PageDown,
321            7 => KeyCode::Home,
322            8 => KeyCode::End,
323            11 => KeyCode::F(1),
324            12 => KeyCode::F(2),
325            13 => KeyCode::F(3),
326            14 => KeyCode::F(4),
327            15 => KeyCode::F(5),
328            17 => KeyCode::F(6),
329            18 => KeyCode::F(7),
330            19 => KeyCode::F(8),
331            20 => KeyCode::F(9),
332            21 => KeyCode::F(10),
333            23 => KeyCode::F(11),
334            24 => KeyCode::F(12),
335            _ => return ParseResult::Invalid,
336        };
337
338        ParseResult::Complete(Event::Key(KeyEvent::new(keycode, modifiers)))
339    }
340
341    /// Parse CSI u (fixterms / kitty keyboard protocol): CSI keycode ; modifiers u
342    ///
343    /// The keycode is a Unicode codepoint. Special codepoints map to functional
344    /// keys (Enter, Tab, Esc, Backspace, etc.); printable codepoints map to
345    /// Char. Modifiers use the same encoding as standard CSI sequences.
346    fn parse_csi_u_sequence(&self, params: &[u8]) -> ParseResult {
347        let params_str = std::str::from_utf8(params).unwrap_or("");
348        let parts: Vec<&str> = params_str.split(';').collect();
349
350        let codepoint: u32 = parts.first().and_then(|s| s.parse().ok()).unwrap_or(0);
351        let mods_param: u8 = parts.get(1).and_then(|s| s.parse().ok()).unwrap_or(1);
352        let modifiers = modifiers_from_param(mods_param);
353
354        let keycode = match codepoint {
355            9 => KeyCode::Tab,
356            13 => KeyCode::Enter,
357            27 => KeyCode::Esc,
358            127 => KeyCode::Backspace,
359            cp => match char::from_u32(cp) {
360                Some(c) => KeyCode::Char(c),
361                None => return ParseResult::Invalid,
362            },
363        };
364
365        ParseResult::Complete(Event::Key(KeyEvent::new(keycode, modifiers)))
366    }
367
368    /// Parse SGR mouse format: CSI < Cb ; Cx ; Cy M/m
369    fn parse_sgr_mouse(&self, params: &[u8], pressed: bool) -> ParseResult {
370        // Skip the '<'
371        let params_str = std::str::from_utf8(&params[1..]).unwrap_or("");
372        let parts: Vec<&str> = params_str.split(';').collect();
373
374        if parts.len() != 3 {
375            return ParseResult::Invalid;
376        }
377
378        let cb: u16 = parts[0].parse().unwrap_or(0);
379        let cx: u16 = parts[1].parse().unwrap_or(1);
380        let cy: u16 = parts[2].parse().unwrap_or(1);
381
382        let button_bits = cb & 0b11;
383        let button = match button_bits {
384            0 => MouseButton::Left,
385            1 => MouseButton::Middle,
386            2 => MouseButton::Right,
387            _ => MouseButton::Left, // 3 = no button (for motion)
388        };
389
390        let modifiers = KeyModifiers::from_bits_truncate(
391            if cb & 4 != 0 {
392                KeyModifiers::SHIFT.bits()
393            } else {
394                0
395            } | if cb & 8 != 0 {
396                KeyModifiers::ALT.bits()
397            } else {
398                0
399            } | if cb & 16 != 0 {
400                KeyModifiers::CONTROL.bits()
401            } else {
402                0
403            },
404        );
405
406        let kind = if cb & 32 != 0 {
407            // Motion event
408            if cb & 64 != 0 {
409                // Scroll while moving (unusual)
410                if cb & 1 != 0 {
411                    MouseEventKind::ScrollDown
412                } else {
413                    MouseEventKind::ScrollUp
414                }
415            } else if button_bits == 3 {
416                // Motion with no button pressed (hover)
417                MouseEventKind::Moved
418            } else {
419                // Motion with button pressed (drag)
420                MouseEventKind::Drag(button)
421            }
422        } else if cb & 64 != 0 {
423            // Scroll
424            if cb & 1 != 0 {
425                MouseEventKind::ScrollDown
426            } else {
427                MouseEventKind::ScrollUp
428            }
429        } else if pressed {
430            MouseEventKind::Down(button)
431        } else {
432            MouseEventKind::Up(button)
433        };
434
435        ParseResult::Complete(Event::Mouse(MouseEvent {
436            kind,
437            column: cx.saturating_sub(1),
438            row: cy.saturating_sub(1),
439            modifiers,
440        }))
441    }
442
443    /// Parse X10 mouse format (legacy)
444    fn parse_x10_mouse(&self) -> ParseResult {
445        let bytes = &self.buffer;
446
447        if bytes.len() < 6 {
448            return ParseResult::Incomplete;
449        }
450
451        let cb = bytes[3].wrapping_sub(32);
452        let cx = bytes[4].wrapping_sub(32);
453        let cy = bytes[5].wrapping_sub(32);
454
455        let button = match cb & 0b11 {
456            0 => MouseButton::Left,
457            1 => MouseButton::Middle,
458            2 => MouseButton::Right,
459            3 => {
460                // Release
461                return ParseResult::Complete(Event::Mouse(MouseEvent {
462                    kind: MouseEventKind::Up(MouseButton::Left),
463                    column: cx as u16,
464                    row: cy as u16,
465                    modifiers: KeyModifiers::empty(),
466                }));
467            }
468            _ => MouseButton::Left,
469        };
470
471        ParseResult::Complete(Event::Mouse(MouseEvent {
472            kind: MouseEventKind::Down(button),
473            column: cx as u16,
474            row: cy as u16,
475            modifiers: KeyModifiers::empty(),
476        }))
477    }
478
479    /// Parse SS3 sequence: ESC O ...
480    fn parse_ss3_sequence(&self) -> ParseResult {
481        let bytes = &self.buffer;
482
483        if bytes.len() < 3 {
484            return ParseResult::Incomplete;
485        }
486
487        let keycode = match bytes[2] {
488            b'P' => KeyCode::F(1),
489            b'Q' => KeyCode::F(2),
490            b'R' => KeyCode::F(3),
491            b'S' => KeyCode::F(4),
492            b'A' => KeyCode::Up,
493            b'B' => KeyCode::Down,
494            b'C' => KeyCode::Right,
495            b'D' => KeyCode::Left,
496            b'H' => KeyCode::Home,
497            b'F' => KeyCode::End,
498            _ => return ParseResult::Invalid,
499        };
500
501        ParseResult::Complete(Event::Key(KeyEvent::new(keycode, KeyModifiers::empty())))
502    }
503
504    /// Parse modifiers from CSI parameters
505    fn parse_modifiers(&self, params: &[u8]) -> KeyModifiers {
506        // Format: [num;modifiers] where modifiers = 1 + (shift) + 2*(alt) + 4*(ctrl)
507        let params_str = std::str::from_utf8(params).unwrap_or("");
508        if let Some(idx) = params_str.find(';') {
509            if let Ok(mods) = params_str[idx + 1..].parse::<u8>() {
510                return modifiers_from_param(mods);
511            }
512        }
513        KeyModifiers::empty()
514    }
515
516    /// Parse number and modifiers from CSI parameters
517    fn parse_num_and_modifiers(&self, params: &[u8]) -> (u8, KeyModifiers) {
518        let params_str = std::str::from_utf8(params).unwrap_or("");
519        let parts: Vec<&str> = params_str.split(';').collect();
520
521        let num = parts.first().and_then(|s| s.parse().ok()).unwrap_or(0);
522        let mods = parts.get(1).and_then(|s| s.parse().ok()).unwrap_or(1);
523
524        (num, modifiers_from_param(mods))
525    }
526
527    /// Convert a single byte to an event
528    fn byte_to_event(&self, byte: u8) -> Option<Event> {
529        let keycode = byte_to_keycode(byte);
530        let modifiers = if byte < 32 && byte != 9 && byte != 10 && byte != 13 && byte != 27 {
531            // Control character (but not Tab, LF, CR, or Esc)
532            KeyModifiers::CONTROL
533        } else {
534            KeyModifiers::empty()
535        };
536
537        Some(Event::Key(KeyEvent::new(keycode, modifiers)))
538    }
539}
540
541/// Result of trying to parse the buffer
542enum ParseResult {
543    /// Successfully parsed a complete event
544    Complete(Event),
545    /// Bracketed paste start marker detected (\x1b[200~)
546    PasteStart,
547    /// Need more bytes to complete the sequence
548    Incomplete,
549    /// Invalid sequence
550    Invalid,
551}
552
553/// Convert a byte to a KeyCode
554fn byte_to_keycode(byte: u8) -> KeyCode {
555    match byte {
556        0 => KeyCode::Char('@'), // Ctrl+@
557        9 => KeyCode::Tab,
558        10 | 13 => KeyCode::Enter,                          // LF or CR
559        1..=26 => KeyCode::Char((b'a' + byte - 1) as char), // Ctrl+A through Ctrl+Z
560        27 => KeyCode::Esc,
561        28..=31 => KeyCode::Char((b'\\' + byte - 28) as char),
562        32 => KeyCode::Char(' '),
563        127 => KeyCode::Backspace,
564        b if (32..127).contains(&b) => KeyCode::Char(b as char),
565        _ => KeyCode::Null,
566    }
567}
568
569/// Convert modifier parameter to KeyModifiers
570fn modifiers_from_param(param: u8) -> KeyModifiers {
571    let param = param.saturating_sub(1);
572    KeyModifiers::from_bits_truncate(
573        if param & 1 != 0 {
574            KeyModifiers::SHIFT.bits()
575        } else {
576            0
577        } | if param & 2 != 0 {
578            KeyModifiers::ALT.bits()
579        } else {
580            0
581        } | if param & 4 != 0 {
582            KeyModifiers::CONTROL.bits()
583        } else {
584            0
585        },
586    )
587}
588
589#[cfg(test)]
590mod tests {
591    use super::*;
592
593    #[test]
594    fn test_simple_characters() {
595        let mut parser = InputParser::new();
596        let events = parser.parse(b"abc");
597        assert_eq!(events.len(), 3);
598        match &events[0] {
599            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Char('a')),
600            _ => panic!("Expected key event"),
601        }
602    }
603
604    #[test]
605    fn test_control_characters_have_ctrl_modifier() {
606        let mut parser = InputParser::new();
607        // Ctrl+C = 0x03
608        let events = parser.parse(&[0x03]);
609        match &events[0] {
610            Event::Key(ke) => {
611                assert_eq!(ke.code, KeyCode::Char('c'));
612                assert!(ke.modifiers.contains(KeyModifiers::CONTROL));
613            }
614            _ => panic!("Expected key event"),
615        }
616    }
617
618    #[test]
619    fn test_escape_buffers_until_complete() {
620        let mut parser = InputParser::new();
621        // ESC alone should buffer
622        assert!(parser.parse(&[0x1b]).is_empty());
623        // Adding more should still buffer
624        assert!(parser.parse(b"[").is_empty());
625        // Final byte completes the sequence
626        let events = parser.parse(b"A");
627        assert_eq!(events.len(), 1);
628        match &events[0] {
629            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Up),
630            _ => panic!("Expected Up key"),
631        }
632    }
633
634    #[test]
635    fn test_csi_sequences_parse_arrow_keys() {
636        let mut parser = InputParser::new();
637        // CSI format: ESC [ <final>
638        let events = parser.parse(b"\x1b[A");
639        match &events[0] {
640            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Up),
641            _ => panic!("Expected key event"),
642        }
643    }
644
645    #[test]
646    fn test_ss3_sequences_parse_function_keys() {
647        let mut parser = InputParser::new();
648        // SS3 format: ESC O <letter>
649        let events = parser.parse(b"\x1bOP");
650        match &events[0] {
651            Event::Key(ke) => assert_eq!(ke.code, KeyCode::F(1)),
652            _ => panic!("Expected key event"),
653        }
654    }
655
656    #[test]
657    fn test_alt_key_via_esc_prefix() {
658        let mut parser = InputParser::new();
659        // Alt+a: ESC a (ESC followed by non-sequence char)
660        let events = parser.parse(b"\x1ba");
661        match &events[0] {
662            Event::Key(ke) => {
663                assert_eq!(ke.code, KeyCode::Char('a'));
664                assert!(ke.modifiers.contains(KeyModifiers::ALT));
665            }
666            _ => panic!("Expected key event"),
667        }
668    }
669
670    #[test]
671    fn test_csi_modifiers_parsed_correctly() {
672        let mut parser = InputParser::new();
673        // Shift+Up: ESC [ 1 ; 2 A (2 = shift)
674        let events = parser.parse(b"\x1b[1;2A");
675        match &events[0] {
676            Event::Key(ke) => {
677                assert_eq!(ke.code, KeyCode::Up);
678                assert!(ke.modifiers.contains(KeyModifiers::SHIFT));
679            }
680            _ => panic!("Expected Shift+Up"),
681        }
682    }
683
684    #[test]
685    fn test_sgr_mouse_events_are_1_indexed() {
686        let mut parser = InputParser::new();
687        // SGR mouse: CSI < button ; x ; y M
688        // Terminal sends 1-indexed, we convert to 0-indexed
689        let events = parser.parse(b"\x1b[<0;10;5M");
690        match &events[0] {
691            Event::Mouse(me) => {
692                assert_eq!(me.column, 9); // 10-1
693                assert_eq!(me.row, 4); // 5-1
694            }
695            _ => panic!("Expected mouse event"),
696        }
697    }
698
699    #[test]
700    fn test_focus_events() {
701        let mut parser = InputParser::new();
702        let events = parser.parse(b"\x1b[I");
703        assert!(matches!(&events[0], Event::FocusGained));
704
705        let events = parser.parse(b"\x1b[O");
706        assert!(matches!(&events[0], Event::FocusLost));
707    }
708
709    #[test]
710    fn test_mixed_input_preserves_order() {
711        let mut parser = InputParser::new();
712        let events = parser.parse(b"a\x1b[Ab");
713        assert_eq!(events.len(), 3);
714        // Order: 'a', Up, 'b'
715        assert!(matches!(&events[0], Event::Key(ke) if ke.code == KeyCode::Char('a')));
716        assert!(matches!(&events[1], Event::Key(ke) if ke.code == KeyCode::Up));
717        assert!(matches!(&events[2], Event::Key(ke) if ke.code == KeyCode::Char('b')));
718    }
719
720    #[test]
721    fn test_enter_key() {
722        let mut parser = InputParser::new();
723        // CR (carriage return) = 0x0D = 13
724        let events = parser.parse(&[0x0D]);
725        match &events[0] {
726            Event::Key(ke) => {
727                assert_eq!(ke.code, KeyCode::Enter);
728                assert!(ke.modifiers.is_empty());
729            }
730            _ => panic!("Expected Enter key event"),
731        }
732
733        // LF (line feed) = 0x0A = 10
734        let events = parser.parse(&[0x0A]);
735        match &events[0] {
736            Event::Key(ke) => {
737                assert_eq!(ke.code, KeyCode::Enter);
738                assert!(ke.modifiers.is_empty());
739            }
740            _ => panic!("Expected Enter key event"),
741        }
742    }
743
744    #[test]
745    fn test_tab_key() {
746        let mut parser = InputParser::new();
747        // Tab = 0x09 = 9
748        let events = parser.parse(&[0x09]);
749        match &events[0] {
750            Event::Key(ke) => {
751                assert_eq!(ke.code, KeyCode::Tab);
752                assert!(ke.modifiers.is_empty());
753            }
754            _ => panic!("Expected Tab key event"),
755        }
756    }
757
758    #[test]
759    fn test_mouse_motion_without_button() {
760        let mut parser = InputParser::new();
761        // SGR mouse motion with no button: CSI < 35 ; x ; y M
762        // 35 = 32 (motion) + 3 (no button)
763        let events = parser.parse(b"\x1b[<35;10;5M");
764        match &events[0] {
765            Event::Mouse(me) => {
766                assert!(matches!(me.kind, MouseEventKind::Moved));
767                assert_eq!(me.column, 9); // 10 - 1 (0-indexed)
768                assert_eq!(me.row, 4); // 5 - 1 (0-indexed)
769            }
770            _ => panic!("Expected mouse motion event"),
771        }
772    }
773
774    // ---- Regression tests for issue #1089 ----
775
776    #[test]
777    fn test_shift_tab_csi_z() {
778        let mut parser = InputParser::new();
779        // Shift+Tab sends CSI Z = ESC [ Z
780        let events = parser.parse(b"\x1b[Z");
781        assert_eq!(events.len(), 1);
782        match &events[0] {
783            Event::Key(ke) => {
784                assert_eq!(ke.code, KeyCode::BackTab);
785                assert!(ke.modifiers.contains(KeyModifiers::SHIFT));
786            }
787            _ => panic!("Expected BackTab key event, got {:?}", events[0]),
788        }
789    }
790
791    #[test]
792    fn test_esc_then_mouse_event_same_chunk() {
793        let mut parser = InputParser::new();
794        // User presses Escape, then moves mouse. Both arrive in one chunk:
795        // ESC (0x1b) followed by mouse event ESC [ < 35 ; 67 ; 18 M
796        let events = parser.parse(b"\x1b\x1b[<35;67;18M");
797        assert_eq!(
798            events.len(),
799            2,
800            "Expected Escape + mouse event, got: {:?}",
801            events
802        );
803
804        // First event: standalone Escape
805        match &events[0] {
806            Event::Key(ke) => {
807                assert_eq!(ke.code, KeyCode::Esc);
808                assert!(ke.modifiers.is_empty());
809            }
810            _ => panic!("Expected Esc key event, got {:?}", events[0]),
811        }
812
813        // Second event: mouse motion
814        match &events[1] {
815            Event::Mouse(me) => {
816                assert!(matches!(me.kind, MouseEventKind::Moved));
817                assert_eq!(me.column, 66); // 67 - 1
818                assert_eq!(me.row, 17); // 18 - 1
819            }
820            _ => panic!("Expected mouse motion event, got {:?}", events[1]),
821        }
822    }
823
824    #[test]
825    fn test_esc_then_mouse_event_separate_chunks() {
826        let mut parser = InputParser::new();
827
828        // First chunk: standalone ESC (buffered, waiting for more bytes)
829        let events = parser.parse(&[0x1b]);
830        assert!(events.is_empty(), "ESC should be buffered");
831
832        // Second chunk: mouse event arrives later
833        let events = parser.parse(b"\x1b[<35;67;18M");
834        assert_eq!(
835            events.len(),
836            2,
837            "Expected Escape + mouse event, got: {:?}",
838            events
839        );
840
841        // First event: standalone Escape (disambiguated by seeing another ESC)
842        match &events[0] {
843            Event::Key(ke) => {
844                assert_eq!(ke.code, KeyCode::Esc);
845                assert!(ke.modifiers.is_empty());
846            }
847            _ => panic!("Expected Esc key event, got {:?}", events[0]),
848        }
849
850        // Second event: mouse motion
851        match &events[1] {
852            Event::Mouse(me) => {
853                assert!(matches!(me.kind, MouseEventKind::Moved));
854            }
855            _ => panic!("Expected mouse motion event, got {:?}", events[1]),
856        }
857    }
858
859    #[test]
860    fn test_esc_then_csi_arrow_separate_chunks() {
861        let mut parser = InputParser::new();
862
863        // ESC buffered
864        let events = parser.parse(&[0x1b]);
865        assert!(events.is_empty());
866
867        // Arrow key sequence arrives (starts with another ESC)
868        let events = parser.parse(b"\x1b[A");
869        assert_eq!(events.len(), 2, "Expected Escape + Up, got: {:?}", events);
870
871        match &events[0] {
872            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Esc),
873            _ => panic!("Expected Esc"),
874        }
875        match &events[1] {
876            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Up),
877            _ => panic!("Expected Up"),
878        }
879    }
880
881    #[test]
882    fn test_esc_waits_for_next_byte() {
883        let mut parser = InputParser::new();
884
885        // ESC buffered
886        let events = parser.parse(&[0x1b]);
887        assert!(events.is_empty());
888
889        // Buffer still has the ESC
890        assert_eq!(parser.buffer.len(), 1);
891
892        // Next byte `[` disambiguates: it's a CSI sequence, not standalone ESC
893        let events = parser.parse(b"[A");
894        assert_eq!(events.len(), 1);
895        match &events[0] {
896            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Up),
897            _ => panic!("Expected Up"),
898        }
899    }
900
901    #[test]
902    fn test_esc_then_printable_byte_emits_alt_key() {
903        let mut parser = InputParser::new();
904
905        // ESC buffered
906        let events = parser.parse(&[0x1b]);
907        assert!(events.is_empty());
908
909        // Next byte `a` completes the sequence as Alt+a (standard terminal behavior)
910        let events = parser.parse(b"a");
911        assert_eq!(events.len(), 1);
912        match &events[0] {
913            Event::Key(ke) => {
914                assert_eq!(ke.code, KeyCode::Char('a'));
915                assert!(ke.modifiers.contains(KeyModifiers::ALT));
916            }
917            _ => panic!("Expected Alt+a"),
918        }
919    }
920
921    #[test]
922    fn test_esc_then_esc_emits_standalone_esc() {
923        let mut parser = InputParser::new();
924
925        // First ESC buffered
926        let events = parser.parse(&[0x1b]);
927        assert!(events.is_empty());
928
929        // Second ESC: first ESC is standalone, second starts new sequence
930        let events = parser.parse(&[0x1b]);
931        assert_eq!(events.len(), 1);
932        match &events[0] {
933            Event::Key(ke) => {
934                assert_eq!(ke.code, KeyCode::Esc);
935                assert!(ke.modifiers.is_empty());
936            }
937            _ => panic!("Expected standalone Esc"),
938        }
939        // Second ESC still buffered
940        assert_eq!(parser.buffer, vec![0x1b]);
941    }
942
943    #[test]
944    fn test_split_mouse_sequence_across_batches() {
945        let mut parser = InputParser::new();
946
947        // Batch 1: just the ESC byte (split at batch boundary)
948        let events = parser.parse(&[0x1b]);
949        assert!(events.is_empty());
950        assert_eq!(parser.buffer.len(), 1);
951
952        // Batch 2: rest of mouse sequence arrives
953        let events = parser.parse(b"[<35;42;5M");
954        assert_eq!(events.len(), 1);
955        match &events[0] {
956            Event::Mouse(_) => {} // Mouse event parsed correctly
957            other => panic!("Expected mouse event, got {:?}", other),
958        }
959    }
960
961    #[test]
962    fn test_partial_csi_sequence_not_flushed() {
963        let mut parser = InputParser::new();
964
965        // Partial CSI mouse sequence (split across batches)
966        let events = parser.parse(b"\x1b[<35;");
967        assert!(events.is_empty());
968        assert_eq!(parser.buffer.len(), 6);
969
970        // Now the rest of the sequence arrives
971        let events = parser.parse(b"42;5M");
972        assert_eq!(events.len(), 1);
973        match &events[0] {
974            Event::Mouse(me) => {
975                assert_eq!(me.column, 41); // 42 - 1 (1-indexed to 0-indexed)
976                assert_eq!(me.row, 4); // 5 - 1
977            }
978            _ => panic!("Expected mouse event, got {:?}", events[0]),
979        }
980    }
981
982    #[test]
983    fn test_esc_then_mouse_click() {
984        let mut parser = InputParser::new();
985        // ESC followed by mouse button press: ESC [ < 0 ; 10 ; 5 M
986        let events = parser.parse(b"\x1b\x1b[<0;10;5M");
987        assert_eq!(
988            events.len(),
989            2,
990            "Expected Escape + mouse click, got: {:?}",
991            events
992        );
993
994        match &events[0] {
995            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Esc),
996            _ => panic!("Expected Esc"),
997        }
998        match &events[1] {
999            Event::Mouse(me) => {
1000                assert!(matches!(me.kind, MouseEventKind::Down(MouseButton::Left)));
1001            }
1002            _ => panic!("Expected mouse down event, got {:?}", events[1]),
1003        }
1004    }
1005
1006    // ---- Bracketed paste tests ----
1007
1008    #[test]
1009    fn test_bracketed_paste_simple() {
1010        let mut parser = InputParser::new();
1011        // Bracketed paste: \x1b[200~ ... \x1b[201~
1012        let events = parser.parse(b"\x1b[200~Hello, world!\x1b[201~");
1013        assert_eq!(events.len(), 1, "Expected 1 paste event, got: {:?}", events);
1014        match &events[0] {
1015            Event::Paste(text) => assert_eq!(text, "Hello, world!"),
1016            _ => panic!("Expected Paste event, got {:?}", events[0]),
1017        }
1018    }
1019
1020    #[test]
1021    fn test_bracketed_paste_with_newlines() {
1022        let mut parser = InputParser::new();
1023        let events = parser.parse(b"\x1b[200~line1\nline2\nline3\x1b[201~");
1024        assert_eq!(events.len(), 1);
1025        match &events[0] {
1026            Event::Paste(text) => assert_eq!(text, "line1\nline2\nline3"),
1027            _ => panic!("Expected Paste event"),
1028        }
1029    }
1030
1031    #[test]
1032    fn test_bracketed_paste_split_across_chunks() {
1033        let mut parser = InputParser::new();
1034
1035        // Start marker arrives
1036        let events = parser.parse(b"\x1b[200~Hello");
1037        assert!(events.is_empty(), "Paste not complete yet");
1038
1039        // More content
1040        let events = parser.parse(b", world!");
1041        assert!(events.is_empty(), "Paste not complete yet");
1042
1043        // End marker arrives
1044        let events = parser.parse(b"\x1b[201~");
1045        assert_eq!(events.len(), 1);
1046        match &events[0] {
1047            Event::Paste(text) => assert_eq!(text, "Hello, world!"),
1048            _ => panic!("Expected Paste event"),
1049        }
1050    }
1051
1052    #[test]
1053    fn test_bracketed_paste_followed_by_keypress() {
1054        let mut parser = InputParser::new();
1055        // Paste followed by a regular keypress
1056        let events = parser.parse(b"\x1b[200~pasted\x1b[201~a");
1057        assert_eq!(
1058            events.len(),
1059            2,
1060            "Expected paste + key event, got: {:?}",
1061            events
1062        );
1063        match &events[0] {
1064            Event::Paste(text) => assert_eq!(text, "pasted"),
1065            _ => panic!("Expected Paste event"),
1066        }
1067        match &events[1] {
1068            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Char('a')),
1069            _ => panic!("Expected key event"),
1070        }
1071    }
1072
1073    #[test]
1074    fn test_bracketed_paste_empty() {
1075        let mut parser = InputParser::new();
1076        let events = parser.parse(b"\x1b[200~\x1b[201~");
1077        assert_eq!(events.len(), 1);
1078        match &events[0] {
1079            Event::Paste(text) => assert_eq!(text, ""),
1080            _ => panic!("Expected empty Paste event"),
1081        }
1082    }
1083
1084    #[test]
1085    fn test_bracketed_paste_with_escape_sequences_inside() {
1086        let mut parser = InputParser::new();
1087        // Pasted text might contain escape sequences (e.g., colored text from another terminal)
1088        let events = parser.parse(b"\x1b[200~\x1b[31mred text\x1b[0m\x1b[201~");
1089        assert_eq!(events.len(), 1);
1090        match &events[0] {
1091            Event::Paste(text) => assert_eq!(text, "\x1b[31mred text\x1b[0m"),
1092            _ => panic!("Expected Paste event with escape sequences"),
1093        }
1094    }
1095
1096    #[test]
1097    fn test_keypress_then_bracketed_paste() {
1098        let mut parser = InputParser::new();
1099        let events = parser.parse(b"x\x1b[200~pasted\x1b[201~");
1100        assert_eq!(events.len(), 2);
1101        match &events[0] {
1102            Event::Key(ke) => assert_eq!(ke.code, KeyCode::Char('x')),
1103            _ => panic!("Expected key event"),
1104        }
1105        match &events[1] {
1106            Event::Paste(text) => assert_eq!(text, "pasted"),
1107            _ => panic!("Expected Paste event"),
1108        }
1109    }
1110}