Skip to content

Add cyclic pane focus shortcuts - #4763

Closed
austinywang wants to merge 14 commits into
mainfrom
issue-2076-keyboard-shortcuts-to-change-focus
Closed

austinywang wants to merge 14 commits into
mainfrom
issue-2076-keyboard-shortcuts-to-change-focus

Conversation

@austinywang

@austinywang austinywang commented May 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds configurable Next Pane and Previous Pane shortcuts for cyclic split-pane focus.
  • Wires the action through the shared Workspace/TabManager focus path, View menu, command palette, Settings keyboard shortcuts, and cmux.json schema/docs.
  • Leaves existing directional pane focus and surface cycling shortcuts intact; the new defaults are Ctrl+Option+Command+] and Ctrl+Option+Command+[.

Testing

  • Not run locally per repo policy and task instructions.
  • Added behavior-level unit coverage for cyclic pane focus and shortcut configurability.

Fixes #2076


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.


Note

Medium Risk
Changes focus navigation across split panes (user-visible), but reuses existing focus/find-preservation patterns and is covered by new unit tests.

Overview
Adds Next Pane and Previous Pane so users can cycle split-pane focus in stable split-tree order with wrap-around, separate from directional focus and tab/surface cycling.

Focus behavior: Workspace walks bonsplitController.allPaneIds, focuses the selected tab (or first tab) in each target pane, and no-ops when there is only one pane. While a pane is zoomed, cycling does not leave the zoomed pane unless focus is already elsewhere.

Wiring: New nextPane / prevPane actions default to Ctrl+Option+Command+] and [ (distinct from workspace and surface shortcuts). Routed in AppDelegate (with find-selection preservation before focus moves), View menu, command palette, Settings, cmux.json schema, Localizable.xcstrings, and web shortcut docs. LocalizedText now prefers text[locale] with ja/en fallback.

Tests: Unit coverage for forward/back wrap, single-pane no-op, zoomed-pane behavior, and public shortcut defaults.

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


Summary by cubic

Adds configurable Next Pane and Previous Pane shortcuts to cycle focus across split panes in stable order with wrap-around. Routed through global shortcuts, View menu, command palette, Settings, schema, and web docs; fixes #2076.

  • New Features

    • Defaults: Ctrl+Option+Command+] (Next) and Ctrl+Option+Command+[ (Previous).
    • Focus behavior: stable split-tree order; wrap-around; stays in a zoomed pane; no-op with one pane.
    • Wiring/docs: View menu and command palette entries with localized labels; KeyboardShortcutSettings, web/data/cmux-shortcuts.ts, and web/data/cmux.schema.json updated; web docs now resolve text[locale] with ja/en fallback.
  • Bug Fixes

    • Preserve Find selection when cycling pane focus.

Written for commit 5ab2bfa. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added Next Pane / Previous Pane commands, Command Palette entries, View menu items and configurable keyboard shortcuts to cycle pane focus with wraparound.
    • English and Japanese localizations added for the new commands and shortcuts.
  • Documentation

    • Keyboard shortcuts docs updated to prefer locale-specific translations when available.
  • Tests

    • Unit tests added for pane-focus cycling and shortcut configuration.

Review Change Stack

@vercel

vercel Bot commented May 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 Jun 14, 2026 11:05pm
cmux-staging Building Building Preview, Comment Jun 14, 2026 11:05pm

@coderabbitai

coderabbitai Bot commented May 26, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@austinywang, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 6 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1ed10ca1-93fd-4e66-9172-faea0cf63648

📥 Commits

Reviewing files that changed from the base of the PR and between efb49b7 and 5ab2bfa.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (1)
  • CLAUDE.md
📝 Walkthrough

Walkthrough

Adds cyclic pane-focus navigation: Workspace and TabManager gain focusNextPane()/focusPreviousPane(); keyboard shortcuts, command-palette commands, and View menu items are wired to those actions; web shortcut metadata/schema and localized strings are added; unit tests cover behavior and shortcut exposure.

Changes

Pane cycling keyboard navigation

Layer / File(s) Summary
Workspace and TabManager pane navigation
Sources/Workspace.swift, Sources/TabManager.swift
Workspace implements pane-cycling with wraparound, resolves target tab/panel, and focuses it. TabManager delegates to the selected workspace and returns false when no workspace exists.
Keyboard shortcut action definitions
Sources/KeyboardShortcutSettings.swift
Adds nextPane/prevPane actions with localized labels, default shortcut key/chord mappings, and helper accessors nextPaneShortcut()/prevPaneShortcut().
Keyboard shortcut event routing
Sources/AppDelegate.swift
handleCustomShortcut recognizes .nextPane/.prevPane, dispatches them to TabManager, and consumes the event early.
Command palette and menu integration
Sources/ContentView.swift, Sources/ContentView+RightSidebarCommandPalette.swift, Sources/cmuxApp.swift
Adds palette.nextPane/palette.previousPane command contributions and handlers; maps command IDs to shortcut actions; adds "Next Pane" and "Previous Pane" menu items bound to the shortcuts.
Web configuration and schema
web/data/cmux-shortcuts.ts, web/data/cmux.schema.json, web/app/[locale]/*
LocalizedText accepts arbitrary locale keys; split-panes shortcuts include nextPane/prevPane with localized descriptions; schema allows the new action ids; localizedText lookup now prefers exact text[locale] when present.
UI string localizations
Resources/Localizable.xcstrings
Adds English and Japanese translations for command titles/subtitles, menu labels, and shortcut labels for next/previous pane actions.
Unit tests
cmuxTests/TabManagerUnitTests.swift, cmuxTests/KeyboardShortcutContextTests.swift
Adds TabManagerPaneFocusCycleTests for forward/backward cycling, wraparound, and single-pane no-op; adds test verifying pane-cycle actions are publicly configurable with expected defaults.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

  • manaflow-ai/cmux#4406: Related edits to AppDelegate shortcut routing pipeline; both touch configured/custom shortcut handling.
  • manaflow-ai/cmux#4445: Also modifies AppDelegate.handleCustomShortcut; changes are related in shortcut-dispatch logic.

Poem

🐇 A rabbit hops from pane to pane,

Cmd+brackets hum its tiny train,
Wraparound steps—left, then right,
Focus settles soft and light,
Keyboard hops, a joyful sight.

🚥 Pre-merge checks | ✅ 15 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive The localization helper logic change in web docs (text[locale] fallback) appears to extend beyond the specific shortcut feature, though it enables proper localization of the new shortcuts. Clarify whether the localized text fallback logic enhancement was necessary for this feature or if it should be a separate refactoring PR.
✅ Passed checks (15 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add cyclic pane focus shortcuts' is clear, specific, and directly summarizes the main change—adding configurable keyboard shortcuts for cycling focus between split panes.
Description check ✅ Passed The description includes all required sections: a comprehensive summary explaining what changed and why, testing methodology, references to the linked issue (#2076), and substantial context about implementation approach.
Linked Issues check ✅ Passed The PR fully addresses the cyclic pane focus requirements from #2076: implements next/previous pane shortcuts with configurable key bindings, wrap-around behavior, integration into all expected systems (menu, palette, settings, schema), unit tests, and localization.
Cmux Swift Actor Isolation ✅ Passed New pane focus methods in @MainActor Workspace and TabManager are properly isolated; all call sites in MainActor contexts. No actor isolation violations.
Cmux Swift Blocking Runtime ✅ Passed New pane focus code contains no blocking/timing patterns (no semaphores, locks, sleeps, or timing-based sync). Tests use deterministic assertions.
Cmux No Hacky Sleeps ✅ Passed PR adds pane focus shortcuts. Non-Swift runtime changes (TypeScript/web files) contain no sleep/setTimeout/polling patterns—only data definitions and locale-aware text selection refactoring.
Cmux Swift Concurrency ✅ Passed All new pane-focus methods (focusNextPane/focusPreviousPane in TabManager/Workspace) are synchronous with no legacy async patterns, DispatchQueue usage, Combine code, or fire-and-forget Tasks.
Cmux Swift @Concurrent ✅ Passed All new Swift functions (focusNextPane/focusPreviousPane) are synchronous with no async/await, invalid @concurrent, or concurrent rule violations.
Cmux Swift File And Package Boundaries ✅ Passed All additions ≤33 lines to existing oversized files, well under 250-line threshold; focused pane-cycling logic with no mixed responsibilities; proper UI/shortcut wiring in app-target code.
Cmux Swift Logging ✅ Passed PR adds pane-focus shortcuts with zero logging violations; all new methods (focusNextPane, focusPreviousPane, handlers) contain no print/debugPrint/dump/NSLog calls.
Cmux User-Facing Error Privacy ✅ Passed PR adds keyboard shortcuts with only safe UI labels ("Next Pane", "Previous Pane"). No credentials, error messages, vendor names, or sensitive data exposed to users.
Cmux Full Internationalization ✅ Passed All 8 Swift localization keys and web shortcuts have complete translations for 20 locales using proper String(localized:) and LocalizedText APIs per guidelines.
Cmux Swiftui State Layout ✅ Passed No new SwiftUI state patterns, GeometryReader measurement, lazy collection store references, or render-time mutations introduced; all changes comply with swiftui-state-layout.md.
Cmux Architecture Rethink ✅ Passed PR adds pane focus cycling via synchronous Workspace.focusPane(); delegates to single focusPanel() owner; no timing, mutable state, observers, duplicate wiring, or bad invariants.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds pane focus shortcuts that navigate within existing panes and menu items; no new NSWindow/NSPanel/WindowGroup created, thus doesn't violate swift-auxiliary-window-close-shortcuts rule.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-2076-keyboard-shortcuts-to-change-focus

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 26, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds configurable Next Pane and Previous Pane shortcuts (default: Ctrl+Opt+Cmd+]/[) for cycling split-pane focus in stable split-tree order with wrap-around. The feature is fully wired through AppDelegate, the View menu, command palette, Settings, the cmux.json schema, and web shortcut docs, and is accompanied by unit tests covering forward/back cycles, single-pane no-op, and zoomed-pane containment.

  • Workspace.focusPane(offset:): uses bonsplitController.allPaneIds for stable ordering, wraps correctly with modular arithmetic, no-ops on single panes, and redirects to the zoomed pane if one is active and focus is elsewhere.
  • Localization: all 8 new xcstrings keys carry translations for every native locale (including nb); the 2 new web shortcut entries cover all 20 locales in web/i18n/routing.ts (including no); localizedText in both web components updated to prefer text[locale] with ja/en fallback.
  • Test coverage: TabManagerPaneFocusCycleTests adds four @MainActor behavior tests; KeyboardShortcutContextTests adds cross-layer default-stroke consistency checks.

Confidence Score: 5/5

Safe to merge — all changed paths are additive, follow established patterns, and are covered by new unit tests.

The implementation reuses the existing focus/find-preservation path in AppDelegate, delegates through TabManager to a well-bounded Workspace method, and all eight new i18n catalog keys are fully translated across every native and web locale. No existing behavior is modified; the new shortcuts occupy a distinct key combination.

No files require special attention.

Important Files Changed

Filename Overview
Sources/Workspace.swift Adds focusNextPane/focusPreviousPane/focusPane(offset:)/focusSelectedPanel; correctly handles zoomed-pane guard, single-pane no-op, and wrap-around arithmetic.
Sources/TabManager.swift Thin delegation wrappers focusNextPane/focusPreviousPane added; consistent with existing tab navigation pattern.
Sources/AppDelegate.swift Routes nextPane/prevPane shortcuts through preferredMainWindowContextForShortcutRouting with find-selection preservation; identical structure to adjacent surface-cycling handlers.
web/data/cmux-shortcuts.ts New nextPane/prevPane shortcut entries correctly provide all 20 web locales from routing.ts; LocalizedText type extended with index signature.
web/app/[locale]/keyboard-shortcuts.tsx localizedText now prefers text[locale] with ja/en fallback; enables new full-locale shortcut descriptions to be picked up correctly.
web/app/[locale]/docs/configuration/page.tsx Same localizedText improvement as keyboard-shortcuts.tsx; mirrors the fix consistently.
Resources/Localizable.xcstrings 8 new catalog keys all carry full translations across every native locale including ar, bs, da, de, en, es, fr, it, ja, km, ko, nb, pl, pt-BR, ru, th, tr, uk, zh-Hans, zh-Hant.
Sources/ContentView.swift Command palette contributions and registry handlers for nextPane/prevPane added; reuses hasFocusedPanel context guard consistent with similar commands.
Sources/cmuxApp.swift View menu entries for Next Pane / Previous Pane added above nextSurface/prevSurface with correct shortcut bindings.
cmuxTests/TabManagerUnitTests.swift Four new @mainactor tests cover: forward cycle, backward wrap, single-pane no-op, and zoomed-pane containment.
cmuxTests/KeyboardShortcutContextTests.swift Two new tests: default strokes match between ShortcutAction and KeyboardShortcutSettings, and all publicShortcutActions have CmuxSettings counterparts.

Sequence Diagram

sequenceDiagram
    participant User
    participant AppDelegate
    participant TabManager
    participant Workspace
    participant BonsplitController

    User->>AppDelegate: Ctrl+Opt+Cmd+] keyEvent
    AppDelegate->>AppDelegate: matchConfiguredShortcut(.nextPane)
    AppDelegate->>AppDelegate: cmuxRememberFindSelectionBeforePanelFocusMove
    AppDelegate->>TabManager: focusNextPane()
    TabManager->>Workspace: focusNextPane()
    Workspace->>BonsplitController: zoomedPaneId?
    alt Pane is zoomed
        BonsplitController-->>Workspace: zoomedPaneId
        Workspace->>Workspace: "focusedPaneId == zoomedPaneId?"
        alt Focus already on zoomed pane
            Workspace-->>TabManager: false (no-op)
        else Focus elsewhere
            Workspace->>Workspace: focusSelectedPanel(inPane: zoomedPaneId)
            Workspace-->>TabManager: true
        end
    else No zoomed pane
        BonsplitController-->>Workspace: allPaneIds
        Workspace->>Workspace: "count > 1?"
        Workspace->>BonsplitController: focusedPaneId
        Workspace->>Workspace: "targetIndex = (current + 1 + n) % n"
        Workspace->>Workspace: focusSelectedPanel(inPane: targetPaneId)
        Workspace-->>TabManager: true
    end
    TabManager-->>AppDelegate: Bool
    AppDelegate-->>User: event consumed
Loading

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

Comment thread Resources/Localizable.xcstrings
Comment thread Sources/Workspace.swift Outdated
@austinywang

Copy link
Copy Markdown
Contributor Author

Addressing the non-threaded CodeRabbit pre-merge note: the locale lookup change is part of this feature, not an unrelated refactor. The new pane-shortcut docs data includes all supported locale keys, and the existing hard-coded en/ja lookup would prevent those new translations from rendering for other locales. The docstring coverage warning is repository-wide baseline/tooling noise, not introduced by this PR's changed Swift/TS paths.

Comment thread Sources/AppDelegate.swift

@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 ccc06d3. Configure here.

Comment thread Sources/Workspace.swift
@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 — 5ab2bfa1 Deployed Jun 14, 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.

Keyboard shortcuts to change focus between panes and tabs

3 participants