fix(terminal): offer paste on the terminal right-click menu - #5240
fix(terminal): offer paste on the terminal right-click menu#5240StiensWout wants to merge 2 commits into
Conversation
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>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ 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.
ApprovabilityVerdict: 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>

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:
DesktopWindowbuilds its editing menu fromparams.editFlags.canPaste. The right-click target is the terminal<canvas>, socanPasteis false and Paste renders greyed out.Either way the shell is focused and perfectly ready for input —
Cmd+V/Ctrl+Shift+Vworks — but the menu says otherwise.The fix
GhosttyTerminalSurfacenow forwards a right-click its host application did not claim to an optionalonContextMenu. Sessions with mouse reporting on (vim, htop, …) still consume the event exactly as before, so nothing changes under a mouse-tracking app.TerminalViewportanswers with its own menu, positioned at the pointer and routed throughlocalApi.contextMenu— native on desktop, the DOM fallback in the browser: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'scontext-menuIPC, 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 runon the touched web tests pluslocalApiand the context-menu fallback — 43 passing, including new coverage for the enabled/disabled item settsgo --noEmitfor@t3tools/web, targeted lint and formattingNote
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
readTextFromClipboardhelper andGhosttyTerminalSurface.pasteFromClipboard, sharing bracketed-paste encoding and paste-race handling with keyboard/native paste. Right-click callspreventDefault, cancels pending selection popups, andonContextMenuon 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
readTextFromClipboardhelper inuseCopyToClipboard.tsand sends it to the terminal as a bracketed paste via a newpasteFromClipboardmethod onGhosttyTerminalSurface.GhosttyTerminalSurfacenow forwards unclaimed right-click events (i.e. not consumed by mouse reporting) to an optionalonContextMenuhost 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
Paste reaches the shell — chosen from the menu above, arriving bracketed-paste encoded:
With a selection — every action enabled, the selection survives the right-click: