Skip to content

fix(web): middle-click pastes in the terminal on Linux - #11018

Merged
maria-rcks merged 2 commits into
pingdotgg:mainfrom
maria-rcks:fix/terminal-middle-click-paste-10921
Sep 10, 2026
Merged

fix(web): middle-click pastes in the terminal on Linux#11018
maria-rcks merged 2 commits into
pingdotgg:mainfrom
maria-rcks:fix/terminal-middle-click-paste-10921

Conversation

@maria-rcks

@maria-rcks maria-rcks commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Middle-clicking the integrated terminal did nothing: onPointerDown in apps/web/src/terminal/ghostty/surface.ts returned early for any button but 0, so the standard Linux middle-click paste never ran and Chromium started autoscroll instead.

Middle click on Linux/BSD now pastes the terminal's own Ghostty selection through pasteFromClipboard, the same bracketed-paste path (and paste race token) used by Ctrl+Shift+V, Shift+Insert, and the right-click menu. With nothing selected in the terminal it does nothing: a browser cannot read the X11/Wayland PRIMARY buffer, and CLIPBOARD is deliberately not substituted, so this never emits text the user only copied. Applications that track the mouse (vim, less) still receive the middle-button press instead of a paste.

This covers in-terminal selections only. External PRIMARY is not wired: reading a highlight made in another Linux app needs Electron clipboard.readText('selection') (and a matching writer on selection change) plus a desktop IPC channel, which is not part of this PR. Middle-clicking with no terminal selection stays a no-op rather than pasting the wrong buffer.

Two details worth reviewing: pointerdown is intentionally left uncancelled, because cancelling it drops the compatibility mousedown that ThreadTerminalDrawer uses to activate an inactive split pane; and mouseup is cancelled, because Chromium otherwise pastes PRIMARY into the focused hidden textarea and would deliver a second paste through onPaste.

Verified: vp test run src/terminal/ghostty/surface.test.ts in apps/web — 54 passed, including a new case asserting the selection is pasted and that the clipboard is never read. vp run --filter @t3tools/web typecheck — exit 0, no errors. vp lint apps/web/src/terminal/ghostty/surface.ts apps/web/src/terminal/ghostty/surface.test.ts — exit 0. Not verified on a real X11 or Wayland session.

Mobile has no middle button; desktop wraps web and picks this up automatically.

Refs #10921

UI evidence: unverified. The browser preview host was unavailable in this session, so the changed interaction was not exercised in a real client. Scoped tests, typecheck, and lint pass; a reviewer should exercise the interaction locally before merge.

Done by Claude Opus 5 (1M context) in Claude Code.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Limited terminal middle-click paste to Linux and BSD platforms.
    • Middle-click now pastes only the terminal’s current selection; it no longer falls back to the system clipboard.
    • Prevented unintended browser autoscrolling and duplicate paste behavior.
    • Preserved split-pane activation when middle-clicking in the terminal.

The terminal canvas ignored the middle button: onPointerDown returned for
any button but 0, so the standard Linux middle-click paste did nothing and
Chromium started autoscroll instead.

Middle-click now pastes through the same bracketed-paste path as every other
paste. A browser cannot read the X11/Wayland PRIMARY buffer, so the terminal's
own selection is the source when the user highlighted here and the system
clipboard covers the rest. Applications that track the mouse still receive the
click.

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

cursor Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Sep 10, 2026
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Sep 10, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at d3cf911

Macroscope's review found this PR approvable — This is a localized Linux/BSD terminal interaction fix with targeted tests and no schema, deployment, security, billing, or configuration impact. The production behavior is confined to middle-click event handling within the existing terminal surface.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: b64d721b-0fee-4439-a89c-7745b13ad112

📥 Commits

Reviewing files that changed from the base of the PR and between 2c6000e and d3cf911.

📒 Files selected for processing (2)
  • apps/web/src/terminal/ghostty/surface.test.ts
  • apps/web/src/terminal/ghostty/surface.ts

Limit details: You’ve used all 10 included reviews currently available.


📝 Walkthrough

Walkthrough

The Ghostty terminal now supports Linux and BSD middle-click paste from the terminal selection only. It preserves split-pane activation and suppresses browser autoscroll and duplicate paste handling. Tests verify selection paste and no clipboard fallback.

Changes

Middle-click terminal interaction

Layer / File(s) Summary
Platform detection and paste resolution
apps/web/src/terminal/ghostty/surface.ts, apps/web/src/terminal/ghostty/surface.test.ts
The surface detects Linux and BSD platforms and pastes only non-empty terminal selections. Tests verify selection preservation and no system clipboard read after clearing the selection.
Middle-click event routing
apps/web/src/terminal/ghostty/surface.ts, apps/web/src/terminal/ghostty/surface.test.ts
Pointer and mouse handlers preserve split-pane activation, prevent browser autoscroll, suppress duplicate paste delivery, and register cleanup. The test harness accepts a configurable button value.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to d3cf9

Linux and BSD middle-click now pastes only an existing terminal selection while preserving pane activation and preventing duplicate browser handling. The current change is ready to merge with no identified actionable risk.

Suggested reviewers: stienswout, juliusmarminge, utkarshusername

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The implementation fixes middle-click event handling and supports pasting the terminal's own selection, but issue #10921 requires pasting text selected in another application through the Linux PRIMARY… Implement Linux PRIMARY selection access, including the required Electron clipboard and IPC integration, or update issue #10921 and its acceptance criteria to exclude external selections before merging this PR.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The changes are focused on middle-click handling, paste behavior, browser autoscroll suppression, split activation, and related tests. No unrelated code changes are identified.
Title check ✅ Passed The title clearly and concisely describes the primary change: fixing middle-click paste behavior in the Linux terminal.
Description check ✅ Passed The description clearly explains the change, rationale, scope, limitations, implementation details, tests, and linked issue. It does not use the template headings or checklist, and UI evidence is stil…
Full details: Linked Issues check

Explanation

The implementation fixes middle-click event handling and supports pasting the terminal's own selection, but issue #10921 requires pasting text selected in another application through the Linux PRIMARY selection. The description explicitly leaves external PRIMARY integration out of scope, so the primary linked-issue workflow is not fully implemented.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Middle click no longer falls back to the system clipboard: with nothing
selected in the terminal there is no primary-selection-like buffer to read,
and CLIPBOARD holds text the user only ever copied.

The gesture also stops cancelling pointerdown, which used to drop the
compatibility mousedown that activates an inactive split pane, and now
cancels the middle mouseup so Chromium cannot paste PRIMARY into the hidden
textarea on top of the paste already sent.

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

cursor Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@macroscopeapp
macroscopeapp Bot dismissed their stale review September 10, 2026 00:49

Dismissing prior approval to re-evaluate d3cf911

@maria-rcks
maria-rcks merged commit d1eeb16 into pingdotgg:main Sep 10, 2026
24 checks passed
aorwall added a commit to aorwall/t3code that referenced this pull request Sep 10, 2026
Merges `pingdotgg/t3code` `2a3035353..0f602b3` (16 commits) into the
fork.

- **Landed:** 283 files (`HEAD^1..HEAD`) against 277 in the upstream
range — `merge-stats.mjs` reports an exact 277/277 file match, so
nothing in the range was dropped and nothing extra came in. The six over
are three typecheck fixes and three fork docs, both listed below. Fork
delta 733 files (`HEAD^2..HEAD`).
- **Conflicts:** 6 files, all on one upstream feature (pingdotgg#10839, linking
several pull requests to a thread). Resolutions in
`docs/fork/upstream-merge-log.md`.
- **Sweep:** 13 owned-concern hits, all `infra/relay/**`
FCM/Android-push files under the decided-out `cloud-relay-connect`
concern. Inherited in tree, adopted by nothing.
- **Unsupported methods:** 0 ADD, 0 DROP — no
`packages/contracts/src/rpc.ts` edit needed.

## What upstream shipped

### Usable as-is against Moatless

Pure client work, no backend involvement — these are live the moment
this merges.

- **pingdotgg#11020** message copy buttons show on touch devices.
- **pingdotgg#11018** middle-click pastes in the terminal on Linux.
- **pingdotgg#10869** expanded images zoom and pan.
- **pingdotgg#11002** the composer uses the available space for model names.
- **pingdotgg#10981** duplicate tool-call commands can be expanded independently.
- **pingdotgg#10947** provider settings grow a bulk model toggle.
- **pingdotgg#10609** the PR list's diff counts return to the top right.
- **pingdotgg#11022** remote projects open in Zed
(`packages/contracts/src/editor.ts` plus the desktop shell — the fork
ships both).
- **pingdotgg#10998 / pingdotgg#10983 / pingdotgg#10964** three Android glass/overlap fixes in
`apps/mobile`.

### Unsupported in Moatless — needs backend implementation

- **pingdotgg#10839 — several pull requests per thread.** This is the substantive
decision in the merge. Upstream now carries `thread.pullRequests:
ThreadPullRequestLink[]`, `packages/shared/src/threadPullRequests.ts`,
and a `ThreadPullRequestBadgeControl` pill with its own `pull-requests`
stack tab. That is exactly the equivalent the fork's
`task-bound-pull-request` convergence entry said to re-home its `+N`
menu onto — but it cannot be re-homed yet: Moatless serves no
`pullRequests` array on a thread and does not advertise the new
`threadPullRequests` capability, so upstream's badge would resolve to
nothing and paint an empty pill over a working one. Taking `theirs`
would have silently deleted live fork behaviour.

**Resolution:** upstream's implementation landed whole, and the two
presentations are switched on `useSupportsMultiplePullRequests` —
upstream's badge and stack where the server advertises the capability,
the fork's binding-derived pill and `+N` menu where it does not.
Additive, no prop threading, and it re-homes itself the day the backend
advertises. `docs/fork/inventory.json` and `docs/fork/gaps.md` are
updated with the switch and with the exact deletion list for when that
happens.

**To close it:** serve `thread.pullRequests` on
`OrchestrationThread`/`OrchestrationThreadShell` from `task_bindings`,
and report `capabilities.threadPullRequests: true`.

- **pingdotgg#10870 — find threads by linked pull request.** Search terms come
off the same `thread.pullRequests` array, so sidebar and command-palette
search by PR number/URL match nothing here until the array is served.
Closes with pingdotgg#10839.

- **pingdotgg#10875 — navigate, merge and rebase GitHub stacks.** Adds two RPC
methods, `pullRequests.stack` and `pullRequests.linkedThreads`, which
the Moatless backend does not dispatch. Both are already covered by the
shared `PullRequestRpcError` union, so the client decodes the refusal
correctly and the stack UI stays inert — no contract change needed.
Implementing the two methods is what turns it on.

- **pingdotgg#10416 — Android agent notifications and ongoing activity.** Rides
FCM through `infra/relay`, which is part of the decided-out
`cloud-relay-connect` concern (being removed with Clerk). Inherited in
tree, not adopted.

### Backend behaviour worth reproducing in Moatless

- **pingdotgg#11007 — recent PR reads survive a server restart.** Upstream added
`apps/server/src/pullRequest/PullRequestReadCache.ts`, persisting which
pull requests a user has already read so a restart does not re-mark the
whole list unread. Moatless owns this surface itself, so nothing in this
repository holds it open — recorded so whoever touches the backend's PR
read state knows the answer exists upstream.

## Verification

`verify.mjs`, seven of eight green: `duplicate-adds`, `tripwires`,
`resolution-check`, `unsupported-methods`, `fmt:check`, `lint`,
`typecheck`.

`test` is red on `@t3tools/desktop` alone —
`scripts/browser-secret-native.test.mjs > bundled libsecret helper`
fails to compile because `libsecret-1` is not installed in this sandbox.
**Pre-existing environment gap, not merge-introduced:** it is already an
entry in `docs/fork/gaps.md`, and `git diff --name-only HEAD^1 HEAD |
grep browser-secret` is empty. 100 of 102 desktop files pass. Four
packages did not finish under `vp run -r test` (`@t3tools/mobile`, `t3`,
`@t3tools/web`, `t3code-relay`) and all four pass when run alone, which
is parallel load rather than the merge.

Three typecheck failures were fixed in the merge commit, all fork-only
web code that upstream's widened shared types reached:
`sandboxControl.placement.test.tsx` needed the two new `RightPanelTabs`
props, and `useSandboxAvailability.ts` / `useSandboxDetail.ts` needed
`isSuccess` threaded through now that `EnvironmentQueryView` carries it.

Nothing is unresolved.

---
Moatless task:
https://moatless.soaplabstest.com/tasks/db1b3cbe-4401-441b-bbec-6b0c725c93ce
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 10, 2026
## What's Changed
* fix(web): restore pr list diff counts to the top right by @maria-rcks in pingdotgg/t3code#10609
* fix(web): show message copy buttons on touch devices by @maria-rcks in pingdotgg/t3code#11020
* fix(web): middle-click pastes in the terminal on Linux by @maria-rcks in pingdotgg/t3code#11018
* fix(editors): open remote projects in Zed by @maria-rcks in pingdotgg/t3code#11022
* feat: add blue and orange diff color palette by @maria-rcks in pingdotgg/t3code#10671
* fix(server): resolve project identity before legacy pr relinks by @t3-code[bot] in pingdotgg/t3code#11045


**Full Changelog**: pingdotgg/t3code@v0.0.41-nightly.20260910.1473...v0.0.41-nightly.20260910.1486

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.41-nightly.20260910.1486
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant