macos: improve "Set Default Terminal" (#10843)

Switch to using the existing UTType.unixExecutable constant for this
operator, which also lets us remove a failure path. Also, use the
completion-based setDefaultApplication() variant to handle errors.

This simplifies the code enough that we don't need the additional
NSWorkspace+Ghostty extension functions.
This commit is contained in:
Mitchell Hashimoto
2026-02-18 09:03:45 -08:00
committed by GitHub
4 changed files with 23 additions and 54 deletions

View File

@@ -147,7 +147,6 @@
Features/Update/UpdatePopoverView.swift,
Features/Update/UpdateSimulator.swift,
Features/Update/UpdateViewModel.swift,
"Ghostty/Extensions/NSWorkspace+Ghostty.swift",
"Ghostty/FullscreenMode+Extension.swift",
Ghostty/Ghostty.Error.swift,
Ghostty/Ghostty.Event.swift,

View File

@@ -1294,19 +1294,21 @@ extension AppDelegate {
ud.removeObject(forKey: key)
}
}
@IBAction func setAsDefaultTerminal(_ sender: NSMenuItem) {
do {
try NSWorkspace.shared.setGhosttyAsDefaultTerminal()
// Success - menu state will automatically update via validateMenuItem
} catch {
// Show error dialog
let alert = NSAlert()
alert.messageText = "Failed to Set Default Terminal"
alert.informativeText = "Ghostty could not be set as the default terminal application.\n\nError: \(error.localizedDescription)"
alert.alertStyle = .warning
alert.addButton(withTitle: "OK")
alert.runModal()
NSWorkspace.shared.setDefaultApplication(at: Bundle.main.bundleURL, toOpen: .unixExecutable) { error in
guard let error else { return }
Task { @MainActor in
let alert = NSAlert()
alert.messageText = "Failed to Set Default Terminal"
alert.informativeText = """
Ghostty could not be set as the default terminal application.
Error: \(error.localizedDescription)
"""
alert.alertStyle = .warning
alert.runModal()
}
}
}
}
@@ -1317,11 +1319,8 @@ extension AppDelegate: NSMenuItemValidation {
func validateMenuItem(_ item: NSMenuItem) -> Bool {
switch item.action {
case #selector(setAsDefaultTerminal(_:)):
// Check if Ghostty is already the default terminal
let isDefault = NSWorkspace.shared.isGhosttyDefaultTerminal
// Disable menu item if already default (option A)
return !isDefault
return NSWorkspace.shared.defaultTerminal != Bundle.main.bundleURL
case #selector(floatOnTop(_:)),
#selector(useAsDefault(_:)):
// Float on top items only active if the key window is a primary

View File

@@ -1,34 +0,0 @@
import AppKit
import UniformTypeIdentifiers
extension NSWorkspace {
/// Checks if Ghostty is the default terminal application.
/// - Returns: True if Ghostty is the default application for handling public.unix-executable files.
var isGhosttyDefaultTerminal: Bool {
let ghosttyURL = Bundle.main.bundleURL
guard let defaultAppURL = defaultApplicationURL(forContentType: "public.unix-executable") else {
return false
}
// Compare bundle paths
return ghosttyURL.path == defaultAppURL.path
}
/// Sets Ghostty as the default terminal application.
/// - Throws: An error if the application bundle cannot be located or if setting the default fails.
func setGhosttyAsDefaultTerminal() throws {
let ghosttyURL = Bundle.main.bundleURL
// Create UTType for unix executables
guard let unixExecutableType = UTType("public.unix-executable") else {
throw NSError(
domain: "com.mitchellh.ghostty",
code: 2,
userInfo: [NSLocalizedDescriptionKey: "Could not create UTType for public.unix-executable"]
)
}
// Use NSWorkspace API to set the default application
// This API is available on macOS 12.0+, Ghostty supports 13.0+, so it's compatible
setDefaultApplication(at: ghosttyURL, toOpen: unixExecutableType)
}
}

View File

@@ -7,7 +7,13 @@ extension NSWorkspace {
var defaultTextEditor: URL? {
defaultApplicationURL(forContentType: UTType.plainText.identifier)
}
/// Returns the URL of the default terminal (Unix Executable) application.
/// - Returns: The URL of the default terminal, or nil if no default terminal is found.
var defaultTerminal: URL? {
defaultApplicationURL(forContentType: UTType.unixExecutable.identifier)
}
/// Returns the URL of the default application for opening files with the specified content type.
/// - Parameter contentType: The content type identifier (UTI) to find the default application for.
/// - Returns: The URL of the default application, or nil if no default application is found.
@@ -26,5 +32,4 @@ extension NSWorkspace {
guard let uti = UTType(filenameExtension: ext) else { return nil}
return defaultApplicationURL(forContentType: uti.identifier)
}
}