Skip to content

Fix paste into browser routing to terminal text box (text box beta) - #6872

Closed
austinywang wants to merge 10 commits into
mainfrom
issue-6380-trying-to-paste-into-browser-always
Closed

austinywang wants to merge 10 commits into
mainfrom
issue-6380-trying-to-paste-into-browser-always

Conversation

@austinywang

@austinywang austinywang commented Jun 26, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #6380

Problem

With a terminal and a browser pane side by side and text box beta enabled, pasting (Cmd+V) into the focused browser pasted into the terminal's text box instead of the browser.

Only paste was affected — not copy/cut/select-all, and not typing — and only with the text box beta enabled. That asymmetry is the tell.

Root cause

Two complementary issues:

  1. Paste was missing from the browser document-editing commands. BrowserDocumentEditingCommandEquivalent listed copy, cut, and selectAll but not paste. Those three preflight into the focused web view (shouldRouteBrowserDocumentEditingCommandEquivalentThroughWebContentFirst) before cmux's menu fallback, so the focused browser claims them first. Cmd+V was never routed there, so it fell through to the original NSWindow.performKeyEquivalent.

  2. performKeyEquivalent is broadcast to every view in the window, not just the first responder. TextBoxInputTextView overrides it and claimed Cmd+C/X/V (and undo/redo) unconditionally. So in the fall-through broadcast, the unfocused terminal text box grabbed Cmd+V before the menu could route it to the browser — pasting into the text box. Copy/cut weren't affected because they were already routed to web content first (issue 1); typing wasn't affected because keyDown only reaches the first responder.

Fix

  • ShortcutRoutingSupport.swift — add paste (Cmd+V) to BrowserDocumentEditingCommandEquivalent so the focused web view claims it first, exactly like copy/cut/select-all. Cmd+V only; Cmd+Shift+V (paste-and-match-style) keeps its dedicated path because matches requires an exact modifier match.
  • TextBoxInput.swift — gate the text box's standard edit/undo shortcuts in performKeyEquivalent on the text view actually owning first responder, so an unfocused text box no longer steals copy/cut/paste/undo from the focused browser (web content or omnibar) or terminal. The focus shortcut path is intentionally left ungated so it can still focus the text box.

Tests

Two-commit red/green:

  • Commit 1 (failing): testBrowserPasteCommandRoutesThroughWebContentFirst and testTextBoxDeclinesPasteShortcutWhenNotFirstResponder.
  • Commit 2 (fix + guards): plus testTextBoxHandlesPasteShortcutWhenFirstResponder (normal paste still works when focused) and testBrowserPlainTextPasteCommandIsNotADocumentEditingPaste (Cmd+Shift+V keeps its own path).

Localization

No user-facing strings, menus, settings rows, shortcut metadata, alerts, tooltips, or docs changed — Cmd+V is a standard system command (not a cmux-owned KeyboardShortcutSettings shortcut), matching the existing copy/cut/select-all pattern. No localization updates required.

🤖 Generated with Claude Code


Summary by cubic

Fixes Cmd+V being intercepted by the terminal text box when Text Box Beta is enabled. Paste now goes to the focused browser; the text box only handles edit shortcuts when it’s first responder (fixes #6380).

  • Bug Fixes
    • Added paste (Cmd+V) to BrowserDocumentEditingCommandEquivalent so the focused web view claims it first; Cmd+Shift+V keeps its dedicated path.
    • Gated TextBoxInputTextView.performKeyEquivalent so copy/cut/paste/undo/redo run only when the text box owns first responder; the focus shortcut stays ungated.
    • Moved regression tests to Swift Testing covering browser preflight, first-responder gating, Cmd+Shift+V behavior, and paste while the text box is focused.

Written for commit c388e03. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved keyboard shortcut routing so paste now goes to the currently focused web content instead of an unrelated text field.
    • Text boxes no longer intercept editing shortcuts unless they are the active input, preventing unfocused fields from handling copy, cut, paste, undo, and redo.
    • Added coverage for paste and paste-as-plain-text shortcut behavior to help ensure consistent handling.

cmux and others added 2 commits June 26, 2026 02:05
With a terminal + browser side by side and text box beta enabled, Cmd+V
into the focused browser pastes into the terminal's text box instead.

Root cause: paste is missing from the browser document-editing commands
(only copy/cut/select-all are routed to focused web content first), so
Cmd+V falls through to the NSWindow.performKeyEquivalent broadcast where
the terminal text box's performKeyEquivalent claims it even though it is
not the first responder.

These two tests fail on the current tree and pass once the fix lands:
- shouldRouteBrowserDocumentEditingCommandEquivalentThroughWebContentFirst
  must return true for Cmd+V.
- TextBoxInputTextView.performKeyEquivalent must decline Cmd+V while
  another view owns first responder.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…6380)

With a terminal + browser side by side and text box beta enabled, pasting
into the focused browser pasted into the terminal's text box instead.

Two complementary causes, fixed here:

1. Paste was missing from the browser document-editing commands
   (BrowserDocumentEditingCommandEquivalent had copy/cut/select-all but not
   paste). Copy/cut/select-all preflight into the focused web view before
   cmux's menu fallback, but Cmd+V fell through to the
   NSWindow.performKeyEquivalent broadcast. Add paste (Cmd+V) so the focused
   web view claims it first, exactly like the other editing commands. Cmd+V
   only — Cmd+Shift+V keeps its dedicated paste-as-plain-text path.

2. performKeyEquivalent is broadcast to every view in the window, not just
   the first responder. TextBoxInputTextView's override claimed Cmd+C/X/V and
   undo/redo unconditionally, so an unfocused text box stole those shortcuts
   from whatever actually owned focus (browser web content, the browser
   omnibar, etc.). Gate the standard edit/undo shortcuts on the text view
   being the first responder; the focus shortcut path is intentionally left
   ungated so it can still focus the text box.

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

vercel Bot commented Jun 26, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jul 4, 2026 9:25pm
cmux-staging Building Building Preview, Comment Jul 4, 2026 9:25pm

@coderabbitai

coderabbitai Bot commented Jun 26, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5492ef6e-9fd5-439a-8b57-3adf4472a433

📥 Commits

Reviewing files that changed from the base of the PR and between 9c91710 and c388e03.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (4)
  • Sources/App/ShortcutRoutingSupport.swift
  • Sources/TextBoxInput.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/AppDelegateBrowserPasteShortcutRoutingTests.swift

📝 Walkthrough

Walkthrough

Adds a .paste case to BrowserDocumentEditingCommandEquivalent so Cmd+V routes to the focused browser web view before window-level key equivalent handling. Restricts TextBoxInputTextView editing shortcut handling to when it is the first responder. Adds a corresponding test suite and Xcode project registration.

Changes

Browser Paste Shortcut Routing Fix

Layer / File(s) Summary
Paste case and routing documentation
Sources/App/ShortcutRoutingSupport.swift
Adds a .paste case to BrowserDocumentEditingCommandEquivalent with a Cmd+V-only shortcut mapping (excluding Cmd+Shift+V), and updates the routing comment to describe preflighting paste to the focused web view.
First-responder gated shortcut handling
Sources/TextBoxInput.swift
Adds isFirstResponderForEditingShortcuts and updates performKeyEquivalent to only handle standard editing shortcuts when the text view is the window's first responder, otherwise deferring to super.
Paste routing tests and project wiring
cmuxTests/AppDelegateBrowserPasteShortcutRoutingTests.swift, cmux.xcodeproj/project.pbxproj
Adds a new test suite validating Cmd+V routes through the web-content-first preflight, that TextBoxInputTextView declines/handles Cmd+V based on first-responder status, and that Cmd+Shift+V is excluded from this path; registers the test file in the Xcode project.

Estimated code review effort: 2 (Simple) | ~15 minutes

Sequence Diagram(s)

sequenceDiagram
  participant NSWindow
  participant BrowserWebView as Focused Web View
  participant TextBoxInputTextView

  NSWindow->>BrowserWebView: performKeyEquivalent(Cmd+V)
  BrowserWebView-->>NSWindow: shouldRouteBrowserDocumentEditingCommandEquivalentThroughWebContentFirst returns true
  NSWindow->>TextBoxInputTextView: performKeyEquivalent(Cmd+V) if web view declines
  TextBoxInputTextView->>TextBoxInputTextView: isFirstResponderForEditingShortcuts?
  TextBoxInputTextView-->>NSWindow: handle if first responder, else fallback to super
Loading

Possibly related PRs

  • manaflow-ai/cmux#4186: Both PRs modify the window-level performKeyEquivalent/browser document-editing routing preflight, overlapping in the same shortcut-routing mechanism.

Suggested reviewers: azooz2003-bit


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Cmux Full Internationalization ❌ Error The PR adds/changes user-facing CLI error strings as hardcoded English literals, with no matching localization keys or catalog entries. Move those messages to localized keys and add translations in the affected Resources/*.xcstrings catalogs (and any CLI-specific catalog) for every supported locale.
✅ Passed checks (24 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fixing paste routing so the browser wins over the terminal text box.
Description check ✅ Passed The description covers the bug, root cause, fix, tests, and rationale, with only optional template sections left out.
Linked Issues check ✅ Passed The changes address #6380 by routing Cmd+V to the focused browser first and preventing unfocused text boxes from stealing it.
Out of Scope Changes check ✅ Passed The diff stays focused on paste-routing and regression tests, with no clear unrelated code changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Cmux Swift Actor Isolation ✅ Passed No new actor-isolation debt: the changes are AppKit UI-only (NSTextView and routing helpers) plus tests, with no new shared Sendable state or background-context UI access.
Cmux Swift Blocking Runtime ✅ Passed Diff only adds key-equivalent routing gates and deterministic tests; no waits, sleeps, locks, or main-queue sync were introduced.
Cmux Browser Automation Off-Main ✅ Passed Only browser shortcut/text-box key handling changed; no browser socket automation, worker routing, or WebKit-waiting browser.* commands were touched.
Cmux Expensive Synchronous Load ✅ Passed PASS: The diff adds only off-main Task.detached scans and shortcut gating; no new RestorableAgentSessionIndex.load() or large agent-history parse lands on a main/interactive path.
Cmux Cache Substitution Correctness ✅ Passed Diff only changes shortcut routing and first-responder gating; no authoritative-read cache substitution appears in persistence/history/undo/snapshot paths.
Cmux No Hacky Sleeps ✅ Passed The diff only adds routing/gating and tests; no sleep, asyncAfter, polling, or delay workaround was introduced, and the rule excludes Swift from this check.
Cmux Algorithmic Complexity ✅ Passed No scalable-collection hot path was introduced: the new scans are over a tiny fixed shortcut enum, and the text-box gate is constant-time.
Cmux Swift Concurrency ✅ Passed PASS: The PR only adds synchronous AppKit shortcut-routing logic and tests; no new DispatchQueue, Task, Combine, or completion-handler async patterns appear in the diff.
Cmux Swift @Concurrent ✅ Passed Touched Swift changes are synchronous UI event routing/tests; no new nonisolated async, @concurrent, or heavy async helper usage was introduced.
Cmux Swift File And Package Boundaries ✅ Passed Touches existing oversized app-glue files with small, focused edits; the only new file is a test, and no reusable domain logic was kept in app-target glue.
Cmux Swiftpm Lockfiles ✅ Passed Diff only wires a new test file in cmux.xcodeproj/project.pbxproj; no Package.resolved or .gitignore changes, and no SwiftPM package-reference edits.
Cmux Swift Logging ✅ Passed PR diff vs merge-base touches 3 Swift files plus tests, and no added print/debugPrint/dump/NSLog/Logger calls appear in the changed Swift code.
Cmux User-Facing Error Privacy ✅ Passed Diff only adds shortcut-routing logic and tests; no user-visible error/alert/copy text exposing restricted details was added.
Cmux Swiftui State Layout ✅ Passed The diff only adds paste routing and first-responder gating inside NSTextView/AppKit helpers; no new ObservableObject, GeometryReader, list-row stores, or render-time state writes.
Cmux Architecture Rethink ✅ Passed PASS: This is a local first-responder correctness fix; no timing hacks, extra owners, observers, or split lifecycle paths were introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed Diff only changes shortcut routing, tests, and pbxproj; no added/changed NSWindow/NSPanel/WindowGroup or cmuxAuxiliaryWindowIdentifiers/close-shortcut code.
Cmux Source Artifacts ✅ Passed No changed path is an artifact/scratch path; remaining additions are intentional source, tests, config, docs, or assets.
Cmux No Test Or Debug Seam In Production Source ✅ Passed Diff only adds Cmd+V routing and first-responder gating; no new DEBUG/test-only seam, widened visibility, or test-hook member appears in production Sources/.
Cmux No Ambient Global State ✅ Passed Diff only adds an enum case, a private computed property, and file-private test helpers; no new top-level API, globals, or singletons were introduced.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-6380-trying-to-paste-into-browser-always

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.

@greptile-apps

greptile-apps Bot commented Jun 26, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Two-part fix for Cmd+V being intercepted by an unfocused TextBoxInputTextView (text box beta) when a browser pane is in focus alongside a terminal pane. The root cause was that paste was missing from the browser preflight list and the text box's performKeyEquivalent claimed it unconditionally from the window-wide broadcast.

  • ShortcutRoutingSupport.swift: Adds paste (Cmd+V) to BrowserDocumentEditingCommandEquivalent so the focused web view claims it first via shouldRouteBrowserDocumentEditingCommandEquivalentThroughWebContentFirst, exactly mirroring copy/cut/selectAll/italic; Cmd+Shift+V is correctly excluded by the existing exact-modifier-match logic.
  • TextBoxInput.swift: Adds a private isFirstResponderForEditingShortcuts guard (checked as window?.firstResponder === self) before handleStandardEditShortcut and the undo/redo handling in performKeyEquivalent, so an unfocused text box falls back to super instead of claiming the event; the focus-shortcut path via handleConfiguredTextBoxShortcut is intentionally left ungated before the guard.
  • Tests: Four Swift Testing scenarios — browser preflight positive/negative (Cmd+Shift+V), text box unfocused decline, and text box focused acceptance — registered in the Xcode project.

Confidence Score: 5/5

Safe to merge — the change is a targeted, well-documented two-part fix with regression tests that cover the exact failure scenario and several related edge cases.

Both production changes are small, follow the established pattern in the file (paste mirrors copy/cut/selectAll/italic in the enum, and the first-responder guard follows the same gating logic as other AppKit performKeyEquivalent overrides), and the fix provides defense-in-depth: the browser preflight ensures the web view claims Cmd+V first, and the first-responder guard ensures an unfocused text box never steals it even if the broadcast reaches it. No new ambient globals, no blocking primitives, no i18n surface, and no test seams introduced.

No files require special attention.

Important Files Changed

Filename Overview
Sources/App/ShortcutRoutingSupport.swift Adds paste (Cmd+V) to BrowserDocumentEditingCommandEquivalent so the focused web view claims it first, exactly mirroring the existing copy/cut/selectAll/italic pattern; comment correctly explains Cmd+Shift+V exclusion
Sources/TextBoxInput.swift Adds private isFirstResponderForEditingShortcuts guard in performKeyEquivalent so an unfocused text box declines standard edit/undo shortcuts and falls back to super; the focus-shortcut path via handleConfiguredTextBoxShortcut remains correctly ungated before the guard
cmuxTests/AppDelegateBrowserPasteShortcutRoutingTests.swift New Swift Testing suite covering the four key scenarios: browser paste preflight, unfocused text box declining Cmd+V, focused text box accepting Cmd+V, and Cmd+Shift+V exclusion from the document-editing path
cmux.xcodeproj/project.pbxproj Registers AppDelegateBrowserPasteShortcutRoutingTests.swift in both the file reference list and the test target Sources phase
.github/swift-file-length-budget.tsv Updates line-count budget for TextBoxInput.swift (+17) and ShortcutRoutingSupport.swift (+16), keeping both within existing over-budget baselines

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User as User (Cmd+V)
    participant CmuxWebView as CmuxWebView<br/>(focused browser)
    participant ShortcutRouting as ShortcutRoutingSupport
    participant TextBox as TextBoxInputTextView<br/>(unfocused)

    Note over User,TextBox: BEFORE fix
    User->>ShortcutRouting: performKeyEquivalent(Cmd+V)
    ShortcutRouting-->>User: paste not in BrowserDocumentEditingCommandEquivalent → skip browser preflight
    User->>TextBox: NSWindow broadcast performKeyEquivalent
    TextBox-->>User: claimed unconditionally → pasted into text box

    Note over User,TextBox: AFTER fix
    User->>ShortcutRouting: performKeyEquivalent(Cmd+V)
    ShortcutRouting->>CmuxWebView: paste now in BrowserDocumentEditingCommandEquivalent → preflight to web content
    CmuxWebView-->>User: handled → paste into browser
    Note over TextBox: broadcast never reaches text box (browser already consumed event)
    Note over TextBox: defense-in-depth: even if broadcast reaches text box, isFirstResponderForEditingShortcuts guard returns false → super()
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User as User (Cmd+V)
    participant CmuxWebView as CmuxWebView<br/>(focused browser)
    participant ShortcutRouting as ShortcutRoutingSupport
    participant TextBox as TextBoxInputTextView<br/>(unfocused)

    Note over User,TextBox: BEFORE fix
    User->>ShortcutRouting: performKeyEquivalent(Cmd+V)
    ShortcutRouting-->>User: paste not in BrowserDocumentEditingCommandEquivalent → skip browser preflight
    User->>TextBox: NSWindow broadcast performKeyEquivalent
    TextBox-->>User: claimed unconditionally → pasted into text box

    Note over User,TextBox: AFTER fix
    User->>ShortcutRouting: performKeyEquivalent(Cmd+V)
    ShortcutRouting->>CmuxWebView: paste now in BrowserDocumentEditingCommandEquivalent → preflight to web content
    CmuxWebView-->>User: handled → paste into browser
    Note over TextBox: broadcast never reaches text box (browser already consumed event)
    Note over TextBox: defense-in-depth: even if broadcast reaches text box, isFirstResponderForEditingShortcuts guard returns false → super()
Loading

Reviews (7): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

@austinywang

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 26, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@austinywang

Copy link
Copy Markdown
Contributor Author

CI note: app-host unit tests (2/4) red is a fleet-wide infra flake, not this PR

The only failing check is the app-host unit tests (2/4) shard (and the ci-status/tests aggregates that gate on it). Evidence this is infrastructure, not this change:

  • Failures are all in unrelated subsystems — BrowserPanelWebViewLifecycleTests, BundledCLILinkageTests (testBundledCLIDoesNotDependOnPrivateRPathFrameworks — the bundled CLI is being linked with private @rpath frameworks, which a source-only change cannot cause and which then cascades into every CLI/socket-dependent test), CLINotifyProcessIntegrationRegressionTests, BrowserDeveloperToolsConfigurationTests (theme color accuracy), FileExplorerStoreTests, etc.
  • Non-deterministic — the failing set differs across 4 fresh-VM runs (original + 2 re-runs + 1 fresh full run after merging origin/main).
  • All 4 of this PR's own tests pass.
  • Other unrelated open PRs are failing the same app-host shards concurrently (Lock in SSH file tree cwd tracking with a regression test (#5471) #6889–Fold split layout into autosave fingerprint so pane order survives restore (#6184) #6892 at the time of writing), and main is green at this PR's base — i.e. the shard is flaky under current fleet load.

This PR's diff is small and review-clean: Codex structured autoreview (patch is correct), Greptile (5/5 "Safe to merge"), and CodeRabbit all returned no actionable findings. Branch is MERGEABLE with no conflicts. The shard should pass on a clean re-run once CI contention subsides.

…paste-into-browser-always

# Conflicts:
#	.github/swift-file-length-budget.tsv
Comment thread .claude/scheduled_tasks.lock Outdated
This gitignored scheduler lock (a stale local artifact) was accidentally
tracked on this branch and is unrelated to the paste-routing fix. Remove
it from the PR diff so only the intended files remain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 4 files

Re-trigger cubic

…paste-into-browser-always

# Conflicts:
#	.github/swift-file-length-budget.tsv
…paste-into-browser-always

# Conflicts:
#	.github/swift-file-length-budget.tsv
@austinywang

Copy link
Copy Markdown
Contributor Author

Reviewed the CodeRabbit "Cmux Full Internationalization" summary finding. This PR does not add user-facing app, CLI, schema, docs, or localization strings: the production changes are shortcut routing data and first-responder gating, and the added English strings are source comments/test assertion messages only. No localization catalog update is needed for this PR. CI and autoreview are clean on the current head.

@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — c388e03a Deployed Jul 4, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trying to paste into browser always pastes into the termina Text Box (beta)

3 participants