Use command palette flow for workspace rename shortcut

This commit is contained in:
Lawrence Chen 2026-02-25 05:12:49 -08:00
parent 2202b6081c
commit 62fffc7221
5 changed files with 89 additions and 3 deletions

View file

@ -4560,8 +4560,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
}
if matchShortcut(event: event, shortcut: KeyboardShortcutSettings.shortcut(for: .renameWorkspace)) {
_ = promptRenameSelectedWorkspace()
return true
return requestRenameWorkspaceViaCommandPalette(
preferredWindow: commandPaletteTargetWindow ?? event.window ?? NSApp.keyWindow ?? NSApp.mainWindow
)
}
if normalizedFlags == [.command, .option], (chars == "t" || event.keyCode == 17) {
@ -5248,6 +5249,13 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
handleCustomShortcut(event: event)
}
@discardableResult
func requestRenameWorkspaceViaCommandPalette(preferredWindow: NSWindow? = nil) -> Bool {
let targetWindow = preferredWindow ?? NSApp.keyWindow ?? NSApp.mainWindow
NotificationCenter.default.post(name: .commandPaletteRenameWorkspaceRequested, object: targetWindow)
return true
}
#if DEBUG
// Debug/test hook: allow socket-driven shortcut simulation to reuse the same shortcut routing
// logic as the local NSEvent monitor, without relying on AppKit event monitor behavior for

View file

@ -2213,6 +2213,17 @@ struct ContentView: View {
openCommandPaletteRenameTabInput()
})
view = AnyView(view.onReceive(NotificationCenter.default.publisher(for: .commandPaletteRenameWorkspaceRequested)) { notification in
let requestedWindow = notification.object as? NSWindow
guard Self.shouldHandleCommandPaletteRequest(
observedWindow: observedWindow,
requestedWindow: requestedWindow,
keyWindow: NSApp.keyWindow,
mainWindow: NSApp.mainWindow
) else { return }
openCommandPaletteRenameWorkspaceInput()
})
view = AnyView(view.onReceive(NotificationCenter.default.publisher(for: .commandPaletteMoveSelection)) { notification in
guard isCommandPalettePresented else { return }
guard case .commands = commandPaletteMode else { return }
@ -4327,6 +4338,13 @@ struct ContentView: View {
beginRenameTabFlow()
}
private func openCommandPaletteRenameWorkspaceInput() {
if !isCommandPalettePresented {
presentCommandPalette(initialQuery: Self.commandPaletteCommandsPrefix)
}
beginRenameWorkspaceFlow()
}
static func shouldHandleCommandPaletteRequest(
observedWindow: NSWindow?,
requestedWindow: NSWindow?,

View file

@ -3414,6 +3414,7 @@ extension Notification.Name {
static let commandPaletteRequested = Notification.Name("cmux.commandPaletteRequested")
static let commandPaletteSwitcherRequested = Notification.Name("cmux.commandPaletteSwitcherRequested")
static let commandPaletteRenameTabRequested = Notification.Name("cmux.commandPaletteRenameTabRequested")
static let commandPaletteRenameWorkspaceRequested = Notification.Name("cmux.commandPaletteRenameWorkspaceRequested")
static let commandPaletteMoveSelection = Notification.Name("cmux.commandPaletteMoveSelection")
static let commandPaletteRenameInputInteractionRequested = Notification.Name("cmux.commandPaletteRenameInputInteractionRequested")
static let commandPaletteRenameInputDeleteBackwardRequested = Notification.Name("cmux.commandPaletteRenameInputDeleteBackwardRequested")

View file

@ -538,7 +538,7 @@ struct cmuxApp: App {
}
splitCommandButton(title: "Rename Workspace…", shortcut: renameWorkspaceMenuShortcut) {
_ = AppDelegate.shared?.promptRenameSelectedWorkspace()
_ = AppDelegate.shared?.requestRenameWorkspaceViaCommandPalette()
}
Divider()

View file

@ -311,6 +311,65 @@ final class AppDelegateShortcutRoutingTests: XCTestCase {
XCTAssertTrue(appDelegate.tabManager === secondManager, "Shortcut routing should retarget active manager to event window")
}
func testCmdShiftRRequestsRenameWorkspaceInCommandPalette() {
guard let appDelegate = AppDelegate.shared else {
XCTFail("Expected AppDelegate.shared")
return
}
let windowId = appDelegate.createMainWindow()
defer {
closeWindow(withId: windowId)
}
guard let window = window(withId: windowId) else {
XCTFail("Expected test window")
return
}
let workspaceExpectation = expectation(description: "Expected command palette rename workspace notification")
var observedWorkspaceWindow: NSWindow?
let workspaceToken = NotificationCenter.default.addObserver(
forName: .commandPaletteRenameWorkspaceRequested,
object: nil,
queue: nil
) { notification in
observedWorkspaceWindow = notification.object as? NSWindow
workspaceExpectation.fulfill()
}
defer { NotificationCenter.default.removeObserver(workspaceToken) }
let renameTabExpectation = expectation(description: "Rename tab notification should not fire for Cmd+Shift+R")
renameTabExpectation.isInverted = true
let renameTabToken = NotificationCenter.default.addObserver(
forName: .commandPaletteRenameTabRequested,
object: nil,
queue: nil
) { _ in
renameTabExpectation.fulfill()
}
defer { NotificationCenter.default.removeObserver(renameTabToken) }
guard let event = makeKeyDownEvent(
key: "r",
modifiers: [.command, .shift],
keyCode: 15, // kVK_ANSI_R
windowNumber: window.windowNumber
) else {
XCTFail("Failed to construct Cmd+Shift+R event")
return
}
#if DEBUG
XCTAssertTrue(appDelegate.debugHandleCustomShortcut(event: event))
#else
XCTFail("debugHandleCustomShortcut is only available in DEBUG")
#endif
wait(for: [workspaceExpectation, renameTabExpectation], timeout: 1.0)
XCTAssertEqual(observedWorkspaceWindow?.windowNumber, window.windowNumber)
}
func testCmdDigitDoesNotFallbackToOtherWindowWhenEventWindowContextIsMissing() {
guard let appDelegate = AppDelegate.shared else {
XCTFail("Expected AppDelegate.shared")