diff --git a/CLAUDE.md b/CLAUDE.md index fe961481..0c2d8156 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -141,6 +141,14 @@ When adding a regression test for a bug fix, use a two-commit structure so CI pr This makes it visible in the GitHub PR UI (Commits tab, check statuses) that the test genuinely fails without the fix. +## Debug menu + +The app has a **Debug** menu in the macOS menu bar (only in DEBUG builds). Use it for visual iteration: + +- **Debug > Debug Windows** contains panels for tuning layout, colors, and behavior. Entries are alphabetical with no dividers. +- To add a debug toggle or visual option: create an `NSWindowController` subclass with a `shared` singleton, add it to the "Debug Windows" menu in `Sources/cmuxApp.swift`, and add a SwiftUI view with `@AppStorage` bindings for live changes. +- When the user says "debug menu" or "debug window", they mean this menu, not `defaults write`. + ## Pitfalls - **Custom UTTypes** for drag-and-drop must be declared in `Resources/Info.plist` under `UTExportedTypeDeclarations` (e.g. `com.splittabbar.tabtransfer`, `com.cmux.sidebar-tab-reorder`). diff --git a/Sources/cmuxApp.swift b/Sources/cmuxApp.swift index 8ba0d97d..8dffff53 100644 --- a/Sources/cmuxApp.swift +++ b/Sources/cmuxApp.swift @@ -474,14 +474,12 @@ struct cmuxApp: App { Divider() Menu("Debug Windows") { - Button("Debug Window Controls…") { - DebugWindowControlsWindowController.shared.show() + Button("Background Debug…") { + BackgroundDebugWindowController.shared.show() } - Button("Browser Import Hint Debug…") { BrowserImportHintDebugWindowController.shared.show() } - Button( String( localized: "debug.menu.browserProfilePopoverDebug", @@ -490,26 +488,21 @@ struct cmuxApp: App { ) { BrowserProfilePopoverDebugWindowController.shared.show() } - - Button("Settings/About Titlebar Debug…") { - SettingsAboutTitlebarDebugWindowController.shared.show() + Button("Debug Window Controls…") { + DebugWindowControlsWindowController.shared.show() } - - Divider() - Button("Sidebar Debug…") { - SidebarDebugWindowController.shared.show() - } - - Button("Background Debug…") { - BackgroundDebugWindowController.shared.show() - } - Button("Menu Bar Extra Debug…") { MenuBarExtraDebugWindowController.shared.show() } - - Divider() - + Button("Settings/About Titlebar Debug…") { + SettingsAboutTitlebarDebugWindowController.shared.show() + } + Button("Sidebar Debug…") { + SidebarDebugWindowController.shared.show() + } + Button("Split Button Layout Debug…") { + SplitButtonLayoutDebugWindowController.shared.show() + } Button("Open All Debug Windows") { openAllDebugWindows() } @@ -3337,6 +3330,76 @@ private struct MenuBarExtraDebugView: View { } } +// MARK: - Split Button Layout Debug Window + +private final class SplitButtonLayoutDebugWindowController: NSWindowController, NSWindowDelegate { + static let shared = SplitButtonLayoutDebugWindowController() + + private init() { + let window = NSPanel( + contentRect: NSRect(x: 0, y: 0, width: 320, height: 240), + styleMask: [.titled, .closable, .utilityWindow], + backing: .buffered, + defer: false + ) + window.title = "Split Button Layout" + window.titleVisibility = .visible + window.titlebarAppearsTransparent = false + window.isMovableByWindowBackground = true + window.isReleasedWhenClosed = false + window.identifier = NSUserInterfaceItemIdentifier("cmux.splitButtonLayoutDebug") + window.center() + window.contentView = NSHostingView(rootView: SplitButtonLayoutDebugView()) + AppDelegate.shared?.applyWindowDecorations(to: window) + super.init(window: window) + window.delegate = self + } + + @available(*, unavailable) + required init?(coder: NSCoder) { fatalError() } + + func show() { + window?.center() + window?.makeKeyAndOrderFront(nil) + } +} + +private struct SplitButtonLayoutDebugView: View { + @AppStorage("debugFadeColorStyle") private var backdropStyle = 0 + + private let options: [(Int, String)] = [ + (0, "Pre-composited paneBackground"), + (1, "Raw paneBackground (opaque)"), + (2, "barBackground (tab chrome)"), + (3, "windowBackgroundColor"), + (4, "controlBackgroundColor"), + (5, "Pre-composited barBackground"), + ] + + var body: some View { + VStack(alignment: .leading, spacing: 10) { + Text("Button Backdrop Color") + .font(.headline) + + ForEach(options, id: \.0) { id, label in + HStack { + Image(systemName: backdropStyle == id ? "checkmark.circle.fill" : "circle") + .foregroundColor(backdropStyle == id ? .accentColor : .secondary) + Text(label) + } + .contentShape(Rectangle()) + .onTapGesture { backdropStyle = id } + } + + Text("Changes apply live.") + .font(.caption) + .foregroundColor(.secondary) + } + .padding(16) + .frame(maxWidth: .infinity, alignment: .topLeading) + } +} + // MARK: - Background Debug Window private final class BackgroundDebugWindowController: NSWindowController, NSWindowDelegate { diff --git a/vendor/bonsplit b/vendor/bonsplit index 447ac42b..aff9f707 160000 --- a/vendor/bonsplit +++ b/vendor/bonsplit @@ -1 +1 @@ -Subproject commit 447ac42b45256bdf333659d2dbe955afcaa87f6b +Subproject commit aff9f7073125d412fed07bce1adab0e78f907b14