Skip to content

Move active surfaces between panes with automatic directional splits - #8764

Merged
austinywang merged 26 commits into
mainfrom
issue-8752-move-surface-between-panes
Jul 27, 2026
Merged

austinywang merged 26 commits into
mainfrom
issue-8752-move-surface-between-panes

Conversation

@austinywang

@austinywang austinywang commented Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add six configurable actions to move the active surface to the previous/next pane in wrapping spatial order or left/right/above/below
  • move through one shared same-workspace transfer path so terminal, browser, and WebView instances retain their live identity and state
  • create an automatic 50/50 split in the requested direction when no adjacent destination exists, while preserving the parent divider extent
  • bound held directional shortcut repeats so they can enter existing panes but never recursively create edge splits
  • expose every action in Keyboard Shortcuts settings, the Command Palette, the View menu, and cmux.json
  • localize labels and shortcut documentation in English and Japanese

Behavior

SurfacePaneMovement is the shared six-action model. Workspace resolves spatial wrapping or Bonsplit directional adjacency, computes the insertion point, and delegates to the existing same-workspace surface transfer machinery used by drag-and-drop. Keyboard routing, Command Palette handlers, View-menu items, and tab context actions converge on the same movement path.

When a directional destination is missing, cmux creates an equal split in that direction and moves the existing surface instance into it. Keyboard auto-repeat can still move into an existing adjacent pane, but cannot create another split while the key is held at an edge. Successful moves insert after the destination pane's selected surface, focus the moved surface, and allow Bonsplit to collapse an emptied source pane. Failed moves restore the previous layout and split-zoom state.

Canvas and remote-tmux mirror layouts reject the action without mutation. Previous/next is a no-op with one pane, and Dock keyboard focus cannot mutate a background workspace.

The existing within-pane actions are labeled “Reorder Surface Left/Right” so they remain distinct from cross-pane movement.

Default shortcuts

  • Previous pane: Control+Command+Shift+[
  • Next pane: Control+Command+Shift+]
  • Left/right/above/below: Option+Command+Shift+Arrow

The directional family adds Shift to the existing Option+Command+Arrow pane-focus bindings. Previous/next adds Control to the existing Command+Shift+[/] surface-navigation family. The defaults are collision-free across current cmux and Ghostty bindings, include Command so they do not steal PTY control sequences, and remain rebindable or unbindable.

Coverage

Behavior-level tests cover:

  • previous/next spatial wrapping
  • all four directional moves, including automatic equal-split creation
  • preservation of parent split extent
  • insertion after destination selection and moved-surface focus
  • source-pane collapse and failure rollback
  • terminal, browser, and WebView identity preservation
  • single-pane no-ops and Canvas/remote-tmux rejection
  • Dock-focus background-workspace protection
  • runtime/Settings default alignment, collision freedom, and Command Palette mapping
  • shared tab-context-action routing

Validation on the merged branch head:

  • 30 focused tests passed across WorkspaceAdjacentPaneMoveTests, DockShortcutRoutingTests, and ReorderShortcutActionTests
  • tagged Debug build passed with ./scripts/reload.sh --tag issue-8752-split
  • PBX normalization and test wiring, workspace package grouping, Package.resolved policy, localization/JSON parsing, locale completeness, and git diff --check passed

At validation time, origin/main had a test-target compile regression. The branch includes the exact reviewed head of upstream repair PR #8857 and a minimal fixture update adding the newly required nil transfer field.

Closes #8752

@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds configurable actions for moving the active surface to previous, next, or directional panes. The implementation centralizes pane transfer logic, exposes keyboard shortcuts through settings, command palette, and View menu, updates schemas and localization, and adds movement and routing coverage.

Changes

Surface movement

Layer / File(s) Summary
Movement actions and shortcut metadata
Packages/macOS/CmuxSettings/..., Sources/KeyboardShortcutSettings*, Sources/SurfacePaneMovement.swift, Resources/Localizable.xcstrings, web/data/*, skills/cmux-settings/...
Adds six pane-movement actions, default shortcuts, labels, command identifiers, localization, metadata, and configuration schema entries.
Workspace surface transfer
Sources/Workspace+SurfaceNavigation.swift, Sources/Workspace.swift
Moves surfaces between existing panes using adjacent or spatial ordering, inserts after the destination selection, preserves focus, and reuses the path for tab-context movement.
Shortcut, command palette, and menu wiring
Sources/AppDelegate+AdjacentNavigationShortcut.swift, Sources/ContentView*, Sources/cmuxApp*, cmux.xcodeproj/project.pbxproj
Routes configured shortcuts and exposes movement commands through the command palette and View menu, with Dock-focus protection and failure beeps.
Movement and shortcut validation
cmuxTests/*
Tests pane wrapping, directional movement, insertion, focus, layout rejection, shortcut defaults, command mappings, and Dock-focused routing.

Runtime and deployment validation

Layer / File(s) Summary
Runtime access and production configuration tests
Sources/Mobile/MobileHostIrohRuntime+Activation.swift, web/tests/client-config-env.test.ts
Accesses the diagnostic log directly during activation and validates production configuration without the optional Iroh limiter identifier.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant AppDelegate
  participant Workspace
  participant CommandPalette
  User->>AppDelegate: Trigger configured movement shortcut
  AppDelegate->>Workspace: moveFocusedSurface(to: movement)
  Workspace->>Workspace: Resolve destination and move surface
  User->>CommandPalette: Select movement command
  CommandPalette->>AppDelegate: performSurfacePaneMovement(...)
  AppDelegate->>Workspace: moveFocusedSurface(to: movement)
Loading

Possibly related PRs

  • manaflow-ai/cmux#8828: Changes the same mobile diagnostic-log access in MobileHostIrohRuntime.activate.

Suggested reviewers: lawrencecchen, azooz2003-bit


Important

Pre-merge checks failed

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

❌ Failed checks (5 errors, 3 warnings)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error The new surface-move path now calls scheduleMovedTerminalRefresh, which uses two DispatchQueue.main.asyncAfter passes (including 30 ms), expanding timing-based sync in production code. Replace the delayed reattach/redraw path with an event-driven completion or lifecycle callback, and remove asyncAfter-based repair from surface moves.
Cmux Swift Concurrency ❌ Error The new pane-move path calls scheduleMovedTerminalRefresh, which uses DispatchQueue.main.asyncAfter for delayed UI repair—an expanded timing-based async workaround. Replace the delayed refresh with an event-driven Bonsplit/reparent completion signal, and avoid adding new asyncAfter-based repair paths.
Cmux Swift Package Boundaries ❌ Error The diff adds a pure, reusable SurfacePaneMovement domain type in app Sources; it’s testable without app lifecycle and fits the existing CmuxWorkspaces boundary better. Extract SurfacePaneMovement (and other pure movement helpers) into Packages/macOS/CmuxWorkspaces, leaving only Workspace/menu/AppKit glue in the app target.
Cmux Full Internationalization ❌ Error New surface-navigation strings are only localized in en/ja, but the touched catalog supports 20 locales; the web shortcut data also adds only en/ja text. Add translated entries for every existing locale in Resources/Localizable.xcstrings, and expand/move web shortcut text so each routing locale has matching localized content.
Cmux Architecture Rethink ❌ Error FAIL: the new pane-move flow calls scheduleMovedTerminalRefresh, which still uses DispatchQueue.main.asyncAfter retries to paper over reparent/layout races, widening a timing-based repair path. Replace the asyncAfter retry with one event-driven lifecycle completion from Bonsplit/host reparenting, and keep surface-move refresh/focus ownership on that single signal.
Out of Scope Changes check ⚠️ Warning The diff includes unrelated MobileHostIrohRuntime and Vercel env test changes that don't support the pane-movement objective. Move the unrelated mobile and web-test edits into a separate PR unless they are required to unblock this surface-navigation work.
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description is detailed, but it omits required template sections: Testing, Demo Video, Review Trigger, and Checklist. Add the missing template sections, including testing details, a demo video link or note, the review trigger block, and the checklist.
✅ Passed checks (17 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The implementation matches #8752 by adding pane-move actions, split creation, state preservation, and the required safety constraints.
Cmux Swift Actor Isolation ✅ Passed PASS: New SurfacePaneMovement/shortcut metadata are pure Sendable value types; UI mutations stay in @MainActor AppDelegate/Workspace/ContentView paths, so no new isolation debt.
Cmux Browser Automation Off-Main ✅ Passed Touched files only add surface-navigation routing; no browser.* socket waits, WebKit/AppKit worker routing, or policy-test gaps were introduced.
Cmux Expensive Synchronous Load ✅ Passed Diff only adds menu/command routing and workspace move helpers; no expensive sync loaders or large JSON/file scans appear in modified interactive paths.
Cmux Cache Substitution Correctness ✅ Passed PASS: The patch only adds surface-navigation helpers/UI wiring and widens scheduleMovedTerminalRefresh; no persistence/history/snapshot read was swapped for a cache.
Cmux No Hacky Sleeps ✅ Passed No new non-Swift sleeps/timers/polling were added; changed TS/JSON files are data/tests only, and the timing concern is in Swift, out of scope here.
Cmux Algorithmic Complexity ✅ Passed PASS: New loops are over a fixed 6-case enum; moveSurface reuses existing pane/tab helpers and adds no nested or batch rescans.
Cmux Swift @Concurrent ✅ Passed No touched app Swift code adds/misuses @concurrent or nonisolated async; the only new async is a @MainActor test with an explicit hop.
Cmux Swiftpm Lockfiles ✅ Passed PR only adds source-file entries in cmux.xcodeproj and no .gitignore or Package.resolved changes; no SwiftPM pin or package-reference edit triggers the lockfile rule.
Cmux Swift Logging ✅ Passed PASS: The changed production Swift files add no print/debugPrint/dump/NSLog, Logger constants, or ad hoc logging.
Cmux User-Facing Error Privacy ✅ Passed Changed user-facing strings are generic surface-navigation labels; no vendor/internal/provider names, raw errors, IDs, or secret material were added.
Cmux Swiftui State Layout ✅ Passed The SwiftUI changes only add command/menu wiring; no new ObservableObject/@published state, GeometryReader layout, lazy-row store refs, or render-time state writes were introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only adds menu/command-palette shortcut wiring; it does not add or materially change any standalone NSWindow/WindowGroup code or cmuxAuxiliaryWindowIdentifiers registration.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source/config/docs/tests/localization assets; none are in forbidden artifact directories like DerivedData, tmp, cache, or artifacts.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The patch only widens scheduleMovedTerminalRefresh for a new production caller and adds normal navigation helpers; no new #if DEBUG or *ForTesting seams appear in Sources.
Cmux No Ambient Global State ✅ Passed No file-scope funcs, global vars, static-only namespaces, or new singletons were added; the new APIs live on extensions, and SurfacePaneMovement is a real enum.
Title check ✅ Passed The title clearly summarizes the main change: moving active surfaces between panes with automatic splits.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-8752-move-surface-between-panes

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 Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds six configurable actions for moving the active surface between panes: previous/next (spatial wrapping) and left/right/above/below (directional). All six actions route through a shared moveSurface(panelId:to:) transfer path, creating an automatic 50/50 split when no adjacent destination exists, and preserving zoom state by snapshotting and restoring on failure.

  • SurfacePaneMovement is a new six-case enum that binds each movement to its KeyboardShortcutSettings.Action, palette command ID, localized title, and search keywords, then drives shortcut routing, Command Palette, and View-menu items from a single source.
  • Workspace+SurfaceNavigation contains the core movement logic: resolves the destination pane (Bonsplit adjacency or spatial wrap), handles directional split creation when no neighbor exists, snaps split-zoom before the transfer, restores it on Bonsplit rejection, and inserts after the destination's selected surface.
  • Keyboard auto-repeat is bounded to allow entry into an existing adjacent pane but not recursive edge-split creation; Canvas and remote-tmux layouts are rejected without mutation; Dock keyboard focus gates prevent background-workspace mutation.

Confidence Score: 5/5

Safe to merge. The change is well-scoped: new movement actions flow through the existing same-workspace surface transfer path, all guards (Canvas, remote-tmux, Dock focus, key-repeat edge) are exercised by the 30 new tests, and zoom rollback on failure has been explicitly verified.

The core movement logic, zoom snapshot/restore, directional-split creation, insertion ordering, and identity preservation for terminal/browser/WebView instances are all covered by focused behavior tests that passed on the merged branch head. Localization is complete in both supported locales across Swift xcstrings and web data. No new global state, no test/debug seams in production source, and no actor isolation regressions are introduced.

Files Needing Attention: No files require special attention. The matchesSurfacePaneMovementShortcut default-arrow fallback in AppDelegate+AdjacentNavigationShortcut.swift is non-obvious but confirmed correct by the matchDirectionalShortcut implementation.

Important Files Changed

Filename Overview
Sources/SurfacePaneMovement.swift New pure-value enum mapping the six movements to shortcut actions, command IDs, localized titles, and palette keywords. Sendable, Hashable, clean. The linear scan in init?(commandID:) is fine for the fixed six-element set.
Sources/Workspace+SurfaceNavigation.swift Core pane-movement logic. Zoom snapshot/restore on failure is correct; the directional-split path uses bonsplitController.splitPane with movingTab which Bonsplit collapses atomically; spatial wrap arithmetic is guarded by count > 1; insertion-after-selection logic is clear.
Sources/AppDelegate+AdjacentNavigationShortcut.swift Shortcut routing correctly deduplicates routedTabs lookup, adds the six-movement loop with repeat guard, and gates Dock focus. The default: ("←", 123) fall-through in matchesSurfacePaneMovementShortcut is functionally correct because matchDirectionalShortcut falls through to matchShortcutStroke for non-arrow configured keys.
Sources/ContentView+SurfaceNavigationCommands.swift New file correctly extracts palette contributions and command handlers into a shared extension; shared subtitle key command.surfaceNavigation.subtitle is now used for all eight surface-navigation palette entries. Loop closure captures are value-type safe.
Sources/cmuxApp+SurfaceNavigationMenu.swift Correctly uses @ViewBuilder to factor the four existing surface-navigation menu items plus the new six pane-movement items into a single extension. NSApp.keyWindow ?? NSApp.mainWindow is the standard preferred-window fallback in this codebase.
Resources/Localizable.xcstrings All six new shortcut.moveSurface*.label keys and the shared command.surfaceNavigation.subtitle key are added with both en and ja translations. moveSurfaceLeft/Right labels updated consistently to "Reorder Surface …".
web/data/cmux-shortcuts.ts Six new shortcut entries added with correct combos and complete en/ja descriptions; existing moveSurfaceLeft/Right descriptions renamed to "Reorder surface …" consistently.
cmuxTests/WorkspaceAdjacentPaneMoveTests.swift Migrated from XCTest to Swift Testing; 13 new behavior tests cover wrap, adjacency, insertion order, zoom rollback, identity preservation, canvas/tmux rejection, and the tab-context shared path. Private helpers are test-side only.
cmuxTests/DockShortcutRoutingTests.swift Three new tests cover the Dock-focus background-workspace gate, the auto-repeat no-split guard, and the repeat-into-existing-pane path. The isARepeat parameter is correctly threaded into the simulated key event.

Sequence Diagram

sequenceDiagram
    participant KB as Keyboard/Menu/Palette
    participant AD as AppDelegate
    participant WS as Workspace
    participant BS as BonsplitController

    KB->>AD: handleAdjacentNavigationShortcut / performSurfacePaneMovement
    AD->>AD: focusedDockStoreForShortcut (Dock gate)
    AD->>WS: moveFocusedSurface(to: movement, allowMissingDestinationSplit:)
    WS->>WS: "guard layoutMode != .canvas && !isRemoteTmuxMirror"
    WS->>BS: adjacentPane / spatiallyOrderedPaneIds (resolve destination)

    alt Existing destination pane found
        WS->>WS: snapshot zoomedPaneId then clearSplitZoom()
        WS->>WS: insertionIndexAfterSelectedSurface(in: destinationPaneId)
        WS->>BS: moveSurface(panelId:toPane:atIndex:focus:)
        BS-->>WS: didMove Bool
        alt didMove is false
            WS->>BS: togglePaneZoom restore zoom
        end
    else No adjacent pane AND allowMissingDestinationSplit
        WS->>WS: snapshot zoomedPaneId then clearSplitZoom()
        WS->>BS: splitPane(sourcePaneId, orientation, movingTab, insertFirst)
        BS-->>WS: newPaneId atomic moves tab collapses empty source
        WS->>BS: focusPane(newPaneId) and selectTab(tabId)
        WS->>WS: focusPanel(panelId)
    else No destination AND not allowMissingDestinationSplit
        WS-->>AD: false
        AD->>AD: NSSound.beep()
    end
    WS-->>AD: Bool success
Loading

Reviews (11): Last reviewed commit: "Merge branch 'main' of https://github.co..." | Re-trigger Greptile

Comment thread Sources/Workspace+SurfaceNavigation.swift Outdated
Comment thread Sources/ContentView+SurfaceNavigationCommands.swift
@austinywang

Copy link
Copy Markdown
Contributor Author

CI note: the first manual full-CI run was blocked by the repository-wide optional-Iroh-limiter test regression tracked in #8761. Commit a0d2aac is the exact reviewed, test-only #8761 fix (original author preserved) so this PR’s macOS build/test matrix can run. Once #8761 lands on main, this file will drop out of the PR content diff.

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

Caution

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

⚠️ Outside diff range comments (1)
Sources/ContentView+SurfaceNavigationCommands.swift (1)

65-70: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use the owning workspace window for the Dock-focus gate.

In registerSurfaceNavigationCommandHandlers(...) at Sources/ContentView+SurfaceNavigationCommands.swift:69, observedWindow can belong to another panel, and NSApp.keyWindow ?? NSApp.mainWindow can be the command palette or another transient window. That can make performSurfacePaneMovement(...) route the movement to the wrong workspace context and bypass Dock-focus protection. Pass the command’s owning workspace window explicitly, or fail closed when it is unavailable.

🤖 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/ContentView`+SurfaceNavigationCommands.swift around lines 65 - 70,
Update registerSurfaceNavigationCommandHandlers and its
performSurfacePaneMovement call to use the command’s owning workspace window for
preferredWindow, rather than observedWindow or global key/main windows; if no
owning workspace window is available, fail closed instead of routing the
movement through a transient or unrelated window.

Source: Path instructions

🤖 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.

Outside diff comments:
In `@Sources/ContentView`+SurfaceNavigationCommands.swift:
- Around line 65-70: Update registerSurfaceNavigationCommandHandlers and its
performSurfacePaneMovement call to use the command’s owning workspace window for
preferredWindow, rather than observedWindow or global key/main windows; if no
owning workspace window is available, fail closed instead of routing the
movement through a transient or unrelated window.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8cf04e15-61a5-431d-ba8e-99eb55dcd980

📥 Commits

Reviewing files that changed from the base of the PR and between e53143d and 254ebbd.

📒 Files selected for processing (4)
  • Resources/Localizable.xcstrings
  • Sources/ContentView+SurfaceNavigationCommands.swift
  • Sources/Workspace+SurfaceNavigation.swift
  • cmuxTests/WorkspaceAdjacentPaneMoveTests.swift

@cursor

cursor Bot commented Jul 23, 2026

Copy link
Copy Markdown

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.

@austinywang

Copy link
Copy Markdown
Contributor Author

Review follow-up: f17accd addresses the Command Palette window-routing finding. Surface-movement handlers now use only the owning ContentView window and fail closed (with the existing beep) when that window is unavailable; they no longer fall back to an ambient key/main window. The shared AppDelegate Dock-focus gate remains the single mutation guard.

cmux reload-cloud and others added 2 commits July 24, 2026 01:58
Co-authored-by: Kyler <leejianhui260901@gmail.com>
Co-authored-by: Kyler <leejianhui260901@gmail.com>

@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: 1

Caution

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

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

88-96: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Localize command-palette keywords.

These search aliases are English-only, so Japanese users cannot discover these commands through equivalent directional terms. Source them from localized keys/catalog entries alongside the titles.

As per coding guidelines, user-facing text and data must use locale-specific sources and update supported locales.

🤖 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/SurfacePaneMovement.swift` around lines 88 - 96, Update the keywords
property on SurfacePaneMovement to source each command-palette alias from the
existing localized keys or catalog entries used by the command titles, including
equivalent directional terms for supported locales. Extend the locale resources
as needed while preserving the current keyword semantics for previous, next,
left, right, up, and down.

Sources: Coding guidelines, Path instructions

🤖 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 `@Sources/Workspace`+SurfaceNavigation.swift:
- Around line 59-60: Replace the split-move calls in
Sources/Workspace+SurfaceNavigation.swift lines 59-60 with a single
lifecycle-owned Bonsplit/host-reparent completion that reattaches the terminal,
reconciles geometry, and refreshes once without delayed asyncAfter retries. In
Sources/Workspace.swift line 10505, do not widen
scheduleMovedTerminalRefresh(panelId:); expose or reuse a lifecycle completion
API for this path instead.

---

Outside diff comments:
In `@Sources/SurfacePaneMovement.swift`:
- Around line 88-96: Update the keywords property on SurfacePaneMovement to
source each command-palette alias from the existing localized keys or catalog
entries used by the command titles, including equivalent directional terms for
supported locales. Extend the locale resources as needed while preserving the
current keyword semantics for previous, next, left, right, up, and down.
🪄 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 Plus

Run ID: b391b728-f053-4e4a-baf9-25eff33c47a1

📥 Commits

Reviewing files that changed from the base of the PR and between 17d86a4 and 5b9e97f.

📒 Files selected for processing (4)
  • Sources/SurfacePaneMovement.swift
  • Sources/Workspace+SurfaceNavigation.swift
  • Sources/Workspace.swift
  • cmuxTests/WorkspaceAdjacentPaneMoveTests.swift

Comment thread Sources/Workspace+SurfaceNavigation.swift Outdated
cmux reload-cloud and others added 6 commits July 24, 2026 02:43
…eds it

Building main at 4dc00ae fails with a single error:

  Sources/DockSplitStore+RestoredAgentLifecycle.swift:13:62: error: cannot find
  type 'PanelShellActivityState' in scope

That file arrived with #8690 and declares
updatePanelShellActivityState(panelId:state:), whose state parameter is
PanelShellActivityState. That type is a public enum in the CmuxWorkspaces
package, and Swift imports are per-file, so the app target linking the package
is not enough on its own. Every other file in Sources that names the type
imports CmuxWorkspaces; this one imports only Foundation.

ci.yml is dispatch-only, so no PR build runs and nothing caught it.
Second and third errors from the same build, after the missing import:

  Sources/DockSplitStore+SessionSnapshot.swift:44:43: error: generic parameter 'Key' could not be inferred
  Sources/DockSplitStore+SessionSnapshot.swift:44:43: error: generic parameter 'Value' could not be inferred
  Sources/DockSplitStore+SessionSnapshot.swift:332:47: error: generic parameter 'U' could not be inferred

Both are the same shape: a multi-statement closure whose bail-out is a bare
`return nil`, handed to something generic. At line 44 that is
Dictionary(uniqueKeysWithValues:), which has to solve Key and Value; at line 332 it
is Optional.flatMap, which has to solve U. A bare `return nil` carries no type, so
the closure result and the generic parameters each depend on the other and the
solver gives up.

Naming the return types breaks the cycle. The types are the ones already required
by the surrounding code: SessionSplitContainerSnapshot declares
sourceWorkspaceIdsByPanelId as [UUID: UUID]?, DetachedSurfaceTransfer's
sessionRestoreWorkspaceId is a UUID, and observation is a
RestorableAgentSessionIndex.Entry?. Behaviour is unchanged.
Fourth error from the same build:

  Sources/ControlSurfaceResumeTarget.swift:282:40: error: reference to member 'auto' cannot be resolved without a contextual type
  Sources/ControlSurfaceResumeTarget.swift:283:41: error: reference to member 'prompt' cannot be resolved without a contextual type
  Sources/ControlSurfaceResumeTarget.swift:284:19: error: reference to member 'manual' cannot be resolved without a contextual type

surfacePromptForResumeApproval builds an NSAlert over several statements and then
ends with a bare `switch alert.runModal()` whose cases are `.auto`, `.prompt` and
`.manual`. Swift gives a function body an implicit return only when the body is a
single expression, so in a multi-statement body that switch is an expression
statement with nothing to type it, and the leading-dot members have no
SurfaceResumeApprovalPolicy to resolve against.

Returning it supplies the contextual type. Every other trailing switch of this shape
under Sources is the single-expression body of a computed property or a one-statement
function, which is why this is the only one that fails.
…ce-between-panes

# Conflicts:
#	cmux.xcodeproj/project.pbxproj
@austinywang austinywang changed the title Move active surfaces between existing panes Move active surfaces between panes with automatic directional splits Jul 24, 2026
@cursor

cursor Bot commented Jul 24, 2026

Copy link
Copy Markdown

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.

@cursor

cursor Bot commented Jul 24, 2026

Copy link
Copy Markdown

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.

cmux reload-cloud and others added 4 commits July 25, 2026 17:26
…-8752-move-surface-between-panes

# Conflicts:
#	Packages/macOS/CmuxSettings/Sources/CmuxSettings/Values/ShortcutAction.swift
#	Sources/ControlSurfaceResumeTarget.swift
#	Sources/DockSplitStore+SessionSnapshot.swift
#	cmux.xcodeproj/project.pbxproj
…-8752-move-surface-between-panes

# Conflicts:
#	Packages/macOS/CmuxSettings/Sources/CmuxSettings/Values/ShortcutAction.swift
#	Sources/KeyboardShortcutSettings.swift
#	Sources/cmuxApp.swift
#	cmux.xcodeproj/project.pbxproj
#	cmuxTests/DockShortcutRoutingTests.swift
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.

Move the active surface between panes and create missing directional splits

3 participants