From b6559d08994ebb39ef66d210cd5461e03c594637 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 20 Jun 2025 11:54:19 -0700 Subject: [PATCH] macos: add a macos-shortcut config --- .../App Intents/IntentPermission.swift | 21 ++++++++++++- macos/Sources/Ghostty/Ghostty.Config.swift | 17 ++++++++++ src/config/Config.zig | 31 +++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/macos/Sources/Features/App Intents/IntentPermission.swift b/macos/Sources/Features/App Intents/IntentPermission.swift index e02c4591d..78efb3d5d 100644 --- a/macos/Sources/Features/App Intents/IntentPermission.swift +++ b/macos/Sources/Features/App Intents/IntentPermission.swift @@ -1,5 +1,7 @@ +import AppKit + /// Requests permission for Shortcuts app to interact with Ghostty -/// +/// /// This function displays a permission dialog asking the user to allow Shortcuts /// to interact with Ghostty. The permission is automatically cached for 10 minutes /// if the user selects "Allow", meaning subsequent intent calls won't show the dialog @@ -25,6 +27,23 @@ func requestIntentPermission() async -> Bool { await withCheckedContinuation { continuation in Task { @MainActor in + if let delegate = NSApp.delegate as? AppDelegate { + switch (delegate.ghostty.config.macosShortcuts) { + case .allow: + continuation.resume(returning: true) + return + + case .deny: + continuation.resume(returning: false) + return + + case .ask: + // Continue with the permission dialog + break + } + } + + PermissionRequest.show( "org.mitchellh.ghostty.shortcutsPermission", message: "Allow Shortcuts to interact with Ghostty for the next 10 minutes?", diff --git a/macos/Sources/Ghostty/Ghostty.Config.swift b/macos/Sources/Ghostty/Ghostty.Config.swift index fcbea2a12..241c10632 100644 --- a/macos/Sources/Ghostty/Ghostty.Config.swift +++ b/macos/Sources/Ghostty/Ghostty.Config.swift @@ -558,6 +558,17 @@ extension Ghostty { _ = ghostty_config_get(config, &v, key, UInt(key.count)) return v } + + var macosShortcuts: MacShortcuts { + let defaultValue = MacShortcuts.ask + guard let config = self.config else { return defaultValue } + var v: UnsafePointer? = nil + let key = "macos-shortcuts" + guard ghostty_config_get(config, &v, key, UInt(key.count)) else { return defaultValue } + guard let ptr = v else { return defaultValue } + let str = String(cString: ptr) + return MacShortcuts(rawValue: str) ?? defaultValue + } } } @@ -584,6 +595,12 @@ extension Ghostty.Config { case always } + enum MacShortcuts: String { + case allow + case deny + case ask + } + enum ResizeOverlay : String { case always case never diff --git a/src/config/Config.zig b/src/config/Config.zig index e9370d9b3..aee670213 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -2355,6 +2355,30 @@ keybind: Keybinds = .{}, /// @"macos-icon-screen-color": ?ColorList = null, +/// Whether macOS Shortcuts are allowed to control Ghostty. +/// +/// Ghostty exposes a number of actions that allow Shortcuts to +/// control and interact with Ghostty. This includes creating new +/// terminals, sending text to terminals, running commands, invoking +/// any keybind action, etc. +/// +/// This is a powerful feature but can be a security risk if a malicious +/// shortcut is able to be installed and executed. Therefore, this +/// configuration allows you to disable this feature. +/// +/// Valid values are: +/// +/// * `ask` - Ask the user whether for permission. Ghostty will by default +/// cache the user's choice for 10 minutes since we can't determine +/// when a single workflow begins or ends. The user also has an option +/// in the GUI to allow for the remainder of the day. +/// +/// * `allow` - Allow Shortcuts to control Ghostty without asking. +/// +/// * `deny` - Deny Shortcuts from controlling Ghostty. +/// +@"macos-shortcuts": MacShortcuts = .ask, + /// Put every surface (tab, split, window) into a dedicated Linux cgroup. /// /// This makes it so that resource management can be done on a per-surface @@ -5961,6 +5985,13 @@ pub const MacAppIconFrame = enum { chrome, }; +/// See macos-shortcuts +pub const MacShortcuts = enum { + allow, + deny, + ask, +}; + /// See gtk-single-instance pub const GtkSingleInstance = enum { desktop,