Skip to content

Fix Cmd+Shift+Enter pane zoom for browser panes - #3520

Merged
austinywang merged 5 commits into
mainfrom
issue-3514-cmd-shift-enter-zoom
May 5, 2026
Merged

austinywang merged 5 commits into
mainfrom
issue-3514-cmd-shift-enter-zoom

Conversation

@austinywang

@austinywang austinywang commented May 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes browser-focused Cmd+Shift+Enter pane zoom by routing Return-bearing browser key equivalents through the central shortcut handler before falling back to WebKit keyDown handling.

Offending commit: 7d59e55

Root cause: commit 7d59e55 widened CmuxWebView Return/Enter routing to unconditionally bypass app/menu key-equivalent handling so WebKit form submission kept working. That bypass meant browser-focused Cmd+Shift+Enter never reached the app shortcut path, and the stored Return binding was also treated as unbound because the shortcut model trimmed newline characters. The fix keeps plain/unclaimed Return events on WebKit keyDown, but lets configured cmux Return shortcuts claim the event first and routes pane zoom through the event-window tab manager.

Tests added:

  • AppDelegateShortcutRoutingTests.testCmdShiftReturnFocusedBrowserTogglesSplitZoom

Verification:

  • Failing test-only commit confirmed red with ./scripts/test-unit.sh test -only-testing:cmuxTests/AppDelegateShortcutRoutingTests/testCmdShiftReturnFocusedBrowserTogglesSplitZoom
  • Fix commit confirmed green with ./scripts/test-unit.sh test -only-testing:cmuxTests/AppDelegateShortcutRoutingTests/testCmdShiftReturnFocusedBrowserTogglesSplitZoom

Closes #3514


Note

Medium Risk
Changes keyboard shortcut routing for Return/Enter inside CmuxWebView and routes split-zoom to a window-specific TabManager, which could affect other browser key-equivalent behaviors and shortcut dispatch across windows.

Overview
Fixes pane zoom (toggleSplitZoom) when a browser pane is focused by routing Return/Enter key equivalents from CmuxWebView.performKeyEquivalent through the central shortcut handler instead of unconditionally bypassing app/menu handling.

Updates shortcut dispatch to use the event window’s routed TabManager (and passes that through DEBUG goto-split recording) so split-zoom toggles the correct workspace. Also corrects StoredShortcut.isUnbound to treat only an empty key as unbound (preserving "\r" Return bindings) and adds a unit test covering Cmd+Shift+Return split zoom from a focused browser web view.

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


Summary by cubic

Fixes Cmd+Shift+Enter pane zoom when a browser pane is focused. Return/Enter shortcuts now go through the central handler before falling back to WebKit, and DEBUG shortcut timing stays accurate.

  • Bug Fixes
    • Route Return/Enter from browser panes through the app shortcut handler; unclaimed events fall back to WebKit for forms/editors.
    • Preserve Return-based shortcuts by treating only empty keys as unbound in StoredShortcut.isUnbound.
    • Route pane zoom via the event window’s tab manager; DEBUG goto-split snapshots use the routed workspace.
    • Keep DEBUG timing accurate in CmuxWebView.performKeyEquivalent by centralizing the handled state. Add unit test testCmdShiftReturnFocusedBrowserTogglesSplitZoom (Equalize Splits suite).

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

Summary by CodeRabbit

  • Bug Fixes

    • Improved split-zoom toggling to respect the focused window context.
    • Fixed keyboard shortcut detection for empty values.
    • Enhanced Enter key handling in browser environments.
  • Tests

    • Added test coverage for split-zoom shortcut functionality.

The browser pane regression needs an executable guard before changing the shared shortcut routing path. The new test focuses a browser panel, sends Cmd+Shift+Return through the WKWebView key-equivalent surface, and expects the existing split zoom action to run.

Constraint: Regression policy requires a failing test-only commit before the fix

Confidence: high

Scope-risk: narrow

Tested: ./scripts/test-unit.sh test -only-testing:cmuxTests/AppDelegateShortcutRoutingTests/testCmdShiftReturnFocusedBrowserTogglesSplitZoom (fails: WebView returns false and split zoom remains off)
Browser Return key equivalents were classified inside CmuxWebView before the configured shortcut router could claim Cmd+Shift+Return. The default Return shortcut was also misclassified as unbound because the shortcut model trimmed newline characters. Treat only an empty key as unbound, let Return-bearing browser key equivalents ask the central AppDelegate shortcut handler before falling through to WebKit, and route the zoom action through the event-window manager.

Constraint: Plain Return and unclaimed Cmd+Return must still reach WebKit keyDown for forms and editors

Rejected: Hardcode Cmd+Shift+Return in CmuxWebView | would duplicate shortcut configuration and miss remapped pane-zoom bindings

Confidence: high

Scope-risk: moderate

Directive: Keep Return-bearing browser shortcuts routed through AppDelegate first; do not add one-off Return guards in WebView

Tested: ./scripts/test-unit.sh test -only-testing:cmuxTests/AppDelegateShortcutRoutingTests/testCmdShiftReturnFocusedBrowserTogglesSplitZoom

Not-tested: XCUITests; per project policy these run in CI
@vercel

vercel Bot commented May 5, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Canceled Canceled May 5, 2026 1:47am
cmux-staging Building Building Preview, Comment May 5, 2026 1:47am

@coderabbitai

coderabbitai Bot commented May 5, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR fixes a regression where Cmd+Shift+Enter no longer toggles pane zoom when a browser pane is focused. It routes the toggleSplitZoom shortcut action through the correct window context instead of always using the cached tabManager, adjusts unbound shortcut detection to treat only empty (not whitespace-only) keys as unbound, enables browser Return/Enter key equivalents to route through the app's shortcut handler, and adds a test to verify the fix.

Changes

Split-Zoom Shortcut Routing & Browser Key Handling

Layer / File(s) Summary
Shortcut Unbound Detection
Sources/KeyboardShortcutSettings.swift
StoredShortcut.isUnbound now checks key.isEmpty instead of trimming whitespace before checking, so whitespace-only keys are no longer treated as unbound.
Browser Key-Equivalent Routing
Sources/Panels/CmuxWebView.swift
For Return/Enter key equivalents, performKeyEquivalent(with:) now first calls AppDelegate.shared?.handleBrowserSurfaceKeyEquivalent(event) and returns true if handled, allowing shortcuts to route through the app handler before WebKit receives keyDown.
Shortcut Action Routing
Sources/AppDelegate.swift
.toggleSplitZoom action now resolves the target TabManager via preferredMainWindowContextForShortcutRouting(event:)?.tabManager ?? tabManager instead of always using tabManager, ensuring the shortcut targets the focused window/context.
Test & Validation
cmuxTests/AppDelegateShortcutRoutingTests.swift
New test testCmdShiftReturnFocusedBrowserTogglesSplitZoom verifies that Cmd+Shift+Return on a focused browser pane toggles split zoom correctly via the local shortcut monitor (DEBUG builds only).

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly Related PRs

  • manaflow-ai/cmux#3468: Both PRs apply shortcut-event-based routing in AppDelegate to resolve the target manager dynamically instead of relying on the cached manager.
  • manaflow-ai/cmux#3334: Both PRs modify StoredShortcut.isUnbound semantics for empty key values.
  • manaflow-ai/cmux#2108: Both PRs delegate Return/Enter key handling from CmuxWebView to AppDelegate's browser-surface handler to ensure shortcuts are routed correctly.

Poem

🐰 A browser pane that once felt shy,
Now zooms when Cmd+Shift+Enter flies—
The rabbit routed through the right window's way,
Split-zoom shortcuts work again today! 🌳

🚥 Pre-merge checks | ✅ 12 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (12 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix Cmd+Shift+Enter pane zoom for browser panes' accurately captures the main objective of the PR—restoring the Cmd+Shift+Enter shortcut for toggling pane zoom when browser panes are focused.
Linked Issues check ✅ Passed The PR directly addresses issue #3514 by routing Return-bearing browser key equivalents through the central shortcut handler, updating the isUnbound logic, and routing pane zoom through the event-window tab manager—all core requirements from the linked issue.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the Cmd+Shift+Enter regression: CmuxWebView routing logic, StoredShortcut.isUnbound semantics, AppDelegate tab manager routing, and a regression test—no unrelated modifications detected.
Cmux Swift Actor Isolation ✅ Passed Changes comply with Swift 6 actor isolation: AppDelegate accesses @MainActor objects within @MainActor context, KeyboardShortcutSettings modifies computed property, and CmuxWebView calls @MainActor.
Cmux Swift Blocking Runtime ✅ Passed No blocking or timing-based synchronization introduced in production code. All changes are straightforward function routing and property checks. Test additions are test-only code.
Cmux Swift Concurrency ✅ Passed No legacy async patterns introduced. Changes are synchronous: routing logic, property update, and key equivalent handling. No DispatchQueue, Combine, Tasks, or completion handlers.
Cmux Swift @Concurrent ✅ Passed No Swift async/await functions added that would require @concurrent annotations. Uses synchronous routing logic and proper DispatchQueue-based concurrency with appropriate QoS levels.
Cmux Swift File And Package Boundaries ✅ Passed Focused bug fixes: +2 lines AppDelegate, +9 CmuxWebView, +1 KeyboardShortcutSettings. All under 250-line threshold. No new oversized files or mixed responsibilities.
Cmux Swift Logging ✅ Passed The PR modifies Swift code without violating swift-logging.md rules. No print, debugPrint, dump, or NSLog in production code. DEBUG-only logging properly guarded with #if DEBUG.
Cmux Swiftui State Layout ✅ Passed PR introduces no new SwiftUI state (@State/@Published/@observable). All changes are AppKit/logic layer: AppDelegate routing, KeyboardShortcutSettings model, CmuxWebView handling, XCTest additions.
Cmux Architecture Rethink ✅ Passed No architectural anti-patterns introduced. Routes through AppDelegate deterministically. Fixes isUnbound bug. Adds regression test with acceptable test-only patterns.
Description check ✅ Passed PR description is comprehensive and well-structured, covering summary, root cause analysis, fix implementation, tests added, and verification steps.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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-3514-cmd-shift-enter-zoom

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 and usage tips.

@greptile-apps

greptile-apps Bot commented May 5, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes Cmd+Shift+Enter pane zoom when a browser pane is focused by addressing two independent root causes: StoredShortcut.isUnbound was trimming " " to empty (treating Return as unbound), and CmuxWebView.performKeyEquivalent unconditionally bypassed app-level shortcut routing for all Return/Enter events. The fix corrects isUnbound to check key.isEmpty, routes Return/Enter through handleBrowserSurfaceKeyEquivalent first (falling back to WebKit when unclaimed), and directs toggleSplitZoom to the event-window-local tab manager rather than the global one.

Confidence Score: 5/5

Safe to merge — the two root causes are independently addressed and the new test exercises both the monitor path and the performKeyEquivalent path end-to-end.

All three changes are small and tightly scoped: the isUnbound one-liner fix, the Return/Enter routing change that preserves the false fallback for unclaimed events, and the tab-manager resolution that mirrors the pattern used by every other split shortcut in the same handler. No existing shortcut dispatch paths are removed or altered for non-Return events, and handleCustomShortcut already guards against close-confirmation alerts and recorder-active states, so the new Return routing path is protected by the same guards.

No files require special attention.

Important Files Changed

Filename Overview
Sources/KeyboardShortcutSettings.swift Fixes isUnbound to check key.isEmpty instead of trimming whitespace, so "\r" (Return) is correctly treated as a bound shortcut key
Sources/Panels/CmuxWebView.swift Routes Return/Enter performKeyEquivalent events through handleBrowserSurfaceKeyEquivalent instead of unconditionally returning false; also refactors repeated #if DEBUG handled = result #endif into a shared finish() helper
Sources/AppDelegate.swift Routes toggleSplitZoom via event-window-resolved tab manager; extends recordGotoSplitZoomIfNeeded to accept an explicit TabManager so the DEBUG recording uses the same routed manager
cmuxTests/AppDelegateEqualizeSplitsShortcutTests.swift Adds testCmdShiftReturnFocusedBrowserTogglesSplitZoom covering both the local-monitor path and the performKeyEquivalent path, plus a withTemporaryShortcut helper that restores the original shortcut via defer

Sequence Diagram

sequenceDiagram
    participant User
    participant CmuxWebView
    participant AppDelegate
    participant handleCustomShortcut
    participant WebKit

    User->>CmuxWebView: Cmd+Shift+Return (keyCode 36/76)
    Note over CmuxWebView: Previously: return false unconditionally
    CmuxWebView->>AppDelegate: handleBrowserSurfaceKeyEquivalent(event)
    AppDelegate->>handleCustomShortcut: handleCustomShortcut(event)
    alt shortcut matches (e.g. toggleSplitZoom)
        handleCustomShortcut-->>AppDelegate: true
        AppDelegate-->>CmuxWebView: true
        CmuxWebView-->>User: event consumed, zoom toggled
    else no shortcut match (plain Return, form submit)
        handleCustomShortcut-->>AppDelegate: false
        AppDelegate-->>CmuxWebView: false
        CmuxWebView->>WebKit: keyDown (form submission path)
        WebKit-->>User: form submitted
    end
Loading

Reviews (3): Last reviewed commit: "Keep browser shortcut timing accurate" | Re-trigger Greptile

Comment thread Sources/AppDelegate.swift

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/Panels/CmuxWebView.swift (1)

1-1: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

CI blocker: file length budget exceeded — trim 7 lines before merging.

The pipeline reports actual=2498, budget=2491. The changed block in performKeyEquivalent grew from 3 lines (if … { return false }) to 12 lines (comment + nested if + #if DEBUG + return false), a net +9 that pushes the file 7 lines over budget.

The quickest path to compliance is to extract one of the self-contained top-level types — for example, BrowserImageCopyPasteboardPayload + BrowserImageCopyPasteboardBuilder (lines 26–103, ≈78 lines) — into a new Sources/Panels/BrowserImageCopyPasteboardBuilder.swift file, which removes the budget pressure here and in any future change to this file.

Based on learnings: "In this repo's CI enforces a Swift file-length budget for large view files… When adding helper views/small components, avoid bloating the existing file: extract the subview into a dedicated Swift file under Sources… and keep it under the CI length threshold."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/Panels/CmuxWebView.swift` at line 1, This file exceeds the CI
file-length budget because the new performKeyEquivalent block expanded the file;
fix by extracting the top-level types BrowserImageCopyPasteboardPayload and
BrowserImageCopyPasteboardBuilder into a new Swift file (e.g.,
Sources/Panels/BrowserImageCopyPasteboardBuilder.swift). Move the entire
definitions of BrowserImageCopyPasteboardPayload and
BrowserImageCopyPasteboardBuilder out of CmuxWebView.swift, ensure they keep the
same access levels and any required imports (e.g., AppKit/Foundation), update
any references in CmuxWebView (e.g., where BrowserImageCopyPasteboardBuilder is
instantiated or BrowserImageCopyPasteboardPayload is used) to the new file, and
run the build to confirm no missing symbols remain.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmuxTests/AppDelegateShortcutRoutingTests.swift`:
- Around line 2750-2820: The test
testCmdShiftReturnFocusedBrowserTogglesSplitZoom is making the file exceed the
length budget; refactor by extracting the repeated setup/assertion scaffolding
into shared helpers and shortening the test to a single high-level flow. Create
helpers (e.g., makeMainWindowAndManager(),
openFocusedBrowserPanel(in:manager:preferSplitRight:),
attachWebViewToWindow(browserPanel:window:), and
makeCmdShiftReturnEvent(window:)) and move the window creation,
workspace/browserPanel lookup, webView attach/remove, and event construction
into those helpers; then reduce the test body to withTemporaryShortcut { guard
let appDelegate = AppDelegate.shared else XCTFail...; let (windowId, manager,
browserPanel, event) =
makeMainWindowAndManager()/openFocusedBrowserPanel()/makeCmdShiftReturnEvent();
perform the minimal assertions and invoke
appDelegate.debugHandleShortcutMonitorEvent and
browserPanel.webView.performKeyEquivalent. Also consider removing or
consolidating duplicate DEBUG-only assertions to further shrink the test size.
- Around line 2773-2778: The test currently always removes browserPanel.webView
in defer which can detach a pre-existing view; add a local Bool (e.g.
didAttachForTest) initialized false, set it to true inside the if branch that
adds browserPanel.webView to window.contentView, and change the defer to only
call browserPanel.webView.removeFromSuperview() when didAttachForTest is true;
reference browserPanel.webView, window.contentView?.addSubview(...), and the new
didAttachForTest flag so the cleanup only runs if this test attached the view.

In `@Sources/AppDelegate.swift`:
- Around line 11246-11247: Collapse the two-line sequence that assigns
routedManager and calls toggleFocusedSplitZoom into a single expression to save
a line: inline the optional chaining so you call toggleFocusedSplitZoom() on
either preferredMainWindowContextForShortcutRouting(event: event)?.tabManager or
fallback tabManager in one statement (referencing
preferredMainWindowContextForShortcutRouting(event:), tabManager, and
toggleFocusedSplitZoom()). Ensure the result is discarded as before (using _ =
...) and preserve the same optional semantics.

---

Outside diff comments:
In `@Sources/Panels/CmuxWebView.swift`:
- Line 1: This file exceeds the CI file-length budget because the new
performKeyEquivalent block expanded the file; fix by extracting the top-level
types BrowserImageCopyPasteboardPayload and BrowserImageCopyPasteboardBuilder
into a new Swift file (e.g.,
Sources/Panels/BrowserImageCopyPasteboardBuilder.swift). Move the entire
definitions of BrowserImageCopyPasteboardPayload and
BrowserImageCopyPasteboardBuilder out of CmuxWebView.swift, ensure they keep the
same access levels and any required imports (e.g., AppKit/Foundation), update
any references in CmuxWebView (e.g., where BrowserImageCopyPasteboardBuilder is
instantiated or BrowserImageCopyPasteboardPayload is used) to the new file, and
run the build to confirm no missing symbols remain.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5c7d8152-0b32-40a3-b70a-4f3a8731dc0a

📥 Commits

Reviewing files that changed from the base of the PR and between 13d7933 and facb950.

📒 Files selected for processing (4)
  • Sources/AppDelegate.swift
  • Sources/KeyboardShortcutSettings.swift
  • Sources/Panels/CmuxWebView.swift
  • cmuxTests/AppDelegateShortcutRoutingTests.swift

Comment thread cmuxTests/AppDelegateShortcutRoutingTests.swift Outdated
Comment thread cmuxTests/AppDelegateShortcutRoutingTests.swift Outdated
Comment thread Sources/AppDelegate.swift
The PR branch needed the latest main changes before resolving review feedback so CI validates against the current shortcut model and file-length budgets.

Constraint: PR target main advanced after the original branch commits

Confidence: high

Scope-risk: narrow

Tested: ./scripts/reload.sh --tag issue-3514-cmd-shift-enter-zoom

Tested: python3 scripts/swift_file_length_budget.py --budget .github/swift-file-length-budget.tsv
Review feedback exposed two cleanup issues after the browser pane-zoom fix: Swift file-length budgets were over limit and DEBUG goto-split recording still read the fallback tab manager after routed zooms. The test now lives in the smaller equalize-splits shortcut suite, the browser Return key-equivalent path stays compact, and the debug recorder snapshots the routed manager's workspace.

Constraint: Swift file-length budget is enforced by workflow-guard-tests

Rejected: Extract BrowserImageCopyPasteboardBuilder | unnecessary after trimming the Return path and moving the regression test

Rejected: Inline toggleFocusedSplitZoom without routedManager | would lose the manager needed for correct DEBUG recording

Confidence: high

Scope-risk: narrow

Tested: ./scripts/reload.sh --tag issue-3514-cmd-shift-enter-zoom

Tested: python3 scripts/swift_file_length_budget.py --budget .github/swift-file-length-budget.tsv

Tested: git diff --check

@cursor cursor 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.

Cursor Bugbot has reviewed your changes 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 0a0c650. Configure here.

Comment thread Sources/Panels/CmuxWebView.swift
Cursor Bugbot caught that the compact Return/Enter shortcut path could report handled=0 in DEBUG timing logs even when it consumed a browser pane shortcut. Centralizing performKeyEquivalent returns through a local finish helper keeps the timing flag accurate and reduces repeated DEBUG bookkeeping.

Constraint: CmuxWebView.swift is governed by the Swift file-length budget

Rejected: Re-add per-branch DEBUG blocks | more repetitive and weaker against the file-length budget

Confidence: high

Scope-risk: narrow

Tested: python3 scripts/swift_file_length_budget.py --budget .github/swift-file-length-budget.tsv

Tested: git diff --check

This branch was successfully deployed

1 active deployment
Preview – cmux — a66b9f61 Deployed May 5, 2026 by vercel[bot]
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.

Cmd+Shift+Enter no longer toggles pane zoom when a browser pane is focused (regression)

1 participant