From 835fe3dd0fce241bc249ebc9e7a33b78d0ffe32e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 17 Dec 2025 09:17:09 -0800 Subject: [PATCH] macos: add the active terminals to our command palette to jump --- .../TerminalCommandPalette.swift | 29 +++++++++++++++++++ .../Terminal/BaseTerminalController.swift | 9 ++++-- .../Helpers/Extensions/String+Extension.swift | 9 ++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/macos/Sources/Features/Command Palette/TerminalCommandPalette.swift b/macos/Sources/Features/Command Palette/TerminalCommandPalette.swift index 8150dbdbb..e3da9ff56 100644 --- a/macos/Sources/Features/Command Palette/TerminalCommandPalette.swift +++ b/macos/Sources/Features/Command Palette/TerminalCommandPalette.swift @@ -64,6 +64,7 @@ struct TerminalCommandPaletteView: View { private var commandOptions: [CommandOption] { var options: [CommandOption] = [] options.append(contentsOf: updateOptions) + options.append(contentsOf: jumpOptions) options.append(contentsOf: terminalOptions) return options } @@ -122,6 +123,34 @@ struct TerminalCommandPaletteView: View { return [] } } + + /// Commands for jumping to other terminal surfaces. + private var jumpOptions: [CommandOption] { + TerminalController.all.flatMap { controller -> [CommandOption] in + guard let window = controller.window else { return [] } + + let color = (window as? TerminalWindow)?.tabColor + let displayColor = color != TerminalTabColor.none ? color : nil + + return controller.surfaceTree.map { surface in + let title = surface.title.isEmpty ? window.title : surface.title + let displayTitle = title.isEmpty ? "Untitled" : title + + return CommandOption( + title: "Focus: \(displayTitle)", + description: surface.pwd?.abbreviatedPath, + leadingIcon: "rectangle.on.rectangle", + leadingColor: displayColor?.displayColor.map { Color($0) } + ) { + NotificationCenter.default.post( + name: Ghostty.Notification.ghosttyPresentTerminal, + object: surface + ) + } + } + } + } + } /// This is done to ensure that the given view is in the responder chain. diff --git a/macos/Sources/Features/Terminal/BaseTerminalController.swift b/macos/Sources/Features/Terminal/BaseTerminalController.swift index b70fd2c56..9e8aece2d 100644 --- a/macos/Sources/Features/Terminal/BaseTerminalController.swift +++ b/macos/Sources/Features/Terminal/BaseTerminalController.swift @@ -709,9 +709,12 @@ class BaseTerminalController: NSWindowController, guard let target = notification.object as? Ghostty.SurfaceView else { return } guard surfaceTree.contains(target) else { return } - // Bring the window to front and focus the surface without activating the app - window?.orderFrontRegardless() - Ghostty.moveFocus(to: target) + // Bring the window to front and focus the surface. + window?.makeKeyAndOrderFront(nil) + + // We use a small delay to ensure this runs after any UI cleanup + // (e.g., command palette restoring focus to its original surface). + Ghostty.moveFocus(to: target, delay: 0.1) } // MARK: Local Events diff --git a/macos/Sources/Helpers/Extensions/String+Extension.swift b/macos/Sources/Helpers/Extensions/String+Extension.swift index 0c1c4fe91..a8d93091a 100644 --- a/macos/Sources/Helpers/Extensions/String+Extension.swift +++ b/macos/Sources/Helpers/Extensions/String+Extension.swift @@ -17,4 +17,13 @@ extension String { return url } #endif + + /// Returns the path with the home directory abbreviated as ~. + var abbreviatedPath: String { + let home = FileManager.default.homeDirectoryForCurrentUser.path + if hasPrefix(home) { + return "~" + dropFirst(home.count) + } + return self + } }