Skip to content

fix(terminal): offer paste on the terminal right-click menu - #5240

Open
StiensWout wants to merge 2 commits into
pingdotgg:mainfrom
StiensWout:fix/terminal-context-menu-paste
Open

fix(terminal): offer paste on the terminal right-click menu#5240
StiensWout wants to merge 2 commits into
pingdotgg:mainfrom
StiensWout:fix/terminal-context-menu-paste

Conversation

@StiensWout

@StiensWout StiensWout commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

The bug

Right-clicking the terminal with nothing selected gives you no way to paste.

The terminal's own popup only appears after a selection (Add to chat / Copy), so an empty prompt falls through to the platform default — and both defaults decide their Paste entry from whether the right-clicked node is editable:

  • Desktop: DesktopWindow builds its editing menu from params.editFlags.canPaste. The right-click target is the terminal <canvas>, so canPaste is false and Paste renders greyed out.
  • Browser: Chromium's own menu offers no Paste over a canvas at all.

Either way the shell is focused and perfectly ready for input — Cmd+V / Ctrl+Shift+V works — but the menu says otherwise.

The fix

GhosttyTerminalSurface now forwards a right-click its host application did not claim to an optional onContextMenu. Sessions with mouse reporting on (vim, htop, …) still consume the event exactly as before, so nothing changes under a mouse-tracking app.

TerminalViewport answers with its own menu, positioned at the pointer and routed through localApi.contextMenu — native on desktop, the DOM fallback in the browser:

no selection selection
Add to chat disabled
Copy disabled
Paste

The item set is constant so the entries never move under the cursor. Paste reads the clipboard and goes through surface.paste(), which applies Ghostty's bracketed-paste encoding — the same path the native paste event and the paste shortcut already use, including the token bump that keeps a shortcut-driven clipboard read from doubling the text. A denied or unavailable clipboard read is reported in the terminal instead of failing silently.

Handling the event in the renderer also means preventDefault() suppresses Chromium's context-menu IPC, so the desktop app no longer pops its unusable editing menu over the terminal.

Copy / Add to chat share one implementation with the existing selection popup rather than being duplicated.

Validation

  • vp test run on the touched web tests plus localApi and the context-menu fallback — 43 passing, including new coverage for the enabled/disabled item set
  • tsgo --noEmit for @t3tools/web, targeted lint and formatting

Note

Medium Risk
Touches terminal input, clipboard read permissions, and context-menu gesture races with selection popups and paste shortcuts; scope is localized to the web terminal UI with tests for menu items.

Overview
Fixes right-click paste on the Ghostty terminal canvas by replacing the platform default (browser/Electron menus that cannot paste into a non-editable canvas) with an in-app context menu via localApi.contextMenu.

The menu always shows Add to chat, Copy, and Paste; selection actions stay disabled until text is selected. Paste uses a new readTextFromClipboard helper and GhosttyTerminalSurface.pasteFromClipboard, sharing bracketed-paste encoding and paste-race handling with keyboard/native paste. Right-click calls preventDefault, cancels pending selection popups, and onContextMenu on the surface only runs when mouse reporting is off (vim/htop unchanged).

Copy / Add to chat are centralized helpers reused by the selection popup and the new menu.

Reviewed by Cursor Bugbot for commit 0ab8f9e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Paste to the terminal right-click context menu

  • Adds a custom right-click context menu to the terminal canvas with Add to chat, Copy, and Paste items; Add to chat and Copy are only enabled when there is a selection.
  • Paste reads clipboard text via a new readTextFromClipboard helper in useCopyToClipboard.ts and sends it to the terminal as a bracketed paste via a new pasteFromClipboard method on GhosttyTerminalSurface.
  • Clipboard read/write errors surface as system messages in the thread; terminal focus is restored after each action.
  • The GhosttyTerminalSurface now forwards unclaimed right-click events (i.e. not consumed by mouse reporting) to an optional onContextMenu host callback.

Macroscope summarized 0ab8f9e.

Screenshots

Captured against a real PTY in the web client (Chromium, browser context menu path), same terminal content and same right-click position in both shots.

Right-click the prompt with nothing typed and nothing selected

Before After
right-clicking the empty terminal prompt produces no in-app menu the same right-click now opens a menu with Add to chat and Copy disabled and Paste enabled
No in-app menu. The gesture falls through to the platform default, which offers no reachable Paste over a canvas — greyed out in the desktop editing menu, absent in the browser's. Add to chat and Copy stay disabled with no selection; Paste is available.

Paste reaches the shell — chosen from the menu above, arriving bracketed-paste encoded:

the pasted command sitting at the shell prompt with bracketed-paste highlighting

With a selection — every action enabled, the selection survives the right-click:

terminal context menu with Add to chat, Copy and Paste all enabled while a word is selected

Right-clicking the terminal with nothing selected offered no way to
paste. The selection popup only appears after text is selected, so an
empty prompt fell through to the platform default — and both defaults
key their Paste entry on the right-clicked node being editable. The
terminal is a canvas, so Electron's editing menu rendered Paste greyed
out and the browser menu offered none at all, even though the shell was
focused and ready for input.

The surface now hands unclaimed right-clicks to its host (mouse-reporting
sessions still consume them, unchanged), and the drawer answers with its
own menu: Add to chat and Copy stay selection-only, Paste is always
available and writes through Ghostty's bracketed-paste encoding — the
same path the native paste event and the paste shortcut already take.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 94697075-b9d0-4a12-9450-32e0735a4a17

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 2, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 518b95f. Configure here.

Comment thread apps/web/src/components/ThreadTerminalDrawer.tsx Outdated
@macroscopeapp

macroscopeapp Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds new user-facing functionality (paste option in terminal right-click menu) rather than fixing existing behavior. It introduces new async workflows, clipboard reading infrastructure, and race condition handling that warrant human review.

You can customize Macroscope's approvability policy. Learn more.

The context-menu paste read the clipboard outside the token protocol and
only claimed it once the text was already in hand. A paste shortcut or
native paste event arriving during that read therefore could not
supersede it, so an ordering where the shortcut resolved first delivered
both.

The surface now owns the read: `pasteFromClipboard` claims the token
before starting it and drops its own result if anything paste-like
landed meanwhile, matching how the shortcut path already yields to the
native paste event. The newest gesture wins and exactly one delivery
reaches the shell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant