Skip to content

Add pane border color settings - #7239

Merged
austinywang merged 5 commits into
mainfrom
issue-7234-pane-border-colors
Jul 3, 2026
Merged

austinywang merged 5 commits into
mainfrom
issue-7234-pane-border-colors

Conversation

@austinywang

@austinywang austinywang commented Jul 3, 2026 •

Copy link
Copy Markdown
Contributor

Closes #7234.

Summary

  • Adds top-level paneBorderColor and activePaneBorderColor support in cmux.json using the existing 6-digit hex color normalization path.
  • Applies paneBorderColor to cmux/Bonsplit pane divider chrome and draws activePaneBorderColor as a focused-pane border in split workspaces.
  • Documents and schemas the new keys, with localized schema descriptions for English and Japanese.

Notes

  • unfocusedPaneOpacity is intentionally deferred. The existing opacity model is Ghostty-terminal-specific; applying pane-wide opacity across all cmux panel types would need a broader design to avoid surprising browser/file/tool panels and accessibility regressions.

Validation

  • ./scripts/reload.sh --tag issue-7234-pane-border-colors
  • python3 scripts/swift_file_length_budget.py
  • python3 scripts/check-package-resolved-policy.py
  • python3 scripts/check-workspace-package-groups.py --check
  • python3 -m json.tool web/data/cmux.schema.json
  • python3 -m json.tool web/messages/en.json
  • python3 -m json.tool web/messages/ja.json
  • Verified docs.configuration.schemaDescriptions contains paneBorderColor and activePaneBorderColor in en and ja.

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


Summary by cubic

Adds configurable pane divider and active‑pane border colors via top‑level paneBorderColor and activePaneBorderColor in cmux.json. Updates apply live in Workspace and Dock; the active border renders as a window overlay and works even if the tmux overlay experiment is off. Ghostty’s internal splits are unaffected.

  • New Features
    • Keys: paneBorderColor and activePaneBorderColor (6‑digit #RRGGBB; null clears), parsed at the root with hex normalization; schema and docs updated with localized descriptions.
    • Dividers use paneBorderColor with a safe fallback; applied to Bonsplit chrome in Workspace and Dock; views observe PaneChromeSettings.didChangeNotification and Settings “Reset All” triggers a full pane‑chrome refresh.
    • Active pane border uses activePaneBorderColor; shown only in multi‑pane splits, hidden when the sidebar has focus; refreshed on setting and layout changes; rendered via a dedicated window overlay controller that stays aligned during focus changes and divider drags via workspacePaneGeometryDidChange.
    • Added a pane‑chrome settings catalog section and JSON path support; tests cover key presence, JSON parsing (including null), color resolution, and overlay model behavior.

Written for commit 67ee286. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added paneBorderColor and optional activePaneBorderColor settings to customize split-workspace pane divider and focused-pane border colors.
    • Pane chrome and overlay now update immediately when these settings change, and when pane geometry changes.
  • Bug Fixes
    • Settings reset now triggers a full pane-chrome refresh after clearing configuration.
    • Border color overrides are applied consistently across chrome rendering.
  • Documentation
    • Updated configuration docs, schema, and UI field descriptions for the new settings.
  • Tests
    • Added coverage for catalog presence, JSON parsing, and chrome-color resolution behavior.

@vercel

vercel Bot commented Jul 3, 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 3, 2026 5:12pm
cmux-staging Building Building Preview, Comment Jul 3, 2026 5:12pm

@coderabbitai

coderabbitai Bot commented Jul 3, 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 paneBorderColor and activePaneBorderColor settings sourced from cmux.json, exposes them through the settings catalog and schema, and wires them into chrome resolution, pane overlay rendering, notification handling, and reset side effects.

Changes

Pane Border Color Feature

Layer / File(s) Summary
PaneChromeSettings core storage and defaults
Sources/PaneChromeSettings.swift, cmux.xcodeproj/project.pbxproj
New PaneChromeSettings enum defines UserDefaults keys, defaults, notification, and helpers to read, resolve, and normalize border color hex values; file registered in Xcode project.
Settings catalog integration
Packages/macOS/CmuxSettings/.../PaneChromeCatalogSection.swift, SettingCatalog.swift, SettingCatalogTests.swift
Adds PaneChromeCatalogSection with two DefaultsKey<String> entries, registers paneChrome on SettingCatalog, and extends catalog tests to verify the new key IDs are reachable.
cmux.json parsing and change notification
Sources/CmuxSettingsJSONPathSupport.swift, Sources/KeyboardShortcutSettingsFileStore.swift, cmuxTests/KeyboardShortcutModifierHoldHintsSettingsFileTests.swift
Adds the border color keys to the supported JSON path whitelist, parses them into managed defaults, and posts PaneChromeSettings change notifications when those managed values change; includes a settings-file test.
Chrome color resolution wiring
Sources/Workspace.swift, Sources/DockSplitStore+Appearance.swift, cmuxTests/GhosttyConfigTests.swift
Extends workspace chrome-color helpers with an optional pane border override, threads the configured value into workspace chrome application paths and Dock split appearance, and adds tests covering the resolved border color behavior.
Pane geometry change notification and overlay refresh coalescing
Sources/TabManager.swift, Sources/Workspace.swift, Sources/ContentView.swift, Sources/WindowTmuxWorkspacePaneOverlayController.swift, cmux.xcodeproj/project.pbxproj
Adds the workspace pane geometry notification, posts it from split geometry changes, and centralizes coalesced overlay refresh scheduling and wiring in ContentView and the new overlay controller.
Active pane border overlay rendering
Sources/TmuxWorkspacePaneOverlayRenderState.swift, Sources/TmuxWorkspacePaneOverlayView.swift, Sources/WorkspaceContentView.swift, cmuxTests/TmuxWorkspacePaneOverlayModelTests.swift
Extends the tmux overlay render state, model, and view with active pane border fields and drawing logic, and adds model coverage for the new state.
Live chrome refresh on settings change
Sources/DockPanelView.swift, Sources/WorkspaceContentView.swift
Subscribes DockPanelView and WorkspaceContentView to PaneChromeSettings change notifications and reapplies chrome or appearance immediately when they fire.
Reset-all-settings host side effects
Packages/macOS/CmuxSettingsUI/.../SettingsHostActions.swift, ResetSection.swift, SettingsWindowScene.swift, Sources/HostSettingsActions.swift
Adds resetAllSettingsSideEffects to the settings host action surface, threads host actions into ResetSection, and invokes the host reset side effects during reset.
Documentation and schema updates
docs/configuration.md, web/data/cmux.schema.json, web/messages/en.json, web/messages/ja.json
Documents paneBorderColor and activePaneBorderColor, adds schema properties, and adds localized description strings.

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

Possibly related issues


Important

Pre-merge checks failed

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

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Full Internationalization ❌ Error The new web schema descriptions for paneBorderColor/activePaneBorderColor were added only in en and ja; the other 18 locales in web/i18n/routing.ts are missing them. Add matching translated schemaDescriptions entries for both keys in every locale JSON under web/messages/.
Cmux No Ambient Global State ❌ Error Sources/PaneChromeSettings.swift:3 adds a caseless enum namespace with only static lets/functions, which the rule forbids as ambient global API. Move pane-chrome behavior onto an injectable owning type (or existing owner), and keep any local helpers private/fileprivate instead of a static namespace.
Description check ⚠️ Warning The description covers summary and validation but omits required template sections like Demo Video, Review Trigger, and Checklist. Add the missing template sections: Testing, Demo Video, Review Trigger, and Checklist, or clearly mark any unavailable items.
✅ Passed checks (22 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes add configurable pane divider and active border colors, document/localize them, and leave unfocused opacity deferred as optional.
Out of Scope Changes check ✅ Passed The extra refactors and notification plumbing appear to support the pane-border feature rather than introduce unrelated behavior.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Cmux Swift Actor Isolation ✅ Passed New UI/state types are MainActor or pure values; no new background access or Sendable isolation regression appears in the diff.
Cmux Swift Blocking Runtime ✅ Passed PASS: The diff only adds event-driven notifications and a main-actor Task coalescer; no new semaphores, waits, sleeps, syncs, or locks in production Swift.
Cmux Browser Automation Off-Main ✅ Passed PR doesn’t touch TerminalController or ControlCommandExecutionPolicy; no browser.* socket-routing changes or worker-lane policy regressions were introduced.
Cmux Expensive Synchronous Load ✅ Passed No new agent-history loads or broad JSON/JSONL scans were added; the diff only wires pane-chrome settings, notifications, and border rendering.
Cmux Cache Substitution Correctness ✅ Passed UI-only AppStorage/UserDefaults reads are event-driven via PaneChromeSettings.didChangeNotification; no persistence/history/undo snapshot cache swap found.
Cmux No Hacky Sleeps ✅ Passed No changed TS/JS/shell/runtime script files introduce sleeps, timers, polling, or fixed waits; the non-Swift diff is docs, JSON, and project metadata.
Cmux Algorithmic Complexity ✅ Passed PR adds only fixed-bound key checks and single-pass batching; no new nested scans or repeated rescans in hot paths, and pane counts come from an array-backed API.
Cmux Swift Concurrency ✅ Passed No new background queues, completion handlers, or app-state Combine; the only new Task is a short main-actor UI refresh hop at an AppKit/SwiftUI boundary.
Cmux Swift @Concurrent ✅ Passed No new @concurrent or nonisolated-async misuse found; added async work is explicitly hopped to @MainActor via Task and the rest is synchronous/UI-bound.
Cmux Swift File And Package Boundaries ✅ Passed No oversized new Swift file or >250-line growth; new code stays in small app glue/UI files, while settings/schema logic is isolated in CmuxSettings package.
Cmux Swiftpm Lockfiles ✅ Passed PR only adds sources/docs; no Package.swift, .gitignore, or Package.resolved changes, and cmux.xcodeproj diff has no SwiftPM package-reference edits.
Cmux Swift Logging ✅ Passed PASS: Full patch scan found no added print/debugPrint/dump/NSLog or new Logger declarations in runtime Swift; changes are settings/overlay only.
Cmux User-Facing Error Privacy ✅ Passed No new user-facing error/alert/recovery copy was added; the diff only adds settings/docs/tests and internal notifications.
Cmux Swiftui State Layout ✅ Passed The PR only adds @State snapshots and AppKit-bridge overlay refreshes; no new ObservableObject/@published, GeometryReader layout measurement, lazy-row store refs, or render-time writes.
Cmux Architecture Rethink ✅ Passed PASS: the PR uses required notification bridges and a single overlay controller owner; no sleeps, polling, or split-state lifecycle hacks were introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds only an overlay controller inside existing windows; no new NSWindow/NSPanel/WindowGroup appears, and no new cmux.* auxiliary identifier is needed.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source/docs/config/test files; the TSV is a tracked CI budget reference, not a scratch or generated artifact.
Cmux No Test Or Debug Seam In Production Source ✅ Passed Touched production files add only pane-chrome/settings plumbing and notifications; no new debug*/ForTesting test seam or debug-only accessor was added.
Title check ✅ Passed The title is concise and matches the main change: adding pane border color 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-7234-pane-border-colors

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.

@austinywang
austinywang force-pushed the issue-7234-pane-border-colors branch from fecd557 to 0de4281 Compare July 3, 2026 04:49
@greptile-apps

greptile-apps Bot commented Jul 3, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds paneBorderColor and activePaneBorderColor as top-level cmux.json keys. paneBorderColor overrides the Bonsplit divider chrome color; activePaneBorderColor renders a focused-pane border overlay via a new WindowTmuxWorkspacePaneOverlayController that coalesces geometry changes and activates independently of the tmux-overlay experiment flag.

  • Parsing, UserDefaults write-back, settings catalog registration, schema, docs, and all 20 locale files are updated in a single consistent pass.
  • WindowTmuxWorkspacePaneOverlayController is extracted from ContentView.swift into its own file, gaining scheduleGeometryRefresh to coalesce divider-drag updates via Task { @MainActor } and a hasRenderedState guard so stale borders are cleared when layout collapses to a single pane.
  • "Reset All" now calls resetAllSettingsSideEffects() through SettingsHostActions, ensuring the pane-chrome notification fires after the catalog is cleared and live divider/overlay colors revert to defaults.

Confidence Score: 5/5

Safe to merge; all new paths are well-guarded and localization is complete across all 20 supported locales.

The parsing, notification, overlay-controller, and chrome-color pipelines are each independently correct. The geometry-refresh coalescing via Task { @mainactor } avoids races during divider drags. The multi-pane / canvas / sidebar-focus guards in shouldShowActivePaneBorder prevent the border from showing in unintended states, and hasRenderedState ensures a stale border is cleared when layout collapses. The previously-flagged missing translations have been resolved — all 20 locale files now carry matching entries. Tests cover catalog presence, hex normalization, JSON parsing, and the overlay model apply/clear cycle.

No files require special attention.

Important Files Changed

Filename Overview
Sources/WindowTmuxWorkspacePaneOverlayController.swift New file extracted from ContentView.swift; adds geometry-refresh coalescing via Task { @mainactor } and a hasRenderedState guard to clear stale borders on layout collapse.
Sources/PaneChromeSettings.swift New caseless-enum namespace for paneBorderColor / activePaneBorderColor defaults key constants and helper statics; ambient-global-state concern already flagged in a prior review thread.
Sources/ContentView.swift Moved overlay controller to its own file; adds @AppStorage for activePaneBorderColorKey, shouldShowActivePaneBorder guard (multi-pane, non-canvas, sidebar not focused), and listeners for workspacePaneGeometryDidChange, workspaceLayoutModeDidChange, and activePaneBorderColorHex onChange.
Sources/Workspace.swift bonsplitChromeColors and resolvedChromeColors gain paneBorderColorHex parameter with default nil; call sites pass PaneChromeSettings.paneBorderColorHex(); splitTabBar delegate now posts workspacePaneGeometryDidChange.
Sources/KeyboardShortcutSettingsFileStore.swift Parses paneBorderColor and activePaneBorderColor from cmux.json root via parsePaneChromeSettings; coalesces notification posting with paneChromeDidChange flag in the apply loop.
Sources/WorkspaceContentView.swift Adds activePaneBorderRect/activePaneBorderColorHex to TmuxWorkspacePaneOverlayModel and clear(); subscribes to PaneChromeSettings.didChangeNotification for live divider chrome refresh.
Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/ResetSection.swift ResetSection now requires hostActions and calls resetAllSettingsSideEffects() after clearing the catalog, ensuring pane-chrome notification fires on reset.
web/messages/en.json Adds paneBorderColor and activePaneBorderColor schema description keys; all 20 supported locale files receive matching entries.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant JSON as cmux.json
    participant Store as KeyboardShortcutSettingsFileStore
    participant UD as UserDefaults
    participant WCV as WorkspaceContentView
    participant CV as ContentView
    participant OC as WindowTmuxWorkspacePaneOverlayController
    participant WS as Workspace (BonsplitDelegate)

    JSON->>Store: parse paneBorderColor / activePaneBorderColor
    Store->>UD: write normalized hex (or nil)
    Store->>Store: "paneChromeDidChange = true"
    Store->>WCV: PaneChromeSettings.didChangeNotification
    WCV->>WCV: applyGhosttyChrome (divider color via bonsplitChromeColors)
    Store->>CV: "@AppStorage(activePaneBorderColorKey) onChange"
    CV->>OC: refreshTmuxWorkspacePaneWindowOverlay
    OC->>OC: update(state:) — draw/clear border overlay

    WS->>WS: splitTabBar(_:didChangeGeometry:)
    WS->>CV: workspacePaneGeometryDidChange notification
    CV->>OC: "scheduleGeometryRefresh { stateProvider }"
    Note over OC: coalesces per main-actor turn
    OC->>CV: stateProvider() on next turn
    CV->>OC: update(state:) — realign border to new geometry
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 JSON as cmux.json
    participant Store as KeyboardShortcutSettingsFileStore
    participant UD as UserDefaults
    participant WCV as WorkspaceContentView
    participant CV as ContentView
    participant OC as WindowTmuxWorkspacePaneOverlayController
    participant WS as Workspace (BonsplitDelegate)

    JSON->>Store: parse paneBorderColor / activePaneBorderColor
    Store->>UD: write normalized hex (or nil)
    Store->>Store: "paneChromeDidChange = true"
    Store->>WCV: PaneChromeSettings.didChangeNotification
    WCV->>WCV: applyGhosttyChrome (divider color via bonsplitChromeColors)
    Store->>CV: "@AppStorage(activePaneBorderColorKey) onChange"
    CV->>OC: refreshTmuxWorkspacePaneWindowOverlay
    OC->>OC: update(state:) — draw/clear border overlay

    WS->>WS: splitTabBar(_:didChangeGeometry:)
    WS->>CV: workspacePaneGeometryDidChange notification
    CV->>OC: "scheduleGeometryRefresh { stateProvider }"
    Note over OC: coalesces per main-actor turn
    OC->>CV: stateProvider() on next turn
    CV->>OC: update(state:) — realign border to new geometry
Loading

Reviews (13): Last reviewed commit: "Update Swift file length budget after ma..." | Re-trigger Greptile

Comment thread Sources/WorkspaceTabColorSettings.swift Outdated
Comment on lines +282 to +305
enum PaneChromeSettings {
static let paneBorderColorKey = "paneBorderColor"
static let activePaneBorderColorKey = "activePaneBorderColor"
static let defaultColorHex = ""
static let activeBorderLineWidth = 2.0
static let didChangeNotification = Notification.Name("cmux.paneChromeSettingsDidChange")

static func paneBorderColorHex(defaults: UserDefaults = .standard) -> String? {
normalizedColorHex(defaults.string(forKey: Self.paneBorderColorKey))
}

static func resolvedPaneBorderHex(configuredHex: String?, fallback: String) -> String {
normalizedColorHex(configuredHex) ?? fallback
}

static func notifyDidChange(notificationCenter: NotificationCenter = .default) {
notificationCenter.post(name: Self.didChangeNotification, object: nil)
}

private static func normalizedColorHex(_ rawValue: String?) -> String? {
guard let rawValue else { return nil }
return WorkspaceTabColorSettings.normalizedHex(rawValue)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 New caseless enum used as a static-only namespace

PaneChromeSettings is a caseless enum whose entire API is static let/static func members — the same pattern the ambient-global-state rule flags. The color helper functions (paneBorderColorHex, resolvedPaneBorderHex, notifyDidChange, normalizedColorHex) are thin wrappers that delegate to WorkspaceTabColorSettings.normalizedHex and NotificationCenter; there is no reason they cannot live as methods or extensions on WorkspaceTabColorSettings or be owned by the settings store that already coordinates these keys. Introducing a second static namespace type in the same file duplicates the pattern rather than fixing it.

Rule Used: Flag new ambient global state in production Swift:... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@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/DockSplitStore+Appearance.swift (1)

12-14: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Dock panel borders need the pane-chrome observer
DockPanelView already reapplies chrome on .ghosttyConfigDidReload, but not on PaneChromeSettings.didChangeNotification. Add that observer so paneBorderColor and activePaneBorderColor changes in cmux.json update the Dock immediately instead of waiting for the next config reload.

🤖 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/DockSplitStore`+Appearance.swift around lines 12 - 14, The Dock panel
only reapplies appearance on .ghosttyConfigDidReload, so changes to pane border
colors from PaneChromeSettings.didChangeNotification are missed until a full
reload. Update the Dock panel observer setup in DockPanelView to also listen for
PaneChromeSettings.didChangeNotification and call the existing
applyGhosttyChrome(from:) path so paneBorderColor and activePaneBorderColor
changes in cmux.json update immediately.

Source: Coding guidelines

🤖 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/DockSplitStore`+Appearance.swift:
- Around line 12-14: The Dock panel only reapplies appearance on
.ghosttyConfigDidReload, so changes to pane border colors from
PaneChromeSettings.didChangeNotification are missed until a full reload. Update
the Dock panel observer setup in DockPanelView to also listen for
PaneChromeSettings.didChangeNotification and call the existing
applyGhosttyChrome(from:) path so paneBorderColor and activePaneBorderColor
changes in cmux.json update immediately.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6929c444-d395-472a-ab73-624d90b18935

📥 Commits

Reviewing files that changed from the base of the PR and between fa5e0c6 and fecd557.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (16)
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/PaneChromeCatalogSection.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/SettingCatalog.swift
  • Packages/macOS/CmuxSettings/Tests/CmuxSettingsTests/SettingCatalogTests.swift
  • Sources/CmuxSettingsJSONPathSupport.swift
  • Sources/DockSplitStore+Appearance.swift
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • Sources/Panels/PanelContentView.swift
  • Sources/Workspace.swift
  • Sources/WorkspaceContentView.swift
  • Sources/WorkspaceTabColorSettings.swift
  • cmuxTests/GhosttyConfigTests.swift
  • cmuxTests/KeyboardShortcutModifierHoldHintsSettingsFileTests.swift
  • docs/configuration.md
  • web/data/cmux.schema.json
  • web/messages/en.json
  • web/messages/ja.json

@austinywang
austinywang force-pushed the issue-7234-pane-border-colors branch 3 times, most recently from f650270 to bd2660d Compare July 3, 2026 05:20
@austinywang
austinywang force-pushed the issue-7234-pane-border-colors branch 2 times, most recently from c7a8b83 to 77baa27 Compare July 3, 2026 05:49

@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

🤖 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
`@Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/PaneChromeCatalogSection.swift`:
- Around line 8-21: The pane border setting keys are duplicated as hardcoded
string literals in PaneChromeCatalogSection and the app-side PaneChromeSettings
constants, with no test guarding that they stay in sync. Add a lightweight
app-target test in cmuxTests that asserts the paneBorderColor and
activePaneBorderColor key constants match the expected literals, using
PaneChromeSettings.paneBorderColorKey and the active variant so any drift is
caught early. Keep the production definitions unchanged and pin the cross-module
contract with assertions instead of sharing the constant directly.
🪄 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: 866eaced-e270-4b16-ab97-f1719b2e5992

📥 Commits

Reviewing files that changed from the base of the PR and between c7a8b83 and 77baa27.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (26)
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/PaneChromeCatalogSection.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/SettingCatalog.swift
  • Packages/macOS/CmuxSettings/Tests/CmuxSettingsTests/SettingCatalogTests.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Environment/SettingsHostActions.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Scene/SettingsWindowScene.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/ResetSection.swift
  • Sources/CmuxSettingsJSONPathSupport.swift
  • Sources/ContentView.swift
  • Sources/DockPanelView.swift
  • Sources/DockSplitStore+Appearance.swift
  • Sources/HostSettingsActions.swift
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • Sources/PaneChromeSettings.swift
  • Sources/TabManager.swift
  • Sources/TmuxWorkspacePaneOverlayRenderState.swift
  • Sources/TmuxWorkspacePaneOverlayView.swift
  • Sources/Workspace.swift
  • Sources/WorkspaceContentView.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/GhosttyConfigTests.swift
  • cmuxTests/KeyboardShortcutModifierHoldHintsSettingsFileTests.swift
  • cmuxTests/TmuxWorkspacePaneOverlayModelTests.swift
  • docs/configuration.md
  • web/data/cmux.schema.json
  • web/messages/en.json
  • web/messages/ja.json

Comment on lines +8 to +21
public struct PaneChromeCatalogSection: SettingCatalogSection {
/// Optional pane divider color for split workspaces.
public let paneBorderColorHex = DefaultsKey<String>(
id: "paneBorderColor",
defaultValue: "",
userDefaultsKey: "paneBorderColor"
)

/// Optional focused pane border color for split workspaces.
public let activePaneBorderColorHex = DefaultsKey<String>(
id: "activePaneBorderColor",
defaultValue: "",
userDefaultsKey: "activePaneBorderColor"
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Cross-module string-literal duplication has no drift guard.

"paneBorderColor"/"activePaneBorderColor" are hardcoded here (both id and userDefaultsKey) because this SwiftPM package can't import the app target's PaneChromeSettings.swift, which independently defines paneBorderColorKey/activePaneBorderColorKey as the same literals. This shows PaneChromeSettings.paneBorderColorHex resolves via PaneChromeSettings.resolvedPaneBorderHex using a configured paneBorderColorHex and a fallback, i.e. the two definitions must stay byte-identical for the feature to work, but nothing currently asserts that. If either side's literal changes independently, the setting will silently stop round-tripping through cmux.json/UserDefaults.

Consider adding a lightweight app-target test (in cmuxTests) asserting PaneChromeSettings.paneBorderColorKey == "paneBorderColor" (and the active variant) to pin both sides to the same contract, since the two modules can't share the constant directly.

🤖 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
`@Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/PaneChromeCatalogSection.swift`
around lines 8 - 21, The pane border setting keys are duplicated as hardcoded
string literals in PaneChromeCatalogSection and the app-side PaneChromeSettings
constants, with no test guarding that they stay in sync. Add a lightweight
app-target test in cmuxTests that asserts the paneBorderColor and
activePaneBorderColor key constants match the expected literals, using
PaneChromeSettings.paneBorderColorKey and the active variant so any drift is
caught early. Keep the production definitions unchanged and pin the cross-module
contract with assertions instead of sharing the constant directly.

@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/ContentView.swift (1)

1013-1173: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the new overlay-state/refresh helpers out of ContentView.swift.

This adds a self-contained cluster of ~160 lines (tmuxWorkspacePaneWindowOverlayState, refreshTmuxWorkspacePaneWindowOverlay, shouldScheduleTmuxWorkspacePaneWindowOverlayGeometryRefresh, scheduleTmuxWorkspacePaneWindowOverlayGeometryRefresh) to an already very large file. The repo already extracts related logic into dedicated extension files (e.g. Sources/DockSplitStore+Appearance.swift, Sources/AppDelegate+DockSurfaceMove.swift); moving these methods into a ContentView+TmuxOverlay.swift extension would keep this file's growth in check without behavior change.

🤖 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.swift` around lines 1013 - 1173, The new tmux overlay
state/refresh logic is grouped inside ContentView.swift, which is making an
already large file harder to maintain. Move tmuxWorkspacePaneWindowOverlayState,
refreshTmuxWorkspacePaneWindowOverlay,
shouldScheduleTmuxWorkspacePaneWindowOverlayGeometryRefresh, and
scheduleTmuxWorkspacePaneWindowOverlayGeometryRefresh into a dedicated
ContentView extension file such as ContentView+TmuxOverlay.swift, matching the
repo’s existing pattern for extracted behavior, while keeping the same call
sites and behavior intact.
🤖 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/ContentView.swift`:
- Around line 1013-1020: The active-pane-border gating rule is duplicated
between tmuxWorkspacePaneWindowOverlayState(for:) and
shouldScheduleTmuxWorkspacePaneWindowOverlayGeometryRefresh, so they can drift.
Extract the shared condition into a single private helper like
shouldShowActivePaneBorder(for:) (or compute it once and pass it through), and
use that helper in both places so the overlay render state and geometry-refresh
scheduling always agree.

---

Outside diff comments:
In `@Sources/ContentView.swift`:
- Around line 1013-1173: The new tmux overlay state/refresh logic is grouped
inside ContentView.swift, which is making an already large file harder to
maintain. Move tmuxWorkspacePaneWindowOverlayState,
refreshTmuxWorkspacePaneWindowOverlay,
shouldScheduleTmuxWorkspacePaneWindowOverlayGeometryRefresh, and
scheduleTmuxWorkspacePaneWindowOverlayGeometryRefresh into a dedicated
ContentView extension file such as ContentView+TmuxOverlay.swift, matching the
repo’s existing pattern for extracted behavior, while keeping the same call
sites and behavior intact.
🪄 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: 4a972a4e-1a5b-4998-a1c2-62fe0625d301

📥 Commits

Reviewing files that changed from the base of the PR and between 77baa27 and 47121aa.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (27)
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/PaneChromeCatalogSection.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Keys/SettingCatalog.swift
  • Packages/macOS/CmuxSettings/Tests/CmuxSettingsTests/SettingCatalogTests.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Environment/SettingsHostActions.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Scene/SettingsWindowScene.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/ResetSection.swift
  • Sources/CmuxSettingsJSONPathSupport.swift
  • Sources/ContentView.swift
  • Sources/DockPanelView.swift
  • Sources/DockSplitStore+Appearance.swift
  • Sources/HostSettingsActions.swift
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • Sources/PaneChromeSettings.swift
  • Sources/TabManager.swift
  • Sources/TmuxWorkspacePaneOverlayRenderState.swift
  • Sources/TmuxWorkspacePaneOverlayView.swift
  • Sources/WindowTmuxWorkspacePaneOverlayController.swift
  • Sources/Workspace.swift
  • Sources/WorkspaceContentView.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/GhosttyConfigTests.swift
  • cmuxTests/KeyboardShortcutModifierHoldHintsSettingsFileTests.swift
  • cmuxTests/TmuxWorkspacePaneOverlayModelTests.swift
  • docs/configuration.md
  • web/data/cmux.schema.json
  • web/messages/en.json
  • web/messages/ja.json

Comment thread Sources/ContentView.swift
@austinywang
austinywang force-pushed the issue-7234-pane-border-colors branch 2 times, most recently from a1d9f88 to 99933e4 Compare July 3, 2026 08:44
…r-colors

# Conflicts:
#	.github/swift-file-length-budget.tsv
@austinywang
austinywang merged commit eeded15 into main Jul 3, 2026
35 checks passed
azooz2003-bit added a commit that referenced this pull request Jul 3, 2026
Both-diverged merge: main advanced 21 commits on the original god-file
structure while this branch dissolved those gods into packages. Resolved
all 19 conflicts keeping the refactored structure and folding main's new
features into their refactored homes:

- #7239 pane-border colors (PaneChromeSettings.paneBorderColorHex, active
  pane border rect/hex in TmuxWorkspacePaneOverlayRenderState + overlay)
- #7157 file-preview zoom (ShortcutContext.browserOrFilePreviewTextEditor,
  GlobalFontMagnification observer in FilePreviewTextEditor)
- canvas-layout shortcut contexts (ShortcutContext.canvasLayout/
  canvasLayoutOutsideFocusedContent + full shortcutContext routing)
- #7155 cwd-inheritance rescue (resumedAgentPaneWorkingDirectoryRescue and
  restoredResumeSessionWorkingDirectories plumbing on Workspace)
- #7259 Fork Conversation (delegated to agentForkCoordinator)
- #7221/#6612 sidebar lazy-layout probes (value @Environment reads on
  TabItemView; hot path Equatable/.equatable() preserved)

KeyboardShortcutActionContext.swift (renamed to KeyboardShortcutContext in
the refactor) and Sources/TmuxWorkspacePaneOverlayRenderState.swift
(moved to CmuxCore) resolved as modify/delete: main's edits ported into
the refactored homes, app-target copies removed. pbxproj pruned of 6
package-moved files (TmuxOverlayExperiment*, WorkspaceTabColorEntry,
WorkspacePlacement+Resolution, ExtensionSidebarWorkspaceRowView,
TmuxWorkspacePaneOverlayRenderState) whose refs would dangle.

9 TODO(delta-merge) markers flag cross-package behavioral tweaks (#7155/
#6617 refinements, resume-rebind, one new palette contribution, overlay
controller reconciliation) that live outside the conflicted files and are
tracked for follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
azooz2003-bit added a commit that referenced this pull request Jul 4, 2026
Fixes surfaced by compiling the both-diverged merge, all keeping HEAD's
refactored package structure while preserving main's delta features:

- CLI: drop spurious `import CmuxCommandPalette` (matches origin/main;
  the SSHPTYAttachReconnect* helpers are same-target).
- pbxproj: prune package-moved/dangling app-target refs (PaneMemory engine
  family → CmuxPanes, TmuxOverlayExperiment*/WorkspaceTabColorEntry/
  WorkspacePlacement+Resolution/ExtensionSidebarWorkspaceRowView →
  packages, GhosttyKeyModifiers/SidebarBonsplitWorkspaceRowDropModifier
  HEAD-deleted); re-wire Sources/TabManager+BrowserFocus.swift (lost its
  entry in the pbxproj union).
- TabManager: dedup focusedBrowserPanel (keep TabManager.swift's compiled
  version; TabManager+BrowserFocus keeps the unique markdown/file-preview
  accessors + zoom helpers).
- #7239 pane-border colors: add `paneBorderColorHex` param to the package
  BonsplitChromeColorResolver.bonsplitChromeColors/resolvedChromeColors +
  resolvedPaneBorderHex helper; thread the border through the app-target
  AppTmuxWorkspacePaneOverlayView call sites; SettingsFileParser parses the
  paneBorderColor/activePaneBorderColor keys.
- WindowTmuxWorkspacePaneOverlayController: import CmuxCore, drop duplicate
  container-identifier decl (ContentView owns the module-level one).
- Missing package imports on main-added app files: PaneChromeSettings
  (CmuxWorkspaces), KeyboardShortcutContext (CmuxAppKitSupportUI),
  DockSplitStore+SurfaceTransfer (CmuxWorkspaces), Workspace+/GhosttyNSView+
  ForkConversationContextMenu (CMUXAgentLaunch).
- #7259 Fork Conversation: add `settingsTitle` to package
  AgentConversationForkDestination; remap legacy
  AgentConversationForkDefaultSettings.current() → configuredDefault().
- #7157 file-preview zoom: remap FilePreviewInteraction.zoomStep →
  FilePreviewZoomInteraction.standard.step.
- #7155 resume rebind: add SurfaceResumeBindingSnapshot.retargetingWorkingDirectory
  to the CmuxWorkspaces package (adapted to HEAD's TerminalStartupWorkingDirectoryPrefix).
- FileExplorer open-selection shortcut: neutralized (TODO) — needs view-class
  state + lifecycle wiring re-add; recorded as follow-up.

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

This branch was successfully deployed

1 active deployment
Preview – cmux — 67ee286c Deployed Jul 3, 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.

Feature request: per-pane border/divider color customization in cmux.json

1 participant