add toggle command palette binding

This commit is contained in:
Mitchell Hashimoto
2025-04-21 09:52:21 -07:00
parent 8bd91e7104
commit 6d2685b5a2
14 changed files with 84 additions and 12 deletions

View File

@ -579,6 +579,7 @@ typedef enum {
GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW, GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW,
GHOSTTY_ACTION_TOGGLE_WINDOW_DECORATIONS, GHOSTTY_ACTION_TOGGLE_WINDOW_DECORATIONS,
GHOSTTY_ACTION_TOGGLE_QUICK_TERMINAL, GHOSTTY_ACTION_TOGGLE_QUICK_TERMINAL,
GHOSTTY_ACTION_TOGGLE_COMMAND_PALETTE,
GHOSTTY_ACTION_TOGGLE_VISIBILITY, GHOSTTY_ACTION_TOGGLE_VISIBILITY,
GHOSTTY_ACTION_MOVE_TAB, GHOSTTY_ACTION_MOVE_TAB,
GHOSTTY_ACTION_GOTO_TAB, GHOSTTY_ACTION_GOTO_TAB,

View File

@ -59,6 +59,7 @@ class AppDelegate: NSObject,
@IBOutlet private var menuChangeTitle: NSMenuItem? @IBOutlet private var menuChangeTitle: NSMenuItem?
@IBOutlet private var menuQuickTerminal: NSMenuItem? @IBOutlet private var menuQuickTerminal: NSMenuItem?
@IBOutlet private var menuTerminalInspector: NSMenuItem? @IBOutlet private var menuTerminalInspector: NSMenuItem?
@IBOutlet private var menuCommandPalette: NSMenuItem?
@IBOutlet private var menuEqualizeSplits: NSMenuItem? @IBOutlet private var menuEqualizeSplits: NSMenuItem?
@IBOutlet private var menuMoveSplitDividerUp: NSMenuItem? @IBOutlet private var menuMoveSplitDividerUp: NSMenuItem?
@ -402,6 +403,7 @@ class AppDelegate: NSObject,
syncMenuShortcut(config, action: "toggle_quick_terminal", menuItem: self.menuQuickTerminal) syncMenuShortcut(config, action: "toggle_quick_terminal", menuItem: self.menuQuickTerminal)
syncMenuShortcut(config, action: "toggle_visibility", menuItem: self.menuToggleVisibility) syncMenuShortcut(config, action: "toggle_visibility", menuItem: self.menuToggleVisibility)
syncMenuShortcut(config, action: "inspector:toggle", menuItem: self.menuTerminalInspector) syncMenuShortcut(config, action: "inspector:toggle", menuItem: self.menuTerminalInspector)
syncMenuShortcut(config, action: "toggle_command_palette", menuItem: self.menuCommandPalette)
syncMenuShortcut(config, action: "toggle_secure_input", menuItem: self.menuSecureInput) syncMenuShortcut(config, action: "toggle_secure_input", menuItem: self.menuSecureInput)

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23727" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23504"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23727"/>
</dependencies> </dependencies>
<objects> <objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication"> <customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@ -21,6 +21,7 @@
<outlet property="menuCloseAllWindows" destination="yKr-Vi-Yqw" id="Zet-Ir-zbm"/> <outlet property="menuCloseAllWindows" destination="yKr-Vi-Yqw" id="Zet-Ir-zbm"/>
<outlet property="menuCloseTab" destination="Obb-Mk-j8J" id="Gda-L0-gdz"/> <outlet property="menuCloseTab" destination="Obb-Mk-j8J" id="Gda-L0-gdz"/>
<outlet property="menuCloseWindow" destination="W5w-UZ-crk" id="6ff-BT-ENV"/> <outlet property="menuCloseWindow" destination="W5w-UZ-crk" id="6ff-BT-ENV"/>
<outlet property="menuCommandPalette" destination="et6-de-Mh7" id="53t-cu-dm5"/>
<outlet property="menuCopy" destination="Jqf-pv-Zcu" id="bKd-1C-oy9"/> <outlet property="menuCopy" destination="Jqf-pv-Zcu" id="bKd-1C-oy9"/>
<outlet property="menuDecreaseFontSize" destination="kzb-SZ-dOA" id="Y1B-Vh-6Z2"/> <outlet property="menuDecreaseFontSize" destination="kzb-SZ-dOA" id="Y1B-Vh-6Z2"/>
<outlet property="menuEqualizeSplits" destination="3gH-VD-vL9" id="SiZ-ce-FOF"/> <outlet property="menuEqualizeSplits" destination="3gH-VD-vL9" id="SiZ-ce-FOF"/>
@ -249,6 +250,12 @@
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="L3L-I8-sqk"/> <menuItem isSeparatorItem="YES" id="L3L-I8-sqk"/>
<menuItem title="Command Palette" id="et6-de-Mh7">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleCommandPalette:" target="-1" id="FcT-XD-gM1"/>
</connections>
</menuItem>
<menuItem title="Change Title..." id="24I-xg-qIq"> <menuItem title="Change Title..." id="24I-xg-qIq">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>

View File

@ -110,6 +110,11 @@ class BaseTerminalController: NSWindowController,
selector: #selector(ghosttyConfigDidChangeBase(_:)), selector: #selector(ghosttyConfigDidChangeBase(_:)),
name: .ghosttyConfigDidChange, name: .ghosttyConfigDidChange,
object: nil) object: nil)
center.addObserver(
self,
selector: #selector(ghosttyCommandPaletteDidToggle(_:)),
name: .ghosttyCommandPaletteDidToggle,
object: nil)
// Listen for local events that we need to know of outside of // Listen for local events that we need to know of outside of
// single surface handlers. // single surface handlers.
@ -222,6 +227,12 @@ class BaseTerminalController: NSWindowController,
self.derivedConfig = DerivedConfig(config) self.derivedConfig = DerivedConfig(config)
} }
@objc private func ghosttyCommandPaletteDidToggle(_ notification: Notification) {
guard let surfaceView = notification.object as? Ghostty.SurfaceView else { return }
guard surfaceTree?.contains(view: surfaceView) ?? false else { return }
toggleCommandPalette(nil)
}
// MARK: Local Events // MARK: Local Events
private func localEventHandler(_ event: NSEvent) -> NSEvent? { private func localEventHandler(_ event: NSEvent) -> NSEvent? {
@ -631,6 +642,10 @@ class BaseTerminalController: NSWindowController,
ghostty.changeFontSize(surface: surface, .reset) ghostty.changeFontSize(surface: surface, .reset)
} }
@IBAction func toggleCommandPalette(_ sender: Any?) {
commandPaletteIsShowing.toggle()
}
@objc func resetTerminal(_ sender: Any) { @objc func resetTerminal(_ sender: Any) {
guard let surface = focusedSurface?.surface else { return } guard let surface = focusedSurface?.surface else { return }
ghostty.resetTerminal(surface: surface) ghostty.resetTerminal(surface: surface)

View File

@ -93,16 +93,6 @@ struct TerminalView<ViewModel: TerminalViewModel>: View {
DebugBuildWarningView() DebugBuildWarningView()
} }
HStack {
Spacer()
Button("Command Palette") {
viewModel.commandPaletteIsShowing.toggle()
}
Spacer()
}
.background(Color(.windowBackgroundColor))
.frame(maxWidth: .infinity)
Ghostty.TerminalSplit(node: $viewModel.surfaceTree) Ghostty.TerminalSplit(node: $viewModel.surfaceTree)
.environmentObject(ghostty) .environmentObject(ghostty)
.focused($focused) .focused($focused)

View File

@ -520,6 +520,9 @@ extension Ghostty {
case GHOSTTY_ACTION_RENDERER_HEALTH: case GHOSTTY_ACTION_RENDERER_HEALTH:
rendererHealth(app, target: target, v: action.action.renderer_health) rendererHealth(app, target: target, v: action.action.renderer_health)
case GHOSTTY_ACTION_TOGGLE_COMMAND_PALETTE:
toggleCommandPalette(app, target: target)
case GHOSTTY_ACTION_TOGGLE_QUICK_TERMINAL: case GHOSTTY_ACTION_TOGGLE_QUICK_TERMINAL:
toggleQuickTerminal(app, target: target) toggleQuickTerminal(app, target: target)
@ -742,6 +745,28 @@ extension Ghostty {
} }
} }
private static func toggleCommandPalette(
_ app: ghostty_app_t,
target: ghostty_target_s) {
switch (target.tag) {
case GHOSTTY_TARGET_APP:
Ghostty.logger.warning("toggle command palette does nothing with an app target")
return
case GHOSTTY_TARGET_SURFACE:
guard let surface = target.target.surface else { return }
guard let surfaceView = self.surfaceView(from: surface) else { return }
NotificationCenter.default.post(
name: .ghosttyCommandPaletteDidToggle,
object: surfaceView
)
default:
assertionFailure()
}
}
private static func toggleVisibility( private static func toggleVisibility(
_ app: ghostty_app_t, _ app: ghostty_app_t,
target: ghostty_target_s target: ghostty_target_s

View File

@ -256,6 +256,7 @@ extension Notification.Name {
/// Ring the bell /// Ring the bell
static let ghosttyBellDidRing = Notification.Name("com.mitchellh.ghostty.ghosttyBellDidRing") static let ghosttyBellDidRing = Notification.Name("com.mitchellh.ghostty.ghosttyBellDidRing")
static let ghosttyCommandPaletteDidToggle = Notification.Name("com.mitchellh.ghostty.commandPaletteDidToggle")
} }
// NOTE: I am moving all of these to Notification.Name extensions over time. This // NOTE: I am moving all of these to Notification.Name extensions over time. This

View File

@ -4295,6 +4295,12 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
.toggle, .toggle,
), ),
.toggle_command_palette => return try self.rt_app.performAction(
.{ .surface = self },
.toggle_command_palette,
{},
),
.select_all => { .select_all => {
const sel = self.io.terminal.screen.selectAll(); const sel = self.io.terminal.screen.selectAll();
if (sel) |s| { if (sel) |s| {

View File

@ -107,6 +107,9 @@ pub const Action = union(Key) {
/// Toggle the quick terminal in or out. /// Toggle the quick terminal in or out.
toggle_quick_terminal, toggle_quick_terminal,
/// Toggle the command palette. This currently only works on macOS.
toggle_command_palette,
/// Toggle the visibility of all Ghostty terminal windows. /// Toggle the visibility of all Ghostty terminal windows.
toggle_visibility, toggle_visibility,
@ -244,6 +247,8 @@ pub const Action = union(Key) {
/// Closes the currently focused window. /// Closes the currently focused window.
close_window, close_window,
/// Called when the bell character is seen. The apprt should do whatever
/// it needs to ring the bell. This is usually a sound or visual effect.
ring_bell, ring_bell,
/// Sync with: ghostty_action_tag_e /// Sync with: ghostty_action_tag_e
@ -259,6 +264,7 @@ pub const Action = union(Key) {
toggle_tab_overview, toggle_tab_overview,
toggle_window_decorations, toggle_window_decorations,
toggle_quick_terminal, toggle_quick_terminal,
toggle_command_palette,
toggle_visibility, toggle_visibility,
move_tab, move_tab,
goto_tab, goto_tab,

View File

@ -228,6 +228,7 @@ pub const App = struct {
.toggle_tab_overview, .toggle_tab_overview,
.toggle_window_decorations, .toggle_window_decorations,
.toggle_quick_terminal, .toggle_quick_terminal,
.toggle_command_palette,
.toggle_visibility, .toggle_visibility,
.goto_tab, .goto_tab,
.move_tab, .move_tab,

View File

@ -488,6 +488,7 @@ pub fn performAction(
// Unimplemented // Unimplemented
.close_all_windows, .close_all_windows,
.toggle_command_palette,
.toggle_visibility, .toggle_visibility,
.cell_size, .cell_size,
.key_sequence, .key_sequence,

View File

@ -4866,6 +4866,13 @@ pub const Keybinds = struct {
.{ .jump_to_prompt = 1 }, .{ .jump_to_prompt = 1 },
); );
// Toggle command palette, matches VSCode
try self.set.put(
alloc,
.{ .key = .{ .translated = .p }, .mods = .{ .super = true, .shift = true } },
.{ .toggle_command_palette = {} },
);
// Inspector, matching Chromium // Inspector, matching Chromium
try self.set.put( try self.set.put(
alloc, alloc,

View File

@ -441,6 +441,14 @@ pub const Action = union(enum) {
/// This only works on macOS, since this is a system API on macOS. /// This only works on macOS, since this is a system API on macOS.
toggle_secure_input: void, toggle_secure_input: void,
/// Toggle the command palette. The command palette is a UI element
/// that lets you see what actions you can perform, their associated
/// keybindings (if any), a search bar to filter the actions, and
/// the ability to then execute the action.
///
/// This only works on macOS.
toggle_command_palette,
/// Toggle the "quick" terminal. The quick terminal is a terminal that /// Toggle the "quick" terminal. The quick terminal is a terminal that
/// appears on demand from a keybinding, often sliding in from a screen /// appears on demand from a keybinding, often sliding in from a screen
/// edge such as the top. This is useful for quick access to a terminal /// edge such as the top. This is useful for quick access to a terminal
@ -790,6 +798,7 @@ pub const Action = union(enum) {
.toggle_fullscreen, .toggle_fullscreen,
.toggle_window_decorations, .toggle_window_decorations,
.toggle_secure_input, .toggle_secure_input,
.toggle_command_palette,
.reset_window_size, .reset_window_size,
.crash, .crash,
=> .surface, => .surface,

View File

@ -365,6 +365,7 @@ fn actionCommands(action: Action.Key) []const Command {
// No commands because I'm not sure they make sense in a command // No commands because I'm not sure they make sense in a command
// palette context. // palette context.
.toggle_command_palette,
.toggle_quick_terminal, .toggle_quick_terminal,
.toggle_visibility, .toggle_visibility,
.previous_tab, .previous_tab,