mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-06 07:38:21 +00:00
macos: use direct parameters for object-targeting commands
Change split, focus, close, activate window, select tab, close tab, and close window commands to accept their target object as a direct parameter instead of a named parameter. This produces natural AppleScript syntax: activate window (window 1) close tab (tab 1 of window 1) split (terminal 1) direction right instead of the awkward redundant form: activate window window (window 1) close tab tab (tab 1 of window 1) split terminal (terminal 1) direction right The implementation moves command logic from NSScriptCommand subclasses into responds-to handler methods on ScriptTerminal, ScriptWindow, and ScriptTab, which is the standard Cocoa Scripting pattern for commands whose direct parameter is an application class.
This commit is contained in:
@@ -44,6 +44,12 @@
|
||||
<property name="selected tab" code="GWsT" type="tab" access="r" description="The selected tab in this window.">
|
||||
<cocoa key="selectedTab"/>
|
||||
</property>
|
||||
<responds-to command="activate window">
|
||||
<cocoa method="handleActivateWindowCommand:"/>
|
||||
</responds-to>
|
||||
<responds-to command="close window">
|
||||
<cocoa method="handleCloseWindowCommand:"/>
|
||||
</responds-to>
|
||||
<element type="tab" access="r">
|
||||
<cocoa key="tabs"/>
|
||||
</element>
|
||||
@@ -60,6 +66,12 @@
|
||||
</property>
|
||||
<property name="index" code="pidx" type="integer" access="r" description="1-based index of this tab in its window."/>
|
||||
<property name="selected" code="GTsl" type="boolean" access="r" description="Whether this tab is selected in its window."/>
|
||||
<responds-to command="select tab">
|
||||
<cocoa method="handleSelectTabCommand:"/>
|
||||
</responds-to>
|
||||
<responds-to command="close tab">
|
||||
<cocoa method="handleCloseTabCommand:"/>
|
||||
</responds-to>
|
||||
<element type="terminal" access="r">
|
||||
<cocoa key="terminals"/>
|
||||
</element>
|
||||
@@ -72,6 +84,15 @@
|
||||
<cocoa key="title"/>
|
||||
</property>
|
||||
<property name="working directory" code="Gwdr" type="text" access="r" description="Current working directory for the terminal process."/>
|
||||
<responds-to command="split">
|
||||
<cocoa method="handleSplitCommand:"/>
|
||||
</responds-to>
|
||||
<responds-to command="focus">
|
||||
<cocoa method="handleFocusCommand:"/>
|
||||
</responds-to>
|
||||
<responds-to command="close">
|
||||
<cocoa method="handleCloseCommand:"/>
|
||||
</responds-to>
|
||||
</class>
|
||||
|
||||
<record-type name="surface configuration" code="GScf" description="Reusable settings applied when creating a terminal surface.">
|
||||
@@ -155,10 +176,7 @@
|
||||
</command>
|
||||
|
||||
<command name="split" code="GhstSplt" description="Split a terminal in the given direction.">
|
||||
<cocoa class="GhosttyScriptSplitCommand"/>
|
||||
<parameter name="terminal" code="GSpT" type="terminal" description="The terminal to split.">
|
||||
<cocoa key="terminal"/>
|
||||
</parameter>
|
||||
<direct-parameter type="specifier" description="The terminal to split."/>
|
||||
<parameter name="direction" code="GSpd" type="split direction" description="The direction to split.">
|
||||
<cocoa key="direction"/>
|
||||
</parameter>
|
||||
@@ -169,45 +187,27 @@
|
||||
</command>
|
||||
|
||||
<command name="focus" code="GhstFcus" description="Focus a terminal, bringing its window to the front.">
|
||||
<cocoa class="GhosttyScriptFocusCommand"/>
|
||||
<parameter name="terminal" code="GFcT" type="terminal" description="The terminal to focus.">
|
||||
<cocoa key="terminal"/>
|
||||
</parameter>
|
||||
<direct-parameter type="specifier" description="The terminal to focus."/>
|
||||
</command>
|
||||
|
||||
<command name="close" code="GhstClos" description="Close a terminal.">
|
||||
<cocoa class="GhosttyScriptCloseCommand"/>
|
||||
<parameter name="terminal" code="GClT" type="terminal" description="The terminal to close.">
|
||||
<cocoa key="terminal"/>
|
||||
</parameter>
|
||||
<direct-parameter type="specifier" description="The terminal to close."/>
|
||||
</command>
|
||||
|
||||
<command name="activate window" code="GhstAcWn" description="Activate a Ghostty window, bringing it to the front.">
|
||||
<cocoa class="GhosttyScriptActivateWindowCommand"/>
|
||||
<parameter name="window" code="GAwW" type="window" description="The window to activate.">
|
||||
<cocoa key="window"/>
|
||||
</parameter>
|
||||
<direct-parameter type="specifier" description="The window to activate."/>
|
||||
</command>
|
||||
|
||||
<command name="select tab" code="GhstSlTb" description="Select a tab in its window.">
|
||||
<cocoa class="GhosttyScriptSelectTabCommand"/>
|
||||
<parameter name="tab" code="GStT" type="tab" description="The tab to select.">
|
||||
<cocoa key="tab"/>
|
||||
</parameter>
|
||||
<direct-parameter type="specifier" description="The tab to select."/>
|
||||
</command>
|
||||
|
||||
<command name="close tab" code="GhstClTb" description="Close a tab.">
|
||||
<cocoa class="GhosttyScriptCloseTabCommand"/>
|
||||
<parameter name="tab" code="GCtT" type="tab" description="The tab to close.">
|
||||
<cocoa key="tab"/>
|
||||
</parameter>
|
||||
<direct-parameter type="specifier" description="The tab to close."/>
|
||||
</command>
|
||||
|
||||
<command name="close window" code="GhstClWn" description="Close a window.">
|
||||
<cocoa class="GhosttyScriptCloseWindowCommand"/>
|
||||
<parameter name="window" code="GCwW" type="window" description="The window to close.">
|
||||
<cocoa key="window"/>
|
||||
</parameter>
|
||||
<direct-parameter type="specifier" description="The window to close."/>
|
||||
</command>
|
||||
|
||||
<command name="input text" code="GhstInTx" description="Input text to a terminal as if it was pasted.">
|
||||
|
||||
@@ -138,15 +138,12 @@
|
||||
"Features/App Intents/QuickTerminalIntent.swift",
|
||||
"Features/AppleScript/AppDelegate+AppleScript.swift",
|
||||
"Features/AppleScript/Ghostty.Input.Mods+AppleScript.swift",
|
||||
Features/AppleScript/ScriptCloseCommand.swift,
|
||||
Features/AppleScript/ScriptFocusCommand.swift,
|
||||
Features/AppleScript/ScriptInputTextCommand.swift,
|
||||
Features/AppleScript/ScriptKeyEventCommand.swift,
|
||||
Features/AppleScript/ScriptMouseButtonCommand.swift,
|
||||
Features/AppleScript/ScriptMousePosCommand.swift,
|
||||
Features/AppleScript/ScriptMouseScrollCommand.swift,
|
||||
Features/AppleScript/ScriptRecord.swift,
|
||||
Features/AppleScript/ScriptSplitCommand.swift,
|
||||
Features/AppleScript/ScriptSurfaceConfiguration.swift,
|
||||
Features/AppleScript/ScriptTab.swift,
|
||||
Features/AppleScript/ScriptTerminal.swift,
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
import AppKit
|
||||
|
||||
/// Handler for the `close` AppleScript command defined in `Ghostty.sdef`.
|
||||
///
|
||||
/// Cocoa scripting instantiates this class because the command's `<cocoa>` element
|
||||
/// specifies `class="GhosttyScriptCloseCommand"`. The runtime calls
|
||||
/// `performDefaultImplementation()` to execute the command.
|
||||
@MainActor
|
||||
@objc(GhosttyScriptCloseCommand)
|
||||
final class ScriptCloseCommand: NSScriptCommand {
|
||||
override func performDefaultImplementation() -> Any? {
|
||||
guard NSApp.validateScript(command: self) else { return nil }
|
||||
|
||||
guard let terminal = evaluatedArguments?["terminal"] as? ScriptTerminal else {
|
||||
scriptErrorNumber = errAEParamMissed
|
||||
scriptErrorString = "Missing terminal target."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let surfaceView = terminal.surfaceView else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Terminal surface is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let controller = surfaceView.window?.windowController as? BaseTerminalController else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Terminal is not in a window."
|
||||
return nil
|
||||
}
|
||||
|
||||
controller.closeSurface(surfaceView, withConfirmation: false)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Handler for the container-level `close tab` AppleScript command defined in
|
||||
/// `Ghostty.sdef`.
|
||||
@MainActor
|
||||
@objc(GhosttyScriptCloseTabCommand)
|
||||
final class ScriptCloseTabCommand: NSScriptCommand {
|
||||
override func performDefaultImplementation() -> Any? {
|
||||
guard NSApp.validateScript(command: self) else { return nil }
|
||||
|
||||
guard let tab = evaluatedArguments?["tab"] as? ScriptTab else {
|
||||
scriptErrorNumber = errAEParamMissed
|
||||
scriptErrorString = "Missing tab target."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let tabController = tab.parentController else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Tab is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
if let managedTerminalController = tabController as? TerminalController {
|
||||
managedTerminalController.closeTabImmediately(registerRedo: false)
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let tabContainerWindow = tab.parentWindow else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Tab container window is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
tabContainerWindow.close()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Handler for the container-level `close window` AppleScript command defined in
|
||||
/// `Ghostty.sdef`.
|
||||
@MainActor
|
||||
@objc(GhosttyScriptCloseWindowCommand)
|
||||
final class ScriptCloseWindowCommand: NSScriptCommand {
|
||||
override func performDefaultImplementation() -> Any? {
|
||||
guard NSApp.validateScript(command: self) else { return nil }
|
||||
|
||||
guard let window = evaluatedArguments?["window"] as? ScriptWindow else {
|
||||
scriptErrorNumber = errAEParamMissed
|
||||
scriptErrorString = "Missing window target."
|
||||
return nil
|
||||
}
|
||||
|
||||
if let managedTerminalController = window.preferredController as? TerminalController {
|
||||
managedTerminalController.closeWindowImmediately()
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let windowContainer = window.preferredParentWindow else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Window is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
windowContainer.close()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
import AppKit
|
||||
|
||||
/// Handler for the `focus` AppleScript command defined in `Ghostty.sdef`.
|
||||
///
|
||||
/// Cocoa scripting instantiates this class because the command's `<cocoa>` element
|
||||
/// specifies `class="GhosttyScriptFocusCommand"`. The runtime calls
|
||||
/// `performDefaultImplementation()` to execute the command.
|
||||
@MainActor
|
||||
@objc(GhosttyScriptFocusCommand)
|
||||
final class ScriptFocusCommand: NSScriptCommand {
|
||||
override func performDefaultImplementation() -> Any? {
|
||||
guard NSApp.validateScript(command: self) else { return nil }
|
||||
|
||||
guard let terminal = evaluatedArguments?["terminal"] as? ScriptTerminal else {
|
||||
scriptErrorNumber = errAEParamMissed
|
||||
scriptErrorString = "Missing terminal target."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let surfaceView = terminal.surfaceView else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Terminal surface is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let controller = surfaceView.window?.windowController as? BaseTerminalController else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Terminal is not in a window."
|
||||
return nil
|
||||
}
|
||||
|
||||
controller.focusSurface(surfaceView)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Handler for the container-level `activate window` AppleScript command
|
||||
/// defined in `Ghostty.sdef`.
|
||||
@MainActor
|
||||
@objc(GhosttyScriptActivateWindowCommand)
|
||||
final class ScriptActivateWindowCommand: NSScriptCommand {
|
||||
override func performDefaultImplementation() -> Any? {
|
||||
guard NSApp.validateScript(command: self) else { return nil }
|
||||
|
||||
guard let window = evaluatedArguments?["window"] as? ScriptWindow else {
|
||||
scriptErrorNumber = errAEParamMissed
|
||||
scriptErrorString = "Missing window target."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let windowContainer = window.preferredParentWindow else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Window is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
windowContainer.makeKeyAndOrderFront(nil)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Handler for the container-level `select tab` AppleScript command defined in
|
||||
/// `Ghostty.sdef`.
|
||||
@MainActor
|
||||
@objc(GhosttyScriptSelectTabCommand)
|
||||
final class ScriptSelectTabCommand: NSScriptCommand {
|
||||
override func performDefaultImplementation() -> Any? {
|
||||
guard NSApp.validateScript(command: self) else { return nil }
|
||||
|
||||
guard let tab = evaluatedArguments?["tab"] as? ScriptTab else {
|
||||
scriptErrorNumber = errAEParamMissed
|
||||
scriptErrorString = "Missing tab target."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let tabContainerWindow = tab.parentWindow else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Tab is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
tabContainerWindow.makeKeyAndOrderFront(nil)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
import AppKit
|
||||
|
||||
/// Handler for the `split` AppleScript command defined in `Ghostty.sdef`.
|
||||
///
|
||||
/// Cocoa scripting instantiates this class because the command's `<cocoa>` element
|
||||
/// specifies `class="GhosttyScriptSplitCommand"`. The runtime calls
|
||||
/// `performDefaultImplementation()` to execute the command.
|
||||
@MainActor
|
||||
@objc(GhosttyScriptSplitCommand)
|
||||
final class ScriptSplitCommand: NSScriptCommand {
|
||||
override func performDefaultImplementation() -> Any? {
|
||||
guard NSApp.validateScript(command: self) else { return nil }
|
||||
|
||||
guard let terminal = evaluatedArguments?["terminal"] as? ScriptTerminal else {
|
||||
scriptErrorNumber = errAEParamMissed
|
||||
scriptErrorString = "Missing terminal target."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let surfaceView = terminal.surfaceView else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Terminal surface is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let directionCode = evaluatedArguments?["direction"] as? UInt32,
|
||||
let direction = ScriptSplitDirection(code: directionCode) else {
|
||||
scriptErrorNumber = errAEParamMissed
|
||||
scriptErrorString = "Missing or unknown split direction."
|
||||
return nil
|
||||
}
|
||||
|
||||
let baseConfig: Ghostty.SurfaceConfiguration?
|
||||
if let scriptRecord = evaluatedArguments?["configuration"] as? NSDictionary {
|
||||
do {
|
||||
baseConfig = try Ghostty.SurfaceConfiguration(scriptRecord: scriptRecord)
|
||||
} catch {
|
||||
scriptErrorNumber = errAECoercionFail
|
||||
scriptErrorString = error.localizedDescription
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
baseConfig = nil
|
||||
}
|
||||
|
||||
// Find the window controller that owns this surface.
|
||||
guard let controller = surfaceView.window?.windowController as? BaseTerminalController else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Terminal is not in a splittable window."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let newView = controller.newSplit(
|
||||
at: surfaceView,
|
||||
direction: direction.splitDirection,
|
||||
baseConfig: baseConfig
|
||||
) else {
|
||||
scriptErrorNumber = errAEEventFailed
|
||||
scriptErrorString = "Failed to create split."
|
||||
return nil
|
||||
}
|
||||
|
||||
return ScriptTerminal(surfaceView: newView)
|
||||
}
|
||||
}
|
||||
|
||||
/// Four-character codes matching the `split direction` enumeration in `Ghostty.sdef`.
|
||||
private enum ScriptSplitDirection {
|
||||
case right
|
||||
case left
|
||||
case down
|
||||
case up
|
||||
|
||||
init?(code: UInt32) {
|
||||
switch code {
|
||||
case "GSrt".fourCharCode: self = .right
|
||||
case "GSlf".fourCharCode: self = .left
|
||||
case "GSdn".fourCharCode: self = .down
|
||||
case "GSup".fourCharCode: self = .up
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
||||
var splitDirection: SplitTree<Ghostty.SurfaceView>.NewDirection {
|
||||
switch self {
|
||||
case .right: .right
|
||||
case .left: .left
|
||||
case .down: .down
|
||||
case .up: .up
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,6 +100,48 @@ final class ScriptTab: NSObject {
|
||||
.map(ScriptTerminal.init)
|
||||
}
|
||||
|
||||
/// Handler for `select tab <tab>`.
|
||||
@objc(handleSelectTabCommand:)
|
||||
func handleSelectTab(_ command: NSScriptCommand) -> Any? {
|
||||
guard NSApp.validateScript(command: command) else { return nil }
|
||||
|
||||
guard let tabContainerWindow = parentWindow else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Tab is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
tabContainerWindow.makeKeyAndOrderFront(nil)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Handler for `close tab <tab>`.
|
||||
@objc(handleCloseTabCommand:)
|
||||
func handleCloseTab(_ command: NSScriptCommand) -> Any? {
|
||||
guard NSApp.validateScript(command: command) else { return nil }
|
||||
|
||||
guard let tabController = parentController else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Tab is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
if let managedTerminalController = tabController as? TerminalController {
|
||||
managedTerminalController.closeTabImmediately(registerRedo: false)
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let tabContainerWindow = parentWindow else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Tab container window is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
tabContainerWindow.close()
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Provides Cocoa scripting with a canonical "path" back to this object.
|
||||
override var objectSpecifier: NSScriptObjectSpecifier? {
|
||||
guard NSApp.isAppleScriptEnabled else { return nil }
|
||||
|
||||
@@ -60,6 +60,103 @@ final class ScriptTerminal: NSObject {
|
||||
return surfaceModel.perform(action: action)
|
||||
}
|
||||
|
||||
/// Handler for `split <terminal> direction <dir>`.
|
||||
@objc(handleSplitCommand:)
|
||||
func handleSplit(_ command: NSScriptCommand) -> Any? {
|
||||
guard NSApp.validateScript(command: command) else { return nil }
|
||||
|
||||
guard let surfaceView else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Terminal surface is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let directionCode = command.evaluatedArguments?["direction"] as? UInt32 else {
|
||||
command.scriptErrorNumber = errAEParamMissed
|
||||
command.scriptErrorString = "Missing or unknown split direction."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let direction = ScriptSplitDirection(code: directionCode)?.splitDirection else {
|
||||
command.scriptErrorNumber = errAEParamMissed
|
||||
command.scriptErrorString = "Missing or unknown split direction."
|
||||
return nil
|
||||
}
|
||||
|
||||
let baseConfig: Ghostty.SurfaceConfiguration?
|
||||
if let scriptRecord = command.evaluatedArguments?["configuration"] as? NSDictionary {
|
||||
do {
|
||||
baseConfig = try Ghostty.SurfaceConfiguration(scriptRecord: scriptRecord)
|
||||
} catch {
|
||||
command.scriptErrorNumber = errAECoercionFail
|
||||
command.scriptErrorString = error.localizedDescription
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
baseConfig = nil
|
||||
}
|
||||
|
||||
guard let controller = surfaceView.window?.windowController as? BaseTerminalController else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Terminal is not in a splittable window."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let newView = controller.newSplit(
|
||||
at: surfaceView,
|
||||
direction: direction,
|
||||
baseConfig: baseConfig
|
||||
) else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Failed to create split."
|
||||
return nil
|
||||
}
|
||||
|
||||
return ScriptTerminal(surfaceView: newView)
|
||||
}
|
||||
|
||||
/// Handler for `focus <terminal>`.
|
||||
@objc(handleFocusCommand:)
|
||||
func handleFocus(_ command: NSScriptCommand) -> Any? {
|
||||
guard NSApp.validateScript(command: command) else { return nil }
|
||||
|
||||
guard let surfaceView else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Terminal surface is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let controller = surfaceView.window?.windowController as? BaseTerminalController else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Terminal is not in a window."
|
||||
return nil
|
||||
}
|
||||
|
||||
controller.focusSurface(surfaceView)
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Handler for `close <terminal>`.
|
||||
@objc(handleCloseCommand:)
|
||||
func handleClose(_ command: NSScriptCommand) -> Any? {
|
||||
guard NSApp.validateScript(command: command) else { return nil }
|
||||
|
||||
guard let surfaceView else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Terminal surface is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let controller = surfaceView.window?.windowController as? BaseTerminalController else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Terminal is not in a window."
|
||||
return nil
|
||||
}
|
||||
|
||||
controller.closeSurface(surfaceView, withConfirmation: false)
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Provides Cocoa scripting with a canonical "path" back to this object.
|
||||
///
|
||||
/// Without an object specifier, returned terminal objects can't be reliably
|
||||
@@ -79,3 +176,31 @@ final class ScriptTerminal: NSObject {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts four-character codes from the `split direction` enumeration in `Ghostty.sdef`
|
||||
/// to `SplitTree.NewDirection` values.
|
||||
enum ScriptSplitDirection {
|
||||
case right
|
||||
case left
|
||||
case down
|
||||
case up
|
||||
|
||||
init?(code: UInt32) {
|
||||
switch code {
|
||||
case "GSrt".fourCharCode: self = .right
|
||||
case "GSlf".fourCharCode: self = .left
|
||||
case "GSdn".fourCharCode: self = .down
|
||||
case "GSup".fourCharCode: self = .up
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
||||
var splitDirection: SplitTree<Ghostty.SurfaceView>.NewDirection {
|
||||
switch self {
|
||||
case .right: .right
|
||||
case .left: .left
|
||||
case .down: .down
|
||||
case .up: .up
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,42 @@ final class ScriptWindow: NSObject {
|
||||
return controllers.first
|
||||
}
|
||||
|
||||
/// Handler for `activate window <window>`.
|
||||
@objc(handleActivateWindowCommand:)
|
||||
func handleActivateWindow(_ command: NSScriptCommand) -> Any? {
|
||||
guard NSApp.validateScript(command: command) else { return nil }
|
||||
|
||||
guard let windowContainer = preferredParentWindow else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Window is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
windowContainer.makeKeyAndOrderFront(nil)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Handler for `close window <window>`.
|
||||
@objc(handleCloseWindowCommand:)
|
||||
func handleCloseWindow(_ command: NSScriptCommand) -> Any? {
|
||||
guard NSApp.validateScript(command: command) else { return nil }
|
||||
|
||||
if let managedTerminalController = preferredController as? TerminalController {
|
||||
managedTerminalController.closeWindowImmediately()
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let windowContainer = preferredParentWindow else {
|
||||
command.scriptErrorNumber = errAEEventFailed
|
||||
command.scriptErrorString = "Window is no longer available."
|
||||
return nil
|
||||
}
|
||||
|
||||
windowContainer.close()
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Provides Cocoa scripting with a canonical "path" back to this object.
|
||||
///
|
||||
/// Without this, Cocoa can return data but cannot reliably build object
|
||||
|
||||
Reference in New Issue
Block a user