fix: capture bracketed paste so multi-line paste can't infinite-loop (#60)#70
Conversation
…60) Pasting multi-line text into the REPL sent the pasted newlines through readline as `enter` keypresses, each firing a submit — so a paste "cycled round and round" as many rapid submissions that couldn't be interrupted. Enable bracketed paste mode (ESC[?2004h) so the terminal wraps a paste in ESC[200~ … ESC[201~; readline surfaces these as `paste-start`/`paste-end`. We now capture everything between the markers as a single paste and route it through the existing #53 paste-store (placeholder for large/multi-line, inline for small), so pasted newlines never submit. A real Enter outside a paste still submits. - input.ts: paste-start/paste-end capture in onKeypress; shared insertPaste() (also used by Ctrl+V); enable on start/resume, disable on pause/close (TTY only); reset capture state on pause. Tests (textarea-bracketed-paste.test.ts): multi-line paste does not submit on its newlines (the bug), atomic-placeholder backspace, small paste inlines, paste interleaved with typed text, normal Enter still submits, empty paste, and enable/disable escape sequences emitted on start/close/pause/resume (TTY). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
✅ VerificationFull suite + typecheck + lint (clean)
Paste tests (15; Ctrl+V refactor kept green + 8 new bracketed-paste)Root cause confirmed empiricallyFeeding The pasted Behavior confirmed
This stops multi-line paste from firing a burst of submissions (the un-interruptible loop), while composing with #53's placeholder handling. |
|
✅ PR OK — verified end-to-end (posted as comment; GitHub blocks self-approval). Closes #60: the un-killable multi-line-paste loop. Root cause correctly diagnosed — without bracketed-paste mode each pasted newline becomes an Fix verified:
Note: even if a given terminal delivered Verification: build ✓ · typecheck ✓ · lint ✓ · full suite 694/694 · 8 new behavioral tests (the bug, empty paste, interleaved typing, normal-Enter, atomic backspace, TTY enable/disable wiring) · Severe bug, correctly fixed, well-tested, cleanly composed with the paste-store. LGTM. |
Closes #60.
Problem
Pasting a long/multi-line block into the interactive REPL "cycled round and round" un-killably. Root cause: without bracketed-paste mode, the terminal sends the pasted text raw, and readline turns each pasted newline into an
enterkeypress → each fires a submit. A 20-line paste = 20 rapid submissions (each a new prompt / mid-run steer), which reads as an infinite loop that Ctrl+C/Esc can't catch between submissions.Fix
Enable bracketed paste mode (
ESC[?2004h) so the terminal wraps a paste inESC[200~ … ESC[201~. Node's readline surfaces these aspaste-start/paste-endkeypresses (verified empirically). The textarea now:paste-start, enters capture mode.\n) without handling them as keystrokes — so pasted newlines never submit.paste-end, inserts the captured text via the same path as Ctrl+V (insertPaste): large/multi-line → a compact placeholder token from the Paste: store large multiline pastes internally and show a placeholder in the textarea #53 paste-store (expanded at submit); small single-line → inline.A real Enter outside a paste still submits normally. Enable/disable is emitted on start/resume and torn down on pause/close (TTY only), and capture state is reset on pause so a half-captured paste can't strand the flag.
This composes with #53: bracketed pastes get the same placeholder treatment, so the input frame stays intact and the original newlines survive to submit.
Tests —
packages/cli/tests/textarea-bracketed-paste.test.ts(8)Behavioral (real
createTextarea+ fake stdin emitting the paste-start/content/paste-end sequence):startimmediatelyend) doesn't strand capture stateTTY wiring:
ESC[?2004h) on start, disable (ESC[?2004l) on closeVerification
insertPastekeeps all existing paste tests green).ESC[?2004hships in the builtdistbundle.🤖 Generated with Claude Code