Skip to content

fix(shell): paste through terminal.paste() and stop swallowing native paste - #1007

Open
mayankdebnath wants to merge 1 commit into
siteboon:mainfrom
mayankdebnath:fix/shell-paste-bracketed
Open

fix(shell): paste through terminal.paste() and stop swallowing native paste#1007
mayankdebnath wants to merge 1 commit into
siteboon:mainfrom
mayankdebnath:fix/shell-paste-bracketed

Conversation

@mayankdebnath

@mayankdebnath mayankdebnath commented Jul 12, 2026

Copy link
Copy Markdown

Summary

Fixes #1006 — two independent paste bugs in the Shell terminal:

  1. Multi-line pastes executed line-by-line. Both paste paths (Ctrl/Cmd+V
    handler and the mobile shortcuts-panel Paste button) sent raw clipboard text
    as a socket input message, bypassing xterm's bracketed-paste wrapping
    (DECSET 2004) and \n\r normalization. Apps that enable bracketed paste
    — Claude Code's CLI, modern shells, vim — treated every newline as Enter:
    pasting a 5-line prompt into claude submitted it 5 times.
  2. Cmd+V / Ctrl+Shift+V pasted nothing on plain-HTTP deployments. The key
    handler unconditionally cancelled the chord but only injected text when
    navigator.clipboard.readText exists — which it doesn't outside secure
    contexts, i.e. on the common self-hosted http://<lan-ip>:3001 setup. The
    cancelled keydown also suppressed the browser's native paste event that
    would have reached xterm's hidden textarea and pasted fine. (Right-click →
    Paste always worked, because only the keydown was intercepted.)

The fix

  • Route both paths through terminal.paste(text). xterm applies bracketed-
    paste wrapping and newline normalization, then emits onData, which already
    flows to the pty through the existing socket input subscription — so the wire
    protocol is unchanged.
  • In the key handler, only intercept the paste chord when the async clipboard
    API is actually usable; otherwise return true so the native paste event
    reaches xterm's textarea (xterm handles bracketed paste for that path
    itself). Plain Ctrl+V (no Shift) intentionally remains xterm's literal ^V,
    matching normal terminal semantics.

Two files, no dependency or protocol changes.

Verification

  • npm run lint (0 errors), npm run typecheck, npm run build, full
    node:test suite — all pass.
  • Behavior of terminal.paste() confirmed against the bundled xterm 5.5.0
    source: replace(/\r?\n/g, "\r") plus \x1b[200~…\x1b[201~ wrapping when
    DECSET 2004 is active, emitted via the normal data event.

Related history: #767 (macOS Cmd+V paste failing in the terminal).

Summary by CodeRabbit

  • Bug Fixes
    • Improved terminal paste handling when clipboard access is unavailable by allowing native paste to proceed.
    • Updated desktop and mobile paste actions to preserve terminal formatting, including bracketed-paste behavior and newline normalization.
    • Improved compatibility with terminal applications that rely on standard paste semantics.

… paste

Both shell paste paths (the Ctrl/Cmd+V handler and the mobile shortcuts-panel
Paste button) sent raw clipboard text as a socket input message, bypassing
xterm's bracketed-paste wrapping (DECSET 2004) and newline normalization —
multi-line pastes submitted or executed line-by-line in Claude Code's CLI,
shells, and vim. Route both through terminal.paste(), whose onData output
flows to the pty via the existing socket input subscription.

The key handler also unconditionally cancelled the paste chord even when
navigator.clipboard.readText was unavailable (plain-HTTP deployments have no
navigator.clipboard), pasting nothing while suppressing the browser's native
paste event that would have reached xterm's hidden textarea. Only intercept
the chord when the async clipboard API is actually usable; otherwise let the
native path handle it.

Fixes siteboon#1006
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ccdb1129-4cc0-4507-9634-eab43bdc0212

📥 Commits

Reviewing files that changed from the base of the PR and between 5884573 and b8b719d.

📒 Files selected for processing (2)
  • src/components/shell/hooks/useShellTerminal.ts
  • src/components/shell/view/subcomponents/TerminalShortcutsPanel.tsx

📝 Walkthrough

Walkthrough

Changes

Terminal paste handling

Layer / File(s) Summary
Route clipboard text through xterm
src/components/shell/hooks/useShellTerminal.ts, src/components/shell/view/subcomponents/TerminalShortcutsPanel.tsx
Keyboard paste falls back to native handling when the Clipboard API is unavailable; available clipboard text and mobile shortcut pastes now use xterm’s paste() path for bracketed-paste wrapping and newline normalization.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant PasteHandler
  participant ClipboardAPI
  participant Xterm
  participant PTY
  User->>PasteHandler: Paste shortcut or mobile paste
  PasteHandler->>ClipboardAPI: readText()
  ClipboardAPI-->>PasteHandler: clipboard text
  PasteHandler->>Xterm: paste(text)
  Xterm->>PTY: normalized bracketed input
Loading

Suggested reviewers: viper151

Poem

I’m a rabbit with paste in my paws,
Lines now hop through xterm’s laws.
Brackets wrap, newlines behave,
HTTP paste gets a native wave.
One neat nibble, safely sent—
Hoppy shells are glad again!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the PR’s main shell paste behavior changes.
Linked Issues check ✅ Passed The changes address #1006 by routing both paste paths through terminal.paste() and allowing native paste when the Clipboard API is unavailable.
Out of Scope Changes check ✅ Passed The PR stays narrowly focused on shell paste handling and only modifies the two relevant shell components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shell: multi-line pastes execute line-by-line (bracketed paste bypassed) and Cmd+V/Ctrl+Shift+V paste nothing on plain-HTTP deployments

1 participant