Repository navigation
fix(tui): normalize CR and CRLF line endings in a paste - #41
TaewoooPark merged 2 commits into
Conversation
xterm.js turns a clipboard's line breaks into CR before bracketed paste, so Composer.paste() inserted raw CRs. A CR moves the cursor to the start of the row when drawn, so later lines overwrote earlier ones and the cursor no longer matched the draft. paste() now converts CRLF and lone CR to LF before counting lines, collapsing long pastes and inserting, so all three line-ending variants produce the same draft, placeholder line count and prompt-history entry. Ordinary Enter handling is unchanged. Fixes TaewoooPark#30 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
xterm.js delivers a clipboard line break as CR inside bracketed paste. Drawing that byte moves the cursor to the start of the row, so later lines cover earlier ones. These tests decode a real bracketed paste, hand it to the composer, and paint it with Screen into a headless terminal. CR, CRLF, and LF stay on separate rows, the cursor stays on the last line, and a short paste can still be edited and submitted.
|
Thanks @nimbly1 for the focused fix and regression tests! Reviewed Live Motif model testing is currently unavailable because the Infron endpoint is unavailable to us. This review did not make live model calls. The changed paste normalization, rendering, editing, history, and submitted-text behavior can be verified without a live model, so I have decided to merge based on that independent evidence. All five new regressions failed on the unchanged base and passed on this head. The full local suite passed (1,644 tests), as did typecheck, build, and tool-schema lint. I also compared the actual built CLI on a macOS PTY in visible xterm.js 6: Korean/emoji multiline paste, cursor movement/deletion, history, and a 30-line collapsed paste worked correctly, with the full normalized text verified at a localhost response fixture. All five CI jobs passed: https://github.com/TaewoooPark/Motifcode/actions/runs/37177849187 . The Python job retains five optional GPU-only skips; this is not live-model or GPU inference validation. No blocking regression or unrelated scope expansion found. Merging as a squash commit. This merges the fix into main; it does not publish an npm release. |
Fixes #30
Bracketed paste keeps the bytes the terminal sends. xterm.js turns a clipboard line break into CR before those markers, and
Composer.paste()counted and inserted only on LF. A CR painted into a row moves the cursor to the start of that row, so later lines cover earlier ones and the cursor no longer matches the draft. A typed Enter is unchanged: the key decoder still reports a bare CR asenter.paste()now converts CRLF and a lone CR to LF before it counts lines, collapses a long paste, or inserts text. The draft, the placeholder line count, and the text sent to the model all use that form.Tests:
Screen. All three lines stay visible and the cursor stays on the last line for CR, CRLF, and LF. A short paste can still be edited and submitted.tsc --noEmitpasses.vitest run packages/tui: 177 tests passed.