Repository navigation
Add reversible Zen Mode - #8249
lawrencecchen wants to merge 8 commits into
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds app-wide Zen Mode session management with reversible workspace settings, lifecycle recovery, command-palette and menu actions, a Cmd+K then Z shortcut, localization, configuration support, and tests. ChangesZen Mode
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ShortcutOrCommand
participant AppDelegate
participant ZenModeController
participant UserDefaults
participant WindowUI
ShortcutOrCommand->>AppDelegate: toggleZenMode(preferredWindow)
AppDelegate->>ZenModeController: begin or end session
ZenModeController->>UserDefaults: persist or restore settings
AppDelegate->>WindowUI: update sidebar and fullscreen state
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 353c5a5d85
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@cmux.xcodeproj/project.pbxproj`:
- Line 4324: Correct the PBXBuildFile references in
cmux.xcodeproj/project.pbxproj: at lines 4324 and 5742, update the Sources-phase
entries to use C71600010000000000000001 and C71610010000000000000001
respectively instead of the corresponding PBXFileReference IDs.
In `@cmuxTests/ZenModeControllerTests.swift`:
- Around line 127-133: Convert ZenModeControllerTests to a final class with
stored defaultsSuiteName and defaults properties, initializing the unique
UserDefaults suite in init and removing the makeDefaults helper and per-test
makeDefaults calls. Add deinit cleanup for the same suite using the appropriate
UserDefaults instance, while preserving the existing test behavior and allowing
tests to use self.defaults directly.
In `@Sources/KeyboardShortcutSettings.swift`:
- Line 208: Add translations for command.toggleZenMode.title in
Resources/Localizable.xcstrings for every supported locale currently missing a
localized value, preserving the existing en and ja translations and the default
English fallback.
🪄 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: 9d918d8a-1208-4324-91d3-cdf08aadf969
📒 Files selected for processing (10)
Resources/Localizable.xcstringsSources/AppDelegate.swiftSources/ContentView.swiftSources/KeyboardShortcutSettings.swiftSources/ZenModeController.swiftSources/cmuxApp.swiftcmux.xcodeproj/project.pbxprojcmuxTests/ZenModeControllerTests.swiftweb/data/cmux-shortcuts.tsweb/data/cmux.schema.json
Greptile SummaryAdds reversible Zen Mode with VS Code-compatible
Confidence Score: 5/5Safe to merge; the Zen Mode state machine, recovery ledger, and chord-timeout refactor are all correct and well-tested. ZenModeController correctly uses guard-let local-copy semantics so end() returns the pre-nil session, guards restoration with current-value equality checks to avoid overwriting user changes made while Zen is active, and separates sidebar crash-recovery from global-settings recovery. The chord-expiry refactor avoids double-delivery via a UUID-based guard between the RunLoop timer and the inline key-event check, and uses NSWindow.sendEvent to replay the prefix so local event monitors are not re-triggered. All termination paths are wired to restoreForTermination(), and window-close hooks call endIfTargeting to clean up the session when the target window disappears. No files require special attention. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User
participant EventMonitor as AppDelegate (Event Monitor)
participant Chord as Chord Handler
participant ZMC as ZenModeController
participant UD as UserDefaults
participant Win as NSWindow
User->>EventMonitor: Cmd+K (prefix)
EventMonitor->>Chord: armConfiguredShortcutChordIfNeeded
Chord->>Chord: Set pendingChord + start 1s Timer
Chord-->>EventMonitor: true (consumed)
alt Within 1s: correct suffix Z arrives
User->>EventMonitor: Z (suffix)
EventMonitor->>Chord: resolvePendingConfiguredShortcutChord
Chord->>Chord: cancel timer, clear pending
Chord-->>EventMonitor: activeChordPrefix set
EventMonitor->>ZMC: begin(windowID, isSidebarVisible, isFullScreen)
ZMC->>UD: write recovery keys
ZMC-->>EventMonitor: Session
EventMonitor->>Win: toggleFullScreen(nil)
else Timeout or mismatch
Chord->>Win: sendEvent(prefixEvent)
end
User->>EventMonitor: Cmd+K Z (toggle off)
EventMonitor->>ZMC: end()
ZMC->>UD: restore settings if unchanged
ZMC->>UD: clearRecoveryState
ZMC-->>EventMonitor: Session
EventMonitor->>Win: restore sidebar and fullscreen
%%{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 User
participant EventMonitor as AppDelegate (Event Monitor)
participant Chord as Chord Handler
participant ZMC as ZenModeController
participant UD as UserDefaults
participant Win as NSWindow
User->>EventMonitor: Cmd+K (prefix)
EventMonitor->>Chord: armConfiguredShortcutChordIfNeeded
Chord->>Chord: Set pendingChord + start 1s Timer
Chord-->>EventMonitor: true (consumed)
alt Within 1s: correct suffix Z arrives
User->>EventMonitor: Z (suffix)
EventMonitor->>Chord: resolvePendingConfiguredShortcutChord
Chord->>Chord: cancel timer, clear pending
Chord-->>EventMonitor: activeChordPrefix set
EventMonitor->>ZMC: begin(windowID, isSidebarVisible, isFullScreen)
ZMC->>UD: write recovery keys
ZMC-->>EventMonitor: Session
EventMonitor->>Win: toggleFullScreen(nil)
else Timeout or mismatch
Chord->>Win: sendEvent(prefixEvent)
end
User->>EventMonitor: Cmd+K Z (toggle off)
EventMonitor->>ZMC: end()
ZMC->>UD: restore settings if unchanged
ZMC->>UD: clearRecoveryState
ZMC-->>EventMonitor: Session
EventMonitor->>Win: restore sidebar and fullscreen
Reviews (5): Last reviewed commit: "Keep interrupted Zen sidebar recovery du..." | Re-trigger Greptile |
There was a problem hiding this comment.
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/AppDelegate.swift (1)
6538-6577: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy liftOwn fullscreen transitions explicitly before clearing Zen recovery state.
toggleFullScreenis asynchronous, but restoration trusts the current style mask. A rapid second toggle can end Zen before fullscreen entry completes, and termination can save the snapshot before fullscreen exit completes, leaving the window or next-launch snapshot in Zen fullscreen state.
Sources/AppDelegate.swift#L6538-L6577: track the desired fullscreen state and reconcile it from window fullscreen lifecycle callbacks rather than conditionally toggling from the instantaneous style mask.Sources/AppDelegate.swift#L1985-L1987: do not clear the recovery ledger or persist the termination snapshot until the same owner has produced the canonical non-Zen window snapshot.Based on coding guidelines, “Keep SwiftUI or AppKit bridge UI lifecycle under one explicit MainActor owner” and do not patch lifecycle races with delays or side channels.
🤖 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/AppDelegate.swift` around lines 6538 - 6577, Update toggleZenMode and restoreZenModeWindowState to let one explicit MainActor owner track the desired fullscreen state and reconcile transitions through window fullscreen lifecycle callbacks, rather than relying on the instantaneous styleMask or delayed toggles. At Sources/AppDelegate.swift lines 6538-6577, ensure rapid enter/exit operations converge to the canonical non-Zen state; at lines 1985-1987, retain the recovery ledger and termination snapshot until that same owner has produced and persisted the canonical non-Zen window snapshot.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.
Inline comments:
In `@Sources/AppDelegate.swift`:
- Around line 15250-15257: Update the configured shortcut chord expiration flow
around configuredShortcutChordTimeoutTask to remove the Task.sleep-based delay
and rely on the shortcut router’s explicit deadline or expiration signal
instead. Have the router own chord lifecycle and invoke
expireConfiguredShortcutChord for the matching pending chord, preserving
cancellation and weak-self behavior without adding another timer or polling
loop.
---
Outside diff comments:
In `@Sources/AppDelegate.swift`:
- Around line 6538-6577: Update toggleZenMode and restoreZenModeWindowState to
let one explicit MainActor owner track the desired fullscreen state and
reconcile transitions through window fullscreen lifecycle callbacks, rather than
relying on the instantaneous styleMask or delayed toggles. At
Sources/AppDelegate.swift lines 6538-6577, ensure rapid enter/exit operations
converge to the canonical non-Zen state; at lines 1985-1987, retain the recovery
ledger and termination snapshot until that same owner has produced and persisted
the canonical non-Zen window snapshot.
🪄 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: 8488344b-1e06-458f-93a8-2c445ee2cee6
📒 Files selected for processing (6)
Packages/macOS/CmuxSettings/Sources/CmuxSettings/Values/ShortcutAction+Defaults.swiftPackages/macOS/CmuxSettings/Sources/CmuxSettings/Values/ShortcutAction.swiftSources/AppDelegate.swiftSources/ZenModeController.swiftcmuxTests/AppDelegateShortcutRoutingTests.swiftcmuxTests/ZenModeControllerTests.swift
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 94c97e827a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 57dbb07515
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Bugbot is paused — on-demand spend limit reachedBugbot 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. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3e202b49f6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
⌘K ZZen Mode across shortcuts, Settings, View menu, and command paletteDepends on and includes #8222.
Verification
zenmd)swift test --package-path Packages/macOS/CmuxSettings: 258 tests passedbun run typecheckbunx eslint data/cmux-shortcuts.tsscripts/check-pbxproj.shscripts/lint-pbxproj-test-wiring.shcmux-unittarget compiled the app and Zen tests, then the existingmainapp-host crash stopped test bootstrap: https://github.com/manaflow-ai/cmux/actions/runs/29479023129UI preflight is UNVERIFIED. Launching the final
zenmdbuild with session restore disabled reproducesCombine/Publisher+AsyncSequence.swift:112: Received an output without requesting demandbefore the Zen shortcut can run. The merged dependency tagswcapreproduces it, and the fix is tracked in #8231.The required Vercel preview remains queued with no reported build error.
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by cubic
Adds a reversible Zen Mode matching VS Code’s ⌘K, Z. It hides the left sidebar, enables Minimal Mode and a content width cap, and enters full screen; on toggle, quit, or relaunch it restores only what Zen changed, with durable crash recovery that restores the sidebar when the original window returns.
cmux.schema.jsonupdates.Written for commit 188ff44. Summary will update on new commits.
Summary by CodeRabbit