mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-19 14:00:29 +00:00
macos: add AppleScript split command
Add a new `split` command to the AppleScript scripting dictionary that splits a terminal in a given direction (right, left, down, up) and returns the newly created terminal. The command is exposed as: split terminal <terminal> direction <direction> Also adds a `fourCharCode` String extension for converting four-character ASCII strings to their FourCharCode (UInt32) representation.
This commit is contained in:
76
macos/Sources/Features/AppleScript/ScriptTerminal.swift
Normal file
76
macos/Sources/Features/AppleScript/ScriptTerminal.swift
Normal file
@@ -0,0 +1,76 @@
|
||||
import AppKit
|
||||
|
||||
/// AppleScript-facing wrapper around a live Ghostty terminal surface.
|
||||
///
|
||||
/// This class is intentionally ObjC-visible because Cocoa scripting resolves
|
||||
/// AppleScript objects through Objective-C runtime names/selectors, not Swift
|
||||
/// protocol conformance.
|
||||
///
|
||||
/// Mapping from `Ghostty.sdef`:
|
||||
/// - `class terminal` -> this class (`@objc(GhosttyAppleScriptTerminal)`).
|
||||
/// - `property id` -> `@objc(id)` getter below.
|
||||
/// - `property title` -> `@objc(title)` getter below.
|
||||
/// - `property working directory` -> `@objc(workingDirectory)` getter below.
|
||||
///
|
||||
/// We keep only a weak reference to the underlying `SurfaceView` so this
|
||||
/// wrapper never extends the terminal's lifetime.
|
||||
@MainActor
|
||||
@objc(GhosttyScriptTerminal)
|
||||
final class ScriptTerminal: NSObject {
|
||||
/// Weak reference to the underlying surface. Package-visible so that
|
||||
/// other AppleScript command handlers (e.g. `ScriptSplitCommand`) can
|
||||
/// access the live surface without exposing it to ObjC/AppleScript.
|
||||
weak var surfaceView: Ghostty.SurfaceView?
|
||||
|
||||
init(surfaceView: Ghostty.SurfaceView) {
|
||||
self.surfaceView = surfaceView
|
||||
}
|
||||
|
||||
/// Exposed as the AppleScript `id` property.
|
||||
///
|
||||
/// This is a stable UUID string for the life of a surface and is also used
|
||||
/// by `NSUniqueIDSpecifier` to re-identify a terminal object in scripts.
|
||||
@objc(id)
|
||||
var stableID: String {
|
||||
surfaceView?.id.uuidString ?? ""
|
||||
}
|
||||
|
||||
/// Exposed as the AppleScript `title` property.
|
||||
@objc(title)
|
||||
var title: String {
|
||||
surfaceView?.title ?? ""
|
||||
}
|
||||
|
||||
/// Exposed as the AppleScript `working directory` property.
|
||||
///
|
||||
/// The `sdef` uses a spaced name, but Cocoa scripting maps that to the
|
||||
/// camel-cased selector name `workingDirectory`.
|
||||
@objc(workingDirectory)
|
||||
var workingDirectory: String {
|
||||
surfaceView?.pwd ?? ""
|
||||
}
|
||||
|
||||
/// Used by command handling (`perform action ... on <terminal>`).
|
||||
func perform(action: String) -> Bool {
|
||||
guard let surfaceModel = surfaceView?.surfaceModel else { return false }
|
||||
return surfaceModel.perform(action: action)
|
||||
}
|
||||
|
||||
/// Provides Cocoa scripting with a canonical "path" back to this object.
|
||||
///
|
||||
/// Without an object specifier, returned terminal objects can't be reliably
|
||||
/// referenced in follow-up script statements because AppleScript cannot
|
||||
/// express where the object came from (`application.terminals[id]`).
|
||||
override var objectSpecifier: NSScriptObjectSpecifier? {
|
||||
guard let appClassDescription = NSApplication.shared.classDescription as? NSScriptClassDescription else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return NSUniqueIDSpecifier(
|
||||
containerClassDescription: appClassDescription,
|
||||
containerSpecifier: nil,
|
||||
key: "terminals",
|
||||
uniqueID: stableID
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user