Skip to content
6 changes: 3 additions & 3 deletions .github/swift-file-length-budget.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# Format: max_lines<TAB>relative path
# Reduce counts as files shrink. CI fails if tracked files exceed this budget.
34475 CLI/cmux.swift
17572 Sources/AppDelegate.swift
17583 Sources/AppDelegate.swift
16578 Sources/ContentView.swift
14388 Sources/TerminalController.swift
14240 Sources/TerminalController.swift
12645 Sources/Workspace.swift
12613 Sources/Panels/BrowserPanel.swift
12115 cmuxTests/AppDelegateShortcutRoutingTests.swift
Expand All @@ -21,7 +21,7 @@
5925 cmuxTests/TerminalAndGhosttyTests.swift
5558 Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
5526 cmuxTests/BrowserConfigTests.swift
4921 Sources/cmuxApp.swift
4516 Sources/cmuxApp.swift
4467 Sources/Panels/FilePreviewPanel.swift
4401 cmuxTests/BrowserPanelTests.swift
4227 Sources/BrowserWindowPortal.swift
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#if canImport(AppKit)

import AppKit
public import Observation

/// Owns and sequences the About Titlebar Debug subsystem on behalf of the app.
///
/// The app composition root constructs one coordinator, injecting the
/// ``WindowDecorating`` seam, and forwards its existing call sites (the Debug
/// menu, the `About`/`Acknowledgments` window controllers, and "open all debug
/// windows") into this type. The coordinator owns the ``AboutTitlebarDebugStore``
/// and lazily owns the editor window controller, so the app target no longer
/// declares the underlying types.
@MainActor
@Observable
public final class DebugWindowsCoordinator {
/// The store backing the About Titlebar Debug options. Exposed so the app's
/// `About`/`Acknowledgments` window controllers can apply current options to
/// their windows as they build them.
public let aboutTitlebarStore: AboutTitlebarDebugStore

@ObservationIgnored
private weak var decorator: (any WindowDecorating)?

@ObservationIgnored
private var aboutTitlebarController: AboutTitlebarDebugWindowController?

/// Creates the coordinator.
///
/// - Parameter decorator: The window-decoration seam. Held weakly because the
/// app-side conformer (`AppDelegate`) is a singleton that also owns this
/// coordinator.
public init(decorator: (any WindowDecorating)?) {
self.decorator = decorator
self.aboutTitlebarStore = AboutTitlebarDebugStore(decorator: decorator)
}

/// Presents the About Titlebar Debug editor, creating its window on first use.
public func showAboutTitlebarDebugWindow() {
let controller = aboutTitlebarController ?? AboutTitlebarDebugWindowController(
store: aboutTitlebarStore,
decorator: decorator
)
aboutTitlebarController = controller
controller.show()
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#if canImport(AppKit)

public import AppKit

/// Applies the app's standard window chrome (background, blur, traffic-light
/// placement, and related decorations) to a freshly built or reconfigured
/// `NSWindow`.
///
/// This inverts the `AboutTitlebarDebug*` types' previous reach into
/// `AppDelegate.shared`: the app target's `AppDelegate` conforms and is injected
/// into ``DebugWindowsCoordinator`` at the composition root, so this package owns
/// no reference to the application delegate.
@MainActor
public protocol WindowDecorating: AnyObject {
/// Applies the standard cmux window decorations to `window`.
///
/// - Parameter window: The window whose chrome should be normalized.
func applyWindowDecorations(to window: NSWindow)
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#if canImport(AppKit)

public import AppKit
public import Observation

/// Holds the live ``AboutTitlebarDebugOptions`` for each ``AboutWindowKind`` and
/// applies them to matching open windows.
///
/// This is the single writer of the debug options. Editing ``aboutOptions``
/// (directly or via ``update(_:for:)``) immediately reapplies the new treatment
/// to any open window with the matching identifier, preserving the original
/// `didSet`-driven behavior. Window decoration is delegated to an injected
/// ``WindowDecorating`` seam rather than reaching into the app delegate.
@MainActor
@Observable
public final class AboutTitlebarDebugStore {
/// The current options for the About window. Setting this reapplies them to
/// every open About window.
public var aboutOptions = AboutTitlebarDebugOptions.defaults(for: .about) {
didSet { applyToOpenWindows(for: .about) }
}

@ObservationIgnored
private weak var decorator: (any WindowDecorating)?

/// Creates a store.
///
/// - Parameter decorator: The seam used to apply standard window chrome after
/// a debug option change. Held weakly because the app-side conformer
/// (`AppDelegate`) is a singleton that also owns this store, so a strong
/// reference would form a retain cycle.
public init(decorator: (any WindowDecorating)?) {
self.decorator = decorator
}

/// Returns the current options for a window kind.
public func options(for kind: AboutWindowKind) -> AboutTitlebarDebugOptions {
switch kind {
case .about:
return aboutOptions
}
}

/// Replaces the current options for a window kind.
public func update(_ newValue: AboutTitlebarDebugOptions, for kind: AboutWindowKind) {
switch kind {
case .about:
aboutOptions = newValue
}
}

/// Resets a window kind to its non-overriding defaults.
public func reset(_ kind: AboutWindowKind) {
update(AboutTitlebarDebugOptions.defaults(for: kind), for: kind)
}

/// Reapplies the current options to every open window of the given kind.
///
/// A nil `NSApp` (no running application, e.g. a headless unit-test process)
/// is a no-op; in the running app `NSApp` is always present, so this is
/// behavior-preserving.
public func applyToOpenWindows(for kind: AboutWindowKind) {
guard let app = NSApp else { return }
for window in app.windows where window.identifier?.rawValue == kind.windowIdentifier {
apply(options(for: kind), to: window, for: kind)
}
}

/// Reapplies the current options to every open About window.
public func applyToOpenWindows() {
applyToOpenWindows(for: .about)
}

/// Applies the current options for `kind` to a specific window. Used by the
/// About/Acknowledgments window controllers as they build their windows.
public func applyCurrentOptions(to window: NSWindow, for kind: AboutWindowKind) {
apply(options(for: kind), to: window, for: kind)
}

/// Builds the human-readable snapshot of the current About options. Pure (no
/// pasteboard side effect) so it is unit-testable without mutating the
/// process clipboard; `copyConfigToPasteboard()` is the side-effecting wrapper.
public func configSnapshot() -> String {
let about = options(for: .about)
return """
# About Titlebar Debug
about.overridesEnabled=\(about.overridesEnabled)
about.title=\(about.windowTitle)
about.titleVisibility=\(about.titleVisibility.rawValue)
about.titlebarAppearsTransparent=\(about.titlebarAppearsTransparent)
about.movableByWindowBackground=\(about.movableByWindowBackground)
about.titled=\(about.titled)
about.closable=\(about.closable)
about.miniaturizable=\(about.miniaturizable)
about.resizable=\(about.resizable)
about.fullSizeContentView=\(about.fullSizeContentView)
about.showToolbar=\(about.showToolbar)
about.toolbarStyle=\(about.toolbarStyle.rawValue)
"""
}

/// Copies a human-readable snapshot of the current About options to the
/// general pasteboard.
public func copyConfigToPasteboard() {
let pasteboard = NSPasteboard.general
pasteboard.clearContents()
pasteboard.setString(configSnapshot(), forType: .string)
}

private func apply(_ options: AboutTitlebarDebugOptions, to window: NSWindow, for kind: AboutWindowKind) {
let effective = options.overridesEnabled ? options : AboutTitlebarDebugOptions.defaults(for: kind)
let resolvedTitle = effective.windowTitle.trimmingCharacters(in: .whitespacesAndNewlines)
window.title = resolvedTitle.isEmpty ? kind.fallbackTitle : resolvedTitle
window.titleVisibility = effective.titleVisibility.windowValue
window.titlebarAppearsTransparent = effective.titlebarAppearsTransparent
window.isMovableByWindowBackground = effective.movableByWindowBackground
window.toolbarStyle = effective.toolbarStyle.windowValue

if effective.showToolbar {
ensureToolbar(on: window, kind: kind)
} else if window.toolbar != nil {
window.toolbar = nil
}

var styleMask = window.styleMask
setStyleMaskBit(&styleMask, .titled, enabled: effective.titled)
setStyleMaskBit(&styleMask, .closable, enabled: effective.closable)
setStyleMaskBit(&styleMask, .miniaturizable, enabled: effective.miniaturizable)
setStyleMaskBit(&styleMask, .resizable, enabled: effective.resizable)
setStyleMaskBit(&styleMask, .fullSizeContentView, enabled: effective.fullSizeContentView)
window.styleMask = styleMask

let maxSize = effective.resizable ? NSSize(width: 8192, height: 8192) : kind.minimumSize
window.minSize = kind.minimumSize
window.maxSize = maxSize
window.contentMinSize = kind.minimumSize
window.contentMaxSize = maxSize
window.invalidateShadow()
decorator?.applyWindowDecorations(to: window)
}

private func ensureToolbar(on window: NSWindow, kind: AboutWindowKind) {
guard window.toolbar == nil else { return }
let identifier = NSToolbar.Identifier("cmux.debug.titlebar.\(kind.rawValue)")
let toolbar = NSToolbar(identifier: identifier)
toolbar.allowsUserCustomization = false
toolbar.autosavesConfiguration = false
toolbar.displayMode = .iconOnly
toolbar.showsBaselineSeparator = false
window.toolbar = toolbar
}

private func setStyleMaskBit(
_ styleMask: inout NSWindow.StyleMask,
_ bit: NSWindow.StyleMask,
enabled: Bool
) {
if enabled {
styleMask.insert(bit)
} else {
styleMask.remove(bit)
}
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#if canImport(AppKit)

public import AppKit

/// A complete, editable description of the titlebar treatment applied to an
/// About-family window by the About Titlebar Debug subsystem.
///
/// When ``overridesEnabled`` is `false`, the store falls back to ``defaults(for:)``
/// so the window keeps its normal appearance; the remaining fields only take
/// effect once overrides are enabled.
public struct AboutTitlebarDebugOptions: Equatable, Sendable {
/// Whether the debug overrides in this value are applied at all.
public var overridesEnabled: Bool
/// The window title text (trimmed; empty falls back to the kind's title).
public var windowTitle: String
/// Whether the title text is shown or hidden.
public var titleVisibility: TitlebarVisibilityOption
/// Whether the titlebar background is transparent.
public var titlebarAppearsTransparent: Bool
/// Whether the window is draggable by its background.
public var movableByWindowBackground: Bool
/// Whether the `.titled` style-mask bit is set.
public var titled: Bool
/// Whether the `.closable` style-mask bit is set.
public var closable: Bool
/// Whether the `.miniaturizable` style-mask bit is set.
public var miniaturizable: Bool
/// Whether the `.resizable` style-mask bit is set.
public var resizable: Bool
/// Whether the `.fullSizeContentView` style-mask bit is set.
public var fullSizeContentView: Bool
/// Whether a toolbar is attached to the window.
public var showToolbar: Bool
/// The toolbar style applied when ``showToolbar`` is `true`.
public var toolbarStyle: TitlebarToolbarStyleOption

/// Creates an options value with every field specified.
public init(
overridesEnabled: Bool,
windowTitle: String,
titleVisibility: TitlebarVisibilityOption,
titlebarAppearsTransparent: Bool,
movableByWindowBackground: Bool,
titled: Bool,
closable: Bool,
miniaturizable: Bool,
resizable: Bool,
fullSizeContentView: Bool,
showToolbar: Bool,
toolbarStyle: TitlebarToolbarStyleOption
) {
self.overridesEnabled = overridesEnabled
self.windowTitle = windowTitle
self.titleVisibility = titleVisibility
self.titlebarAppearsTransparent = titlebarAppearsTransparent
self.movableByWindowBackground = movableByWindowBackground
self.titled = titled
self.closable = closable
self.miniaturizable = miniaturizable
self.resizable = resizable
self.fullSizeContentView = fullSizeContentView
self.showToolbar = showToolbar
self.toolbarStyle = toolbarStyle
}

/// The default, non-overriding options for a given window kind. This matches
/// the window's normal appearance, so applying it with overrides disabled is
/// a no-op relative to the system defaults.
public static func defaults(for kind: AboutWindowKind) -> AboutTitlebarDebugOptions {
switch kind {
case .about:
return AboutTitlebarDebugOptions(
overridesEnabled: false,
windowTitle: "About cmux",
titleVisibility: .hidden,
titlebarAppearsTransparent: true,
movableByWindowBackground: false,
titled: true,
closable: true,
miniaturizable: true,
resizable: false,
fullSizeContentView: false,
showToolbar: false,
toolbarStyle: .automatic
)
}
}
Comment on lines +69 to +87

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Localize the default window title.

The windowTitle default value in defaults(for:) uses a bare English string "About cmux" that becomes the displayed window title. This should use String(localized:defaultValue:) to match the localization requirement. Consider reusing the same key as AboutWindowKind.fallbackTitle for consistency.

🌐 Proposed localization fix
         case .about:
             return AboutTitlebarDebugOptions(
                 overridesEnabled: false,
-                windowTitle: "About cmux",
+                windowTitle: String(localized: "window.about.title", defaultValue: "About cmux"),
                 titleVisibility: .hidden,
🤖 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/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AboutTitlebarDebug/Values/AboutTitlebarDebugOptions.swift`
around lines 69 - 87, The windowTitle assignment in the defaults(for:) method of
AboutTitlebarDebugOptions uses a hardcoded English string "About cmux" instead
of a localized value. Replace this hardcoded string with
String(localized:defaultValue:) to enable proper localization, reusing the same
localization key as AboutWindowKind.fallbackTitle for consistency across the
codebase.

Source: Coding guidelines

}

#endif
Loading
Loading