mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: implement service provider
This commit is contained in:
@ -22,6 +22,47 @@
|
|||||||
<key>GHOSTTY_MAC_APP</key>
|
<key>GHOSTTY_MAC_APP</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>NSServices</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>NSMenuItem</key>
|
||||||
|
<dict>
|
||||||
|
<key>default</key>
|
||||||
|
<string>New Ghostty Tab Here</string>
|
||||||
|
</dict>
|
||||||
|
<key>NSMessage</key>
|
||||||
|
<string>openTab</string>
|
||||||
|
<key>NSRequiredContext</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSTextContent</key>
|
||||||
|
<string>FilePath</string>
|
||||||
|
</dict>
|
||||||
|
<key>NSSendTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>NSFilenamesPboardType</string>
|
||||||
|
<string>public.plain-text</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>NSMenuItem</key>
|
||||||
|
<dict>
|
||||||
|
<key>default</key>
|
||||||
|
<string>New Ghostty Window Here</string>
|
||||||
|
</dict>
|
||||||
|
<key>NSMessage</key>
|
||||||
|
<string>openWindow</string>
|
||||||
|
<key>NSRequiredContext</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSTextContent</key>
|
||||||
|
<string>FilePath</string>
|
||||||
|
</dict>
|
||||||
|
<key>NSSendTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>NSFilenamesPboardType</string>
|
||||||
|
<string>public.plain-text</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSAppleEventsUsageDescription</key>
|
<key>NSAppleEventsUsageDescription</key>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
A55B7BBE29B701360055DE60 /* Ghostty.SplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BBD29B701360055DE60 /* Ghostty.SplitView.swift */; };
|
A55B7BBE29B701360055DE60 /* Ghostty.SplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BBD29B701360055DE60 /* Ghostty.SplitView.swift */; };
|
||||||
A56B880B2A840447007A0E29 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A56B880A2A840447007A0E29 /* Carbon.framework */; };
|
A56B880B2A840447007A0E29 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A56B880A2A840447007A0E29 /* Carbon.framework */; };
|
||||||
A56D58862ACDDB4100508D2C /* Ghostty.Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A56D58852ACDDB4100508D2C /* Ghostty.Shell.swift */; };
|
A56D58862ACDDB4100508D2C /* Ghostty.Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A56D58852ACDDB4100508D2C /* Ghostty.Shell.swift */; };
|
||||||
|
A56D58892ACDE6CA00508D2C /* ServiceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A56D58882ACDE6CA00508D2C /* ServiceProvider.swift */; };
|
||||||
A571AB1D2A206FCF00248498 /* GhosttyKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A5D495A1299BEC7E00DD1313 /* GhosttyKit.xcframework */; };
|
A571AB1D2A206FCF00248498 /* GhosttyKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A5D495A1299BEC7E00DD1313 /* GhosttyKit.xcframework */; };
|
||||||
A59444F729A2ED5200725BBA /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59444F629A2ED5200725BBA /* SettingsView.swift */; };
|
A59444F729A2ED5200725BBA /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59444F629A2ED5200725BBA /* SettingsView.swift */; };
|
||||||
A5A1F8852A489D6800D1E8BC /* terminfo in Resources */ = {isa = PBXBuildFile; fileRef = A5A1F8842A489D6800D1E8BC /* terminfo */; };
|
A5A1F8852A489D6800D1E8BC /* terminfo in Resources */ = {isa = PBXBuildFile; fileRef = A5A1F8842A489D6800D1E8BC /* terminfo */; };
|
||||||
@ -55,6 +56,7 @@
|
|||||||
A55B7BBD29B701360055DE60 /* Ghostty.SplitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.SplitView.swift; sourceTree = "<group>"; };
|
A55B7BBD29B701360055DE60 /* Ghostty.SplitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.SplitView.swift; sourceTree = "<group>"; };
|
||||||
A56B880A2A840447007A0E29 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
|
A56B880A2A840447007A0E29 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
|
||||||
A56D58852ACDDB4100508D2C /* Ghostty.Shell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Shell.swift; sourceTree = "<group>"; };
|
A56D58852ACDDB4100508D2C /* Ghostty.Shell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Shell.swift; sourceTree = "<group>"; };
|
||||||
|
A56D58882ACDE6CA00508D2C /* ServiceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceProvider.swift; sourceTree = "<group>"; };
|
||||||
A571AB1C2A206FC600248498 /* Ghostty-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Ghostty-Info.plist"; sourceTree = "<group>"; };
|
A571AB1C2A206FC600248498 /* Ghostty-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Ghostty-Info.plist"; sourceTree = "<group>"; };
|
||||||
A59444F629A2ED5200725BBA /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
A59444F629A2ED5200725BBA /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||||
A5A1F8842A489D6800D1E8BC /* terminfo */ = {isa = PBXFileReference; lastKnownFileType = folder; name = terminfo; path = "../zig-out/share/terminfo"; sourceTree = "<group>"; };
|
A5A1F8842A489D6800D1E8BC /* terminfo */ = {isa = PBXFileReference; lastKnownFileType = folder; name = terminfo; path = "../zig-out/share/terminfo"; sourceTree = "<group>"; };
|
||||||
@ -89,6 +91,7 @@
|
|||||||
A53426362A7DC53000EBB7A2 /* Features */ = {
|
A53426362A7DC53000EBB7A2 /* Features */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
A56D58872ACDE6BE00508D2C /* Services */,
|
||||||
A53426372A7DC53A00EBB7A2 /* Primary Window */,
|
A53426372A7DC53A00EBB7A2 /* Primary Window */,
|
||||||
A534263E2A7DCC5800EBB7A2 /* Settings */,
|
A534263E2A7DCC5800EBB7A2 /* Settings */,
|
||||||
);
|
);
|
||||||
@ -156,6 +159,14 @@
|
|||||||
path = Ghostty;
|
path = Ghostty;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
A56D58872ACDE6BE00508D2C /* Services */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A56D58882ACDE6CA00508D2C /* ServiceProvider.swift */,
|
||||||
|
);
|
||||||
|
path = Services;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
A5A1F8862A489D7400D1E8BC /* Resources */ = {
|
A5A1F8862A489D7400D1E8BC /* Resources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -279,6 +290,7 @@
|
|||||||
files = (
|
files = (
|
||||||
A53426392A7DC55C00EBB7A2 /* PrimaryWindowManager.swift in Sources */,
|
A53426392A7DC55C00EBB7A2 /* PrimaryWindowManager.swift in Sources */,
|
||||||
85DE1C922A6A3DCA00493853 /* PrimaryWindow.swift in Sources */,
|
85DE1C922A6A3DCA00493853 /* PrimaryWindow.swift in Sources */,
|
||||||
|
A56D58892ACDE6CA00508D2C /* ServiceProvider.swift in Sources */,
|
||||||
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */,
|
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */,
|
||||||
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */,
|
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */,
|
||||||
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */,
|
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */,
|
||||||
|
@ -40,7 +40,7 @@ class AppDelegate: NSObject, ObservableObject, NSApplicationDelegate, GhosttyApp
|
|||||||
private var ghostty: Ghostty.AppState = Ghostty.AppState()
|
private var ghostty: Ghostty.AppState = Ghostty.AppState()
|
||||||
|
|
||||||
/// Manages windows and tabs, ensuring they're allocated/deallocated correctly
|
/// Manages windows and tabs, ensuring they're allocated/deallocated correctly
|
||||||
private var windowManager: PrimaryWindowManager!
|
var windowManager: PrimaryWindowManager!
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
super.init()
|
super.init()
|
||||||
@ -72,6 +72,10 @@ class AppDelegate: NSObject, ObservableObject, NSApplicationDelegate, GhosttyApp
|
|||||||
|
|
||||||
// Initial config loading
|
// Initial config loading
|
||||||
configDidReload(ghostty)
|
configDidReload(ghostty)
|
||||||
|
|
||||||
|
// Register our service provider. This must happen after everything
|
||||||
|
// else is initialized.
|
||||||
|
NSApp.servicesProvider = ServiceProvider()
|
||||||
}
|
}
|
||||||
|
|
||||||
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
|
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
|
||||||
|
68
macos/Sources/Features/Services/ServiceProvider.swift
Normal file
68
macos/Sources/Features/Services/ServiceProvider.swift
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import Foundation
|
||||||
|
import AppKit
|
||||||
|
|
||||||
|
class ServiceProvider: NSObject {
|
||||||
|
static private let errorNoString = NSString(string: "Could not load any text from the clipboard.")
|
||||||
|
|
||||||
|
/// The target for an open operation
|
||||||
|
enum OpenTarget {
|
||||||
|
case tab
|
||||||
|
case window
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func openTab(
|
||||||
|
_ pasteboard: NSPasteboard,
|
||||||
|
userData: String?,
|
||||||
|
error: AutoreleasingUnsafeMutablePointer<NSString>
|
||||||
|
) {
|
||||||
|
guard let str = pasteboard.string(forType: .string) else {
|
||||||
|
error.pointee = Self.errorNoString
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
openTerminal(str, target: .tab)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func openWindow(
|
||||||
|
_ pasteboard: NSPasteboard,
|
||||||
|
userData: String?,
|
||||||
|
error: AutoreleasingUnsafeMutablePointer<NSString>
|
||||||
|
) {
|
||||||
|
guard let str = pasteboard.string(forType: .string) else {
|
||||||
|
error.pointee = Self.errorNoString
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
openTerminal(str, target: .window)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func openTerminal(_ path: String, target: OpenTarget) {
|
||||||
|
guard let delegateRaw = NSApp.delegate else { return }
|
||||||
|
guard let delegate = delegateRaw as? AppDelegate else { return }
|
||||||
|
guard let windowManager = delegate.windowManager else { return }
|
||||||
|
|
||||||
|
// We only open in directories.
|
||||||
|
var isDirectory = ObjCBool(true)
|
||||||
|
guard FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory) else { return }
|
||||||
|
guard isDirectory.boolValue else { return }
|
||||||
|
|
||||||
|
// Build our config
|
||||||
|
var config = Ghostty.SurfaceConfiguration()
|
||||||
|
config.workingDirectory = path
|
||||||
|
|
||||||
|
// If we don't have a window open through the window manager, we launch
|
||||||
|
// a new window even if they requested a tab.
|
||||||
|
guard let mainWindow = windowManager.mainWindow else {
|
||||||
|
windowManager.addNewWindow(withBaseConfig: config)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (target) {
|
||||||
|
case .window:
|
||||||
|
windowManager.addNewWindow(withBaseConfig: config)
|
||||||
|
|
||||||
|
case .tab:
|
||||||
|
windowManager.addNewTab(to: mainWindow, withBaseConfig: config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user