Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,11 @@ enum CmuxEmbeddedConfigSchema {
"default": true,
"description": "Show a confirmation before closing a workspace with a running process, or several workspaces at once. Pinned workspaces still ask when this is off."
},
"alwaysConfirmWorkspaceClose": {
"type": "boolean",
"default": false,
"description": "Ask before every workspace close, even when nothing in it is running. Overrides warnBeforeClosingWorkspace for workspace closes."
},
"warnBeforeClosingWindow": {
"type": "boolean",
"default": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,30 @@ public struct AppCatalogSection: SettingCatalogSection {
)
)

/// Opt-in: ask before every workspace close, even when nothing in the
/// workspace is running. Overrides `warnBeforeClosingWorkspace` for the
/// workspace prompts, the way pinning does for a single workspace.
public let alwaysConfirmWorkspaceClose = DefaultsKey<Bool>(
id: "app.alwaysConfirmWorkspaceClose",
defaultValue: false,
userDefaultsKey: "alwaysConfirmWorkspaceClose",
userFacing: UserFacingSettingDescriptor(
title: String(
localized: "settings.app.alwaysConfirmWorkspaceClose",
defaultValue: "Always Confirm Closing Workspaces"
),
section: .app,
searchID: "always-confirm-workspace-close",
searchKeywords: ["always", "close", "workspace", "confirmation", "idle", "protect"],
control: .toggle(.init(
commandPalette: .init(
id: "alwaysConfirmWorkspaceClose",
keywords: ["always", "confirm", "close", "workspace"]
)
))
)
)

/// Gates the "Close window?" prompts (the Close Window command, and closing
/// every workspace in a window at once).
public let warnBeforeClosingWindow = DefaultsKey<Bool>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Foundation
/// Repository for the close warning settings, persisted in `UserDefaults`
/// under the catalog's `app.warnBeforeClosingTab`,
/// `app.warnBeforeClosingTabXButton`, `app.warnBeforeClosingAgentSession`,
/// `app.warnBeforeClosingWorkspace`,
/// `app.warnBeforeClosingWorkspace`, `app.alwaysConfirmWorkspaceClose`,
/// `app.warnBeforeClosingWindow`, and
/// `app.hideTabCloseButton` keys.
///
Expand Down Expand Up @@ -59,6 +59,11 @@ public struct CloseTabWarningStore: CloseTabWarningReading {
keys.warnBeforeClosingWorkspace.value(in: defaults)
}

/// Whether every workspace close asks first, even when nothing is running.
public var alwaysConfirmsWorkspaceClose: Bool {
keys.alwaysConfirmWorkspaceClose.value(in: defaults)
}

/// Turns off the given warnings, for a dialog's "Don't ask again" checkbox.
public func disableWarnings(_ kinds: CloseWarningKinds) {
// An agent-session prompt owns its own suppression choice. Keep a
Expand All @@ -80,6 +85,9 @@ public struct CloseTabWarningStore: CloseTabWarningReading {
if kinds.contains(.workspace) {
keys.warnBeforeClosingWorkspace.set(false, in: defaults)
}
if kinds.contains(.alwaysConfirmWorkspace) {
keys.alwaysConfirmWorkspaceClose.set(false, in: defaults)
}
if kinds.contains(.window) {
keys.warnBeforeClosingWindow.set(false, in: defaults)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,7 @@ public struct CloseWarningKinds: OptionSet, Sendable, Hashable {

/// `app.warnBeforeClosingAgentSession`: an agent session that is mid-turn.
public static let agentSession = CloseWarningKinds(rawValue: 1 << 5)

/// `app.alwaysConfirmWorkspaceClose`: every workspace close, idle or not.
public static let alwaysConfirmWorkspace = CloseWarningKinds(rawValue: 1 << 6)
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ extension Array where Element == CuratedSettingEntry {
.init(userFacing: catalog.app.warnBeforeClosingAgentSession),
.init(section: .app, id: "warn-before-closing-tab-x-button", title: String(localized: "settings.app.warnBeforeClosingTabXButton", defaultValue: "Warn Before Tab Close Button"), synonyms: "Warn Before Tab Close Button app.warnBeforeClosingTabXButton x button close tab confirmation terminal surface"),
.init(userFacing: catalog.app.warnBeforeClosingWorkspace),
.init(userFacing: catalog.app.alwaysConfirmWorkspaceClose),
.init(userFacing: catalog.app.warnBeforeClosingWindow),
.init(userFacing: catalog.app.hideTabCloseButton),
.init(userFacing: catalog.app.renameSelectsExistingName),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public struct AppSection: View {
@State private var warnCloseAgentSession: DefaultsValueModel<Bool>
@State private var warnCloseX: DefaultsValueModel<Bool>
@State private var warnCloseWorkspace: DefaultsValueModel<Bool>
@State private var alwaysConfirmCloseWorkspace: DefaultsValueModel<Bool>
@State private var warnCloseWindow: DefaultsValueModel<Bool>
@State private var hideCloseButton: DefaultsValueModel<Bool>
@State private var renameSelects: DefaultsValueModel<Bool>
Expand Down Expand Up @@ -149,6 +150,7 @@ public struct AppSection: View {
_warnCloseAgentSession = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.app.warnBeforeClosingAgentSession))
_warnCloseX = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.app.warnBeforeClosingTabXButton))
_warnCloseWorkspace = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.app.warnBeforeClosingWorkspace))
_alwaysConfirmCloseWorkspace = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.app.alwaysConfirmWorkspaceClose))
_warnCloseWindow = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.app.warnBeforeClosingWindow))
_hideCloseButton = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.app.hideTabCloseButton))
_renameSelects = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.app.renameSelectsExistingName))
Expand All @@ -174,7 +176,7 @@ public struct AppSection: View {
mainCard
}
.task {
startSettingsObservation([language, appIcon, placement, inheritDir, minimalMode, keepWorkspaceOpen, firstClick, focusHistoryIncludesPanesAndTabs, equalizeSplitsOnCreate, fileDrop, preferredEditor, openSupported, openMarkdown, globalFontMagnification, markdownFontSize, markdownFontFamily, markdownMaxWidth, canvasPaneGap, canvasSnapping, fileEditorWordWrap, fileEditorSyntaxHighlighting, fileEditorLineNumbers, fileEditorIndentGuides, fileEditorCurrentLineHighlight, fileEditorTabWidth, iMessage, reorder, dockBadge, menuBarOnly, showInMenuBar, paneRing, paneFlash, paneFlashDoubleBlink, paneFlashOnTyping, paneFlashThemeColor, desktopNotifications, agentPermissionPrompt, agentTurnComplete, agentIdleReminder, soundName, soundWhenFocused, soundCommand, customSoundFile, soundOverrides, telemetry, confirmQuit, warnCloseTab, warnCloseAgentSession, warnCloseX, warnCloseWorkspace, warnCloseWindow, hideCloseButton, renameSelects, paletteAllSurfaces])
startSettingsObservation([language, appIcon, placement, inheritDir, minimalMode, keepWorkspaceOpen, firstClick, focusHistoryIncludesPanesAndTabs, equalizeSplitsOnCreate, fileDrop, preferredEditor, openSupported, openMarkdown, globalFontMagnification, markdownFontSize, markdownFontFamily, markdownMaxWidth, canvasPaneGap, canvasSnapping, fileEditorWordWrap, fileEditorSyntaxHighlighting, fileEditorLineNumbers, fileEditorIndentGuides, fileEditorCurrentLineHighlight, fileEditorTabWidth, iMessage, reorder, dockBadge, menuBarOnly, showInMenuBar, paneRing, paneFlash, paneFlashDoubleBlink, paneFlashOnTyping, paneFlashThemeColor, desktopNotifications, agentPermissionPrompt, agentTurnComplete, agentIdleReminder, soundName, soundWhenFocused, soundCommand, customSoundFile, soundOverrides, telemetry, confirmQuit, warnCloseTab, warnCloseAgentSession, warnCloseX, warnCloseWorkspace, alwaysConfirmCloseWorkspace, warnCloseWindow, hideCloseButton, renameSelects, paletteAllSurfaces])
await soundAgentCache.loadIfNeeded { await hostActions.notificationSoundAgentOptions() }
if languageAtAppear == nil { languageAtAppear = language.current }; if telemetryAtAppear == nil { telemetryAtAppear = telemetry.current }
}
Expand Down Expand Up @@ -954,6 +956,20 @@ public struct AppSection: View {
}
SettingsCardDivider()

// Always Confirm Closing Workspaces
SettingsCardRow(
configurationReview: .json(catalog.app.alwaysConfirmWorkspaceClose.id),
catalog.app.alwaysConfirmWorkspaceClose.userFacing!.title,
subtitle: alwaysConfirmCloseWorkspace.current
? String(localized: "settings.app.alwaysConfirmWorkspaceClose.subtitleOn", defaultValue: "Every workspace close asks first, even when nothing is running.")
: String(localized: "settings.app.alwaysConfirmWorkspaceClose.subtitleOff", defaultValue: "Idle workspaces close without asking. Turn on to protect long-lived workspaces.")
) {
Toggle("", isOn: Binding(get: { alwaysConfirmCloseWorkspace.current }, set: { alwaysConfirmCloseWorkspace.set($0) }))
.labelsHidden()
.controlSize(.small)
}
SettingsCardDivider()

// Warn Before Closing Window
SettingsCardRow(
configurationReview: .json(catalog.app.warnBeforeClosingWindow.id),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct SettingsRowAnchorResolutionTests {
"app.warnBeforeClosingTabXButton",
"app.warnBeforeClosingWindow",
"app.warnBeforeClosingWorkspace",
"app.alwaysConfirmWorkspaceClose",
"app.workspaceInheritWorkingDirectory",
"agentMessages.enabled",
"automation.agentAutoResume",
Expand Down
Loading
Loading