diff --git a/CLAUDE.md b/CLAUDE.md index 2d1710c7..0c147fc9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,6 +16,14 @@ After making code changes, always run the reload script with a tag to launch the ./scripts/reload.sh --tag fix-zsh-autosuggestions ``` +When reporting a tagged reload result in chat, use this exact clickable format: + +```markdown +======================================================= +[: file:///tmp/cmux-.app](file:///tmp/cmux-.app) +======================================================= +``` + After making code changes, always run the build: ```bash diff --git a/Sources/ContentView.swift b/Sources/ContentView.swift index 944426a2..dd19fc85 100644 --- a/Sources/ContentView.swift +++ b/Sources/ContentView.swift @@ -5810,8 +5810,12 @@ struct VerticalTabsSidebar: View { enum SidebarCommandHintPolicy { static let intentionalHoldDelay: TimeInterval = 0.30 - static func shouldShowHints(for modifierFlags: NSEvent.ModifierFlags) -> Bool { - modifierFlags.intersection(.deviceIndependentFlagsMask) == [.command] + static func shouldShowHints( + for modifierFlags: NSEvent.ModifierFlags, + defaults: UserDefaults = .standard + ) -> Bool { + ShortcutHintDebugSettings.showHintsOnCommandHoldEnabled(defaults: defaults) && + modifierFlags.intersection(.deviceIndependentFlagsMask) == [.command] } static func isCurrentWindow( @@ -5832,9 +5836,10 @@ enum SidebarCommandHintPolicy { hostWindowNumber: Int?, hostWindowIsKey: Bool, eventWindowNumber: Int?, - keyWindowNumber: Int? + keyWindowNumber: Int?, + defaults: UserDefaults = .standard ) -> Bool { - shouldShowHints(for: modifierFlags) && + shouldShowHints(for: modifierFlags, defaults: defaults) && isCurrentWindow( hostWindowNumber: hostWindowNumber, hostWindowIsKey: hostWindowIsKey, @@ -5852,6 +5857,7 @@ enum ShortcutHintDebugSettings { static let paneHintXKey = "shortcutHintPaneTabXOffset" static let paneHintYKey = "shortcutHintPaneTabYOffset" static let alwaysShowHintsKey = "shortcutHintAlwaysShow" + static let showHintsOnCommandHoldKey = "shortcutHintShowOnCommandHold" static let defaultSidebarHintX = 0.0 static let defaultSidebarHintY = 0.0 @@ -5860,12 +5866,20 @@ enum ShortcutHintDebugSettings { static let defaultPaneHintX = 0.0 static let defaultPaneHintY = 0.0 static let defaultAlwaysShowHints = false + static let defaultShowHintsOnCommandHold = true static let offsetRange: ClosedRange = -20...20 static func clamped(_ value: Double) -> Double { min(max(value, offsetRange.lowerBound), offsetRange.upperBound) } + + static func showHintsOnCommandHoldEnabled(defaults: UserDefaults = .standard) -> Bool { + guard defaults.object(forKey: showHintsOnCommandHoldKey) != nil else { + return defaultShowHintsOnCommandHold + } + return defaults.bool(forKey: showHintsOnCommandHoldKey) + } } enum SidebarDragLifecycleNotification { diff --git a/Sources/cmuxApp.swift b/Sources/cmuxApp.swift index 9936536a..4f7cea7d 100644 --- a/Sources/cmuxApp.swift +++ b/Sources/cmuxApp.swift @@ -1313,6 +1313,7 @@ private enum DebugWindowConfigSnapshot { shortcutHintPaneTabXOffset=\(String(format: "%.1f", doubleValue(defaults, key: ShortcutHintDebugSettings.paneHintXKey, fallback: ShortcutHintDebugSettings.defaultPaneHintX))) shortcutHintPaneTabYOffset=\(String(format: "%.1f", doubleValue(defaults, key: ShortcutHintDebugSettings.paneHintYKey, fallback: ShortcutHintDebugSettings.defaultPaneHintY))) shortcutHintAlwaysShow=\(boolValue(defaults, key: ShortcutHintDebugSettings.alwaysShowHintsKey, fallback: ShortcutHintDebugSettings.defaultAlwaysShowHints)) + shortcutHintShowOnCommandHold=\(boolValue(defaults, key: ShortcutHintDebugSettings.showHintsOnCommandHoldKey, fallback: ShortcutHintDebugSettings.defaultShowHintsOnCommandHold)) """ let backgroundPayload = """ @@ -2746,6 +2747,8 @@ struct SettingsView: View { @AppStorage("sidebarShowPullRequest") private var sidebarShowPullRequest = true @AppStorage(BrowserLinkOpenSettings.openSidebarPullRequestLinksInCmuxBrowserKey) private var openSidebarPullRequestLinksInCmuxBrowser = BrowserLinkOpenSettings.defaultOpenSidebarPullRequestLinksInCmuxBrowser + @AppStorage(ShortcutHintDebugSettings.showHintsOnCommandHoldKey) + private var showShortcutHintsOnCommandHold = ShortcutHintDebugSettings.defaultShowHintsOnCommandHold @AppStorage("sidebarShowPorts") private var sidebarShowPorts = true @AppStorage("sidebarShowLog") private var sidebarShowLog = true @AppStorage("sidebarShowProgress") private var sidebarShowProgress = true @@ -3460,6 +3463,19 @@ struct SettingsView: View { SettingsSectionHeader(title: "Keyboard Shortcuts") SettingsCard { + SettingsCardRow( + "Show Cmd/Ctrl-Hold Shortcut Hints", + subtitle: showShortcutHintsOnCommandHold + ? "Holding Cmd (sidebar/titlebar) or Ctrl/Cmd (pane tabs) shows shortcut hint pills." + : "Holding Cmd or Ctrl keeps shortcut hint pills hidden." + ) { + Toggle("", isOn: $showShortcutHintsOnCommandHold) + .labelsHidden() + .controlSize(.small) + } + + SettingsCardDivider() + let actions = KeyboardShortcutSettings.Action.allCases ForEach(Array(actions.enumerated()), id: \.element.id) { index, action in ShortcutSettingRow(action: action) @@ -3642,6 +3658,7 @@ struct SettingsView: View { sidebarShowBranchDirectory = true sidebarShowPullRequest = true openSidebarPullRequestLinksInCmuxBrowser = BrowserLinkOpenSettings.defaultOpenSidebarPullRequestLinksInCmuxBrowser + showShortcutHintsOnCommandHold = ShortcutHintDebugSettings.defaultShowHintsOnCommandHold sidebarShowPorts = true sidebarShowLog = true sidebarShowProgress = true diff --git a/cmuxTests/CmuxWebViewKeyEquivalentTests.swift b/cmuxTests/CmuxWebViewKeyEquivalentTests.swift index d116a4e9..3e0d1c72 100644 --- a/cmuxTests/CmuxWebViewKeyEquivalentTests.swift +++ b/cmuxTests/CmuxWebViewKeyEquivalentTests.swift @@ -2554,11 +2554,31 @@ final class CommandPaletteSelectionScrollBehaviorTests: XCTestCase { final class SidebarCommandHintPolicyTests: XCTestCase { func testCommandHintRequiresCommandOnlyModifier() { - XCTAssertTrue(SidebarCommandHintPolicy.shouldShowHints(for: [.command])) - XCTAssertFalse(SidebarCommandHintPolicy.shouldShowHints(for: [])) - XCTAssertFalse(SidebarCommandHintPolicy.shouldShowHints(for: [.command, .shift])) - XCTAssertFalse(SidebarCommandHintPolicy.shouldShowHints(for: [.command, .option])) - XCTAssertFalse(SidebarCommandHintPolicy.shouldShowHints(for: [.command, .control])) + withDefaultsSuite { defaults in + defaults.set(true, forKey: ShortcutHintDebugSettings.showHintsOnCommandHoldKey) + + XCTAssertTrue(SidebarCommandHintPolicy.shouldShowHints(for: [.command], defaults: defaults)) + XCTAssertFalse(SidebarCommandHintPolicy.shouldShowHints(for: [], defaults: defaults)) + XCTAssertFalse(SidebarCommandHintPolicy.shouldShowHints(for: [.command, .shift], defaults: defaults)) + XCTAssertFalse(SidebarCommandHintPolicy.shouldShowHints(for: [.command, .option], defaults: defaults)) + XCTAssertFalse(SidebarCommandHintPolicy.shouldShowHints(for: [.command, .control], defaults: defaults)) + } + } + + func testCommandHintCanBeDisabledInSettings() { + withDefaultsSuite { defaults in + defaults.set(false, forKey: ShortcutHintDebugSettings.showHintsOnCommandHoldKey) + + XCTAssertFalse(SidebarCommandHintPolicy.shouldShowHints(for: [.command], defaults: defaults)) + } + } + + func testCommandHintDefaultsToEnabledWhenSettingMissing() { + withDefaultsSuite { defaults in + defaults.removeObject(forKey: ShortcutHintDebugSettings.showHintsOnCommandHoldKey) + + XCTAssertTrue(SidebarCommandHintPolicy.shouldShowHints(for: [.command], defaults: defaults)) + } } func testCommandHintUsesIntentionalHoldDelay() { @@ -2595,25 +2615,43 @@ final class SidebarCommandHintPolicyTests: XCTestCase { } func testWindowScopedCommandHintsUseKeyWindowWhenNoEventWindowIsAvailable() { - XCTAssertTrue( - SidebarCommandHintPolicy.shouldShowHints( - for: [.command], - hostWindowNumber: 42, - hostWindowIsKey: true, - eventWindowNumber: nil, - keyWindowNumber: 42 - ) - ) + withDefaultsSuite { defaults in + defaults.set(true, forKey: ShortcutHintDebugSettings.showHintsOnCommandHoldKey) - XCTAssertFalse( - SidebarCommandHintPolicy.shouldShowHints( - for: [.command], - hostWindowNumber: 42, - hostWindowIsKey: true, - eventWindowNumber: nil, - keyWindowNumber: 7 + XCTAssertTrue( + SidebarCommandHintPolicy.shouldShowHints( + for: [.command], + hostWindowNumber: 42, + hostWindowIsKey: true, + eventWindowNumber: nil, + keyWindowNumber: 42, + defaults: defaults + ) ) - ) + + XCTAssertFalse( + SidebarCommandHintPolicy.shouldShowHints( + for: [.command], + hostWindowNumber: 42, + hostWindowIsKey: true, + eventWindowNumber: nil, + keyWindowNumber: 7, + defaults: defaults + ) + ) + } + } + + private func withDefaultsSuite(_ body: (UserDefaults) -> Void) { + let suiteName = "SidebarCommandHintPolicyTests-\(UUID().uuidString)" + guard let defaults = UserDefaults(suiteName: suiteName) else { + XCTFail("Failed to create defaults suite") + return + } + + defaults.removePersistentDomain(forName: suiteName) + body(defaults) + defaults.removePersistentDomain(forName: suiteName) } } @@ -2633,6 +2671,27 @@ final class ShortcutHintDebugSettingsTests: XCTestCase { XCTAssertEqual(ShortcutHintDebugSettings.defaultPaneHintX, 0.0) XCTAssertEqual(ShortcutHintDebugSettings.defaultPaneHintY, 0.0) XCTAssertFalse(ShortcutHintDebugSettings.defaultAlwaysShowHints) + XCTAssertTrue(ShortcutHintDebugSettings.defaultShowHintsOnCommandHold) + } + + func testShowHintsOnCommandHoldSettingRespectsStoredValue() { + let suiteName = "ShortcutHintDebugSettingsTests-\(UUID().uuidString)" + guard let defaults = UserDefaults(suiteName: suiteName) else { + XCTFail("Failed to create defaults suite") + return + } + + defaults.removePersistentDomain(forName: suiteName) + defer { defaults.removePersistentDomain(forName: suiteName) } + + defaults.removeObject(forKey: ShortcutHintDebugSettings.showHintsOnCommandHoldKey) + XCTAssertTrue(ShortcutHintDebugSettings.showHintsOnCommandHoldEnabled(defaults: defaults)) + + defaults.set(false, forKey: ShortcutHintDebugSettings.showHintsOnCommandHoldKey) + XCTAssertFalse(ShortcutHintDebugSettings.showHintsOnCommandHoldEnabled(defaults: defaults)) + + defaults.set(true, forKey: ShortcutHintDebugSettings.showHintsOnCommandHoldKey) + XCTAssertTrue(ShortcutHintDebugSettings.showHintsOnCommandHoldEnabled(defaults: defaults)) } } diff --git a/vendor/bonsplit b/vendor/bonsplit index 335facd9..89a4fd12 160000 --- a/vendor/bonsplit +++ b/vendor/bonsplit @@ -1 +1 @@ -Subproject commit 335facd9fd1d81a3c71fea69345af30f7e3601f9 +Subproject commit 89a4fd1288a706ae4b766f323191d6570b7123aa