Skip to content

Preserve selected tabs in saved workspace layouts - #9527

Closed
austinywang wants to merge 8 commits into
mainfrom
issue-7444-saved-layouts-preserve-selected-tab-in-n
Closed

austinywang wants to merge 8 commits into
mainfrom
issue-7444-saved-layouts-preserve-selected-tab-in-n

Conversation

@austinywang

@austinywang austinywang commented Aug 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • extend CmuxSurfaceDefinition with an optional selected flag while keeping existing layouts backward compatible
  • capture each Bonsplit pane’s selected tab in both saved-layout export paths, then restore pane selection before applying the workspace’s single global focus
  • document the new hand-written cmux.json field in English and Japanese

Fixes #7444

Testing

  • Red, test-only commit cefc07ea17: on a Tailscale fleet Mac, xcodebuild ... -only-testing:cmuxTests/WorkspaceCustomLayoutOrderTests test-without-building failed only capturedLayoutRestoresSelectedTabInBackgroundPane; the restored title was Background A instead of Background B.
  • Green, fix commit 1ecd3693e7: the same fleet suite passed all 4 tests, including capturedLayoutRestoresSelectedTabInBackgroundPane.
  • Hosted focused run: https://github.com/manaflow-ai/cmux/actions/runs/30882510570
  • Tagged dev build: ./scripts/reload-cloud.sh --tag sym7444 succeeded on blacksmith-6vcpu-macos-26: https://github.com/manaflow-ai/cmux/actions/runs/30882576258 (cloud path used; no local-build fallback).
  • Live socket dogfood against /tmp/cmux-debug-sym7444.sock: created a split workspace with tabs A/B in a background pane, selected B, refocused the other pane, then ran layout save, layout get, and layout open. The saved JSON marked B as selected: true; the reopened live tree selected B in the background pane and retained the other pane’s global focus. Deleted the temporary layout and terminated the tagged app afterward.
  • Localization audit: parsed both touched catalogs, confirmed matching surfaceSelected keys in web/messages/en.json and web/messages/ja.json, and checked the changed docs/Swift diff for new unlocalized UI text.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Preserves per-pane selected tabs in saved, handwritten, and config-action layouts so reopened workspaces keep the right tab in each pane. Adds selected to CmuxSurfaceDefinition and applies tab selection without activation, then restores focus, fixing #7444.

  • New Features

    • Capture and export selected in saved-layout and config-action paths; select the marked tab in each pane when applying layouts.
    • Documented selected in cmux.json and localized the help text across all locales.
  • Bug Fixes

    • Selection runs in a focus-neutral path and restores the prior pane focus when layouts only set selected (no focus), preventing focus theft.

Written for commit 0532b92. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Custom workspace layouts now preserve and restore the selected tab in each pane when reopened.
    • Surface definitions support marking a specific tab for automatic selection.
  • Documentation

    • Added documentation and translations for configuring selected tabs across supported languages.
  • Tests

    • Added coverage confirming selected tabs are preserved during layout capture and restoration.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Custom layouts now capture the selected tab in each pane and restore that selection when surfaces are populated. The selected field is documented and localized. Tests cover saved-layout and configuration-action capture paths.

Changes

Selected tab layout preservation

Layer / File(s) Summary
Capture selected tabs
Sources/CmuxConfig.swift, Sources/Workspace+LayoutCapture.swift, Sources/WorkspaceConfigActionCapture.swift
The surface definition records an optional selected flag. Both capture paths mark the selected tab in each pane, including unsupported-tab fallbacks.
Restore selected tabs
Sources/Workspace+CustomLayout.swift
Surface creation and configuration return panel IDs. Custom layout population selects panels whose definitions have selected set.
Validation and documentation
cmuxTests/WorkspaceCustomLayoutOrderTests.swift, web/app/[locale]/(landing)/docs/custom-commands/page.tsx, web/messages/*.json
Tests verify restoration through saved-layout and configuration-action paths. Documentation and localized strings describe the selected field.

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

Sequence Diagram(s)

sequenceDiagram
  participant LayoutCapture
  participant CustomLayout
  participant Bonsplit
  LayoutCapture->>CustomLayout: record selected surface
  CustomLayout->>Bonsplit: create or configure surfaces
  Bonsplit-->>CustomLayout: return panel IDs
  CustomLayout->>Bonsplit: select panels marked selected
Loading

Possibly related issues

  • manaflow-ai/cmux-dev-artifacts#8208: The issue concerns compile failures in the added WorkspaceCustomLayoutOrderTests file.
  • manaflow-ai/cmux-dev-artifacts#8184: The issue concerns the selected-tab preservation changes and their tests.

Possibly related PRs

Suggested reviewers: lawrencecchen

🚥 Pre-merge checks | ✅ 24 | ❌ 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 (24 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy issue #7444 by extending the schema, capturing selections, restoring them per pane, and preserving backward compatibility.
Out of Scope Changes check ✅ Passed The code, tests, documentation, and localization changes support the selected-tab layout feature and show no unrelated scope.
Cmux Swift Actor Isolation ✅ Passed The PR adds only a Bool? to the existing Sendable value model; selection and capture changes remain in Workspace extensions, and Workspace is explicitly @MainActor. No new isolation boundary or sha...
Cmux Swift Blocking Runtime ✅ Passed Production Swift additions only capture/apply selected tabs and call selectTab; no new waits, sleeps, delayed dispatch, polling, sync, or locks. Existing asyncAfter is unchanged.
Cmux Browser Automation Off-Main ✅ Passed The PR changes layout capture/restoration and localization only; rule-scoped TerminalController.swift and execution policy are unchanged, with no browser.* socket commands added or moved.
Cmux Expensive Synchronous Load ✅ Passed The production Swift diff only adds selected-tab schema, Bonsplit selection, and in-memory capture logic; it adds no agent-history loader, file/JSON scan, transcript access, or interactive synchron...
Cmux Cache Substitution Correctness ✅ Passed The diff adds selected-tab reads from the live BonsplitController in existing layout snapshot paths; it does not replace an authoritative read with a cache or opportunistic value.
Cmux No Hacky Sleeps ✅ Passed The PR adds no non-Swift runtime changes. Its TypeScript diff is documentation-only, localization files add text, and added non-Swift lines contain no sleep, timer, polling, or fixed-delay logic.
Cmux Algorithmic Complexity ✅ Passed The production diff adds one pass over each pane's tabs and constant-time selection tracking; no new nested full-collection scan or repeated sort/filter was introduced.
Cmux Swift Concurrency ✅ Passed The PR adds no Dispatch, Combine, completion-handler, or fire-and-forget Task patterns. Swift changes use synchronous tab selection and capture logic; existing concurrency code is untouched.
Cmux Swift @Concurrent ✅ Passed The PR adds no async, nonisolated, or @concurrent Swift code. Changed Workspace methods remain synchronous and run on the existing @MainActor Workspace; no heavy async call site changed.
Cmux Swift Package Boundaries ✅ Passed The changed Swift logic is @MainActor Workspace/Bonsplit/panel integration, and CmuxSurfaceDefinition remains an internal app-only schema with no SwiftPM consumers; this is app-lifecycle compositio...
Cmux Swiftpm Lockfiles ✅ Passed The complete PR diff changes only Swift sources, tests, docs, and localization; it contains no Package.swift, Package.resolved, .gitignore, Xcode project, workflow, or dependency changes.
Cmux Swift Logging ✅ Passed The PR’s changed Swift diff adds no print, debugPrint, dump, NSLog, ad hoc I/O, Logger, or sensitive-data logging; changes only selection and test logic.
Cmux User-Facing Error Privacy ✅ Passed The PR adds layout selection logic, schema/docs text, and tests; it adds no user-facing errors or diagnostic payloads, and the new config documentation is explicitly allowed.
Cmux Full Internationalization ✅ Passed The docs field uses next-intl useTranslations, and surfaceSelected has non-English entries in all 20 locales listed by web/i18n/routing.ts; Swift changes add no user-facing text or catalogs.
Cmux Swiftui State Layout ✅ Passed The Swift diff only updates Codable layout models and Workspace capture/apply methods; it adds no SwiftUI views, state wrappers, GeometryReader, lazy-row store references, or render-time writes.
Cmux Architecture Rethink ✅ Passed The Swift diff adds schema-backed selection restoration through the shared apply path; Bonsplit remains the source of truth, global focus follows pane selection, and no prohibited timing, locking,...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed Swift changes only update layout schema, capture/apply logic, and tests; they add no standalone window code. The auxiliary-window lint passed via scripts/lint_auxiliary_window_close_shortcuts.py.
Cmux Source Artifacts ✅ Passed All 26 changed paths are product source, tests, documentation, or localization catalogs; no added files, binaries, logs, scratch directories, or artifact extensions appear in the PR diff.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The PR adds only selected-field and layout capture/restoration logic in Sources; the added-line scan found no test/debug guard, seam-named member, or widened visibility wrapper.
Cmux No Ambient Global State ✅ Passed The production Swift diff adds only an instance property and local variables/returns inside existing Workspace methods; it adds no file-scope functions, mutable globals, static namespaces, or singl...
Title check ✅ Passed The title clearly describes the primary change: preserving selected tabs in saved workspace layouts.
Description check ✅ Passed The description provides a clear summary and detailed testing evidence, but it omits the template checklist and demo video section.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-7444-saved-layouts-preserve-selected-tab-in-n

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.

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

🤖 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/WorkspaceCustomLayoutOrderTests.swift`:
- Around line 94-147: Expand capturedLayoutRestoresSelectedTabInBackgroundPane
to cover a hand-written layout with the first surface marked selected and a
layout produced by captureConfigActionSnapshot(). After applying global focus,
assert that every pane restores its configured selected tab, including index 0
and the existing index 1 case.

In `@Sources/CmuxConfig.swift`:
- Line 1617: Add the optional boolean selected property to the surfaces item
definition in cmux.schema.json, matching the selected field decoded by
CmuxSurfaceDefinition and preserving existing schema validation behavior.
🪄 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: 20468d70-e32b-4270-8bce-92dbe3b56032

📥 Commits

Reviewing files that changed from the base of the PR and between a9c351b and 1ecd369.

📒 Files selected for processing (8)
  • Sources/CmuxConfig.swift
  • Sources/Workspace+CustomLayout.swift
  • Sources/Workspace+LayoutCapture.swift
  • Sources/WorkspaceConfigActionCapture.swift
  • cmuxTests/WorkspaceCustomLayoutOrderTests.swift
  • web/app/[locale]/(landing)/docs/custom-commands/page.tsx
  • web/messages/en.json
  • web/messages/ja.json

Comment thread cmuxTests/WorkspaceCustomLayoutOrderTests.swift Outdated
Comment thread Sources/CmuxConfig.swift
@cursor

cursor Bot commented Aug 4, 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 Aug 4, 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.

@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
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.

Saved layouts: preserve selected tab in non-focused multi-tab panes (schema extension)

3 participants