diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-03-31 13:54:23 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-03-31 13:54:23 +0300 |
| commit | b2293687afa4ba268eac98bf885bf6e5a5133180 (patch) | |
| tree | 58fb49e735889ae55fe9f0387ebaf4b511a5aee3 /src | |
| parent | f8c452294d6f76ccb264c0d9e205398492f00e18 (diff) | |
fix: preserve incomplete bracketed paste across read timeouts
Diffstat (limited to 'src')
| -rw-r--r-- | src/raw_input.rs | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/src/raw_input.rs b/src/raw_input.rs index 48b9547c..859f4c26 100644 --- a/src/raw_input.rs +++ b/src/raw_input.rs @@ -63,6 +63,13 @@ fn flush_incomplete_buffer(buffer: &mut Vec<u8>, tx: &mpsc::Sender<RawInputEvent return; } + if buffer.starts_with(BRACKETED_PASTE_START) + && find_subsequence(buffer, BRACKETED_PASTE_END).is_none() + { + tracing::trace!(len = buffer.len(), "waiting for bracketed paste terminator"); + return; + } + if buffer.as_slice() == [ESC] { let _ = tx.blocking_send(RawInputEvent::Key(TerminalKey::new( crossterm::event::KeyCode::Esc, @@ -662,6 +669,29 @@ mod tests { } #[test] + fn incomplete_bracketed_paste_is_not_flushed_on_timeout() { + let (tx, mut rx) = mpsc::channel(8); + let mut buffer = Vec::new(); + + drain_chunk(&mut buffer, &tx, b"\x1b[200~hello\nworld"); + assert_eq!(buffer, b"\x1b[200~hello\nworld"); + assert!(collect_events(&mut rx).is_empty()); + + flush_incomplete_buffer(&mut buffer, &tx); + assert_eq!(buffer, b"\x1b[200~hello\nworld"); + assert!(collect_events(&mut rx).is_empty()); + + drain_chunk(&mut buffer, &tx, b"\x1b[201~"); + assert!(buffer.is_empty()); + let events = collect_events(&mut rx); + assert_eq!(events.len(), 1); + let RawInputEvent::Paste(text) = &events[0] else { + panic!("expected paste"); + }; + assert_eq!(text, "hello\nworld"); + } + + #[test] fn chunked_utf8_waits_for_continuation_byte() { let (tx, mut rx) = mpsc::channel(8); let mut buffer = Vec::new(); |
