* Update ghostty to v1.3.0 * Add bell handling and AppleScript support * Add zsh shell integration handoff test * Fix Ghostty zsh integration handoff in cmux * Add terminal keypress notification dismissal test * Dismiss terminal notifications on keypress * Address PR review feedback * Tighten notification dismissal regression test * Pin GhosttyKit checksum for latest ghostty
705 lines
22 KiB
Swift
705 lines
22 KiB
Swift
import AppKit
|
|
|
|
private enum AppleScriptStrings {
|
|
static let disabled = String(
|
|
localized: "applescript.error.disabled",
|
|
defaultValue: "AppleScript is disabled by the macos-applescript configuration."
|
|
)
|
|
static let missingAction = String(
|
|
localized: "applescript.error.missingAction",
|
|
defaultValue: "Missing action string."
|
|
)
|
|
static let missingInputText = String(
|
|
localized: "applescript.error.missingInputText",
|
|
defaultValue: "Missing input text."
|
|
)
|
|
static let missingTerminalTarget = String(
|
|
localized: "applescript.error.missingTerminalTarget",
|
|
defaultValue: "Missing terminal target."
|
|
)
|
|
static let missingSplitDirection = String(
|
|
localized: "applescript.error.missingSplitDirection",
|
|
defaultValue: "Missing or unknown split direction."
|
|
)
|
|
static let windowUnavailable = String(
|
|
localized: "applescript.error.windowUnavailable",
|
|
defaultValue: "Window is no longer available."
|
|
)
|
|
static let workspaceUnavailable = String(
|
|
localized: "applescript.error.workspaceUnavailable",
|
|
defaultValue: "Workspace is no longer available."
|
|
)
|
|
static let terminalUnavailable = String(
|
|
localized: "applescript.error.terminalUnavailable",
|
|
defaultValue: "Terminal is no longer available."
|
|
)
|
|
static let failedToCreateWindow = String(
|
|
localized: "applescript.error.failedToCreateWindow",
|
|
defaultValue: "Failed to create window."
|
|
)
|
|
static let failedToCreateWorkspace = String(
|
|
localized: "applescript.error.failedToCreateWorkspace",
|
|
defaultValue: "Failed to create workspace."
|
|
)
|
|
static let failedToCreateSplit = String(
|
|
localized: "applescript.error.failedToCreateSplit",
|
|
defaultValue: "Failed to create split."
|
|
)
|
|
}
|
|
|
|
private extension String {
|
|
var fourCharCode: UInt32 {
|
|
utf8.reduce(0) { ($0 << 8) + UInt32($1) }
|
|
}
|
|
}
|
|
|
|
private extension Workspace {
|
|
func scriptingTerminalPanels() -> [TerminalPanel] {
|
|
var results: [TerminalPanel] = []
|
|
var seen: Set<UUID> = []
|
|
|
|
for panelId in sidebarOrderedPanelIds() {
|
|
guard seen.insert(panelId).inserted,
|
|
let terminal = terminalPanel(for: panelId) else {
|
|
continue
|
|
}
|
|
results.append(terminal)
|
|
}
|
|
|
|
let remaining = panels.values
|
|
.compactMap { $0 as? TerminalPanel }
|
|
.sorted { $0.id.uuidString < $1.id.uuidString }
|
|
|
|
for terminal in remaining where seen.insert(terminal.id).inserted {
|
|
results.append(terminal)
|
|
}
|
|
|
|
return results
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
extension NSApplication {
|
|
var isAppleScriptEnabled: Bool {
|
|
GhosttyApp.shared.appleScriptAutomationEnabled()
|
|
}
|
|
|
|
@discardableResult
|
|
func validateScript(command: NSScriptCommand) -> Bool {
|
|
guard isAppleScriptEnabled else {
|
|
command.scriptErrorNumber = errAEEventNotPermitted
|
|
command.scriptErrorString = AppleScriptStrings.disabled
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
@objc(scriptWindows)
|
|
var scriptWindows: [ScriptWindow] {
|
|
guard isAppleScriptEnabled,
|
|
let appDelegate = AppDelegate.shared else {
|
|
return []
|
|
}
|
|
return appDelegate.scriptableMainWindows().map { ScriptWindow(windowId: $0.windowId) }
|
|
}
|
|
|
|
@objc(frontWindow)
|
|
var frontWindow: ScriptWindow? {
|
|
scriptWindows.first
|
|
}
|
|
|
|
@objc(valueInScriptWindowsWithUniqueID:)
|
|
func valueInScriptWindows(uniqueID: String) -> ScriptWindow? {
|
|
guard isAppleScriptEnabled,
|
|
let windowId = UUID(uuidString: uniqueID),
|
|
let appDelegate = AppDelegate.shared,
|
|
appDelegate.scriptableMainWindow(windowId: windowId) != nil else {
|
|
return nil
|
|
}
|
|
return ScriptWindow(windowId: windowId)
|
|
}
|
|
|
|
@objc(terminals)
|
|
var terminals: [ScriptTerminal] {
|
|
guard isAppleScriptEnabled,
|
|
let appDelegate = AppDelegate.shared else {
|
|
return []
|
|
}
|
|
|
|
return appDelegate.scriptableMainWindows()
|
|
.flatMap { state in
|
|
state.tabManager.tabs.flatMap { workspace in
|
|
workspace.scriptingTerminalPanels().map {
|
|
ScriptTerminal(workspaceId: workspace.id, terminalId: $0.id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc(valueInTerminalsWithUniqueID:)
|
|
func valueInTerminals(uniqueID: String) -> ScriptTerminal? {
|
|
guard isAppleScriptEnabled,
|
|
let terminalId = UUID(uuidString: uniqueID),
|
|
let appDelegate = AppDelegate.shared else {
|
|
return nil
|
|
}
|
|
|
|
for state in appDelegate.scriptableMainWindows() {
|
|
for workspace in state.tabManager.tabs where workspace.terminalPanel(for: terminalId) != nil {
|
|
return ScriptTerminal(workspaceId: workspace.id, terminalId: terminalId)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
@objc(handlePerformActionScriptCommand:)
|
|
func handlePerformActionScriptCommand(_ command: NSScriptCommand) -> NSNumber? {
|
|
guard validateScript(command: command) else { return nil }
|
|
|
|
guard let action = command.directParameter as? String else {
|
|
command.scriptErrorNumber = errAEParamMissed
|
|
command.scriptErrorString = AppleScriptStrings.missingAction
|
|
return nil
|
|
}
|
|
|
|
guard let terminal = command.evaluatedArguments?["on"] as? ScriptTerminal else {
|
|
command.scriptErrorNumber = errAEParamMissed
|
|
command.scriptErrorString = AppleScriptStrings.missingTerminalTarget
|
|
return nil
|
|
}
|
|
|
|
return NSNumber(value: terminal.perform(action: action))
|
|
}
|
|
|
|
@objc(handleNewWindowScriptCommand:)
|
|
func handleNewWindowScriptCommand(_ command: NSScriptCommand) -> ScriptWindow? {
|
|
guard validateScript(command: command) else { return nil }
|
|
|
|
guard let appDelegate = AppDelegate.shared else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.failedToCreateWindow
|
|
return nil
|
|
}
|
|
|
|
let windowId = appDelegate.createMainWindow()
|
|
return ScriptWindow(windowId: windowId)
|
|
}
|
|
|
|
@objc(handleNewTabScriptCommand:)
|
|
func handleNewTabScriptCommand(_ command: NSScriptCommand) -> ScriptTab? {
|
|
guard validateScript(command: command) else { return nil }
|
|
|
|
guard let appDelegate = AppDelegate.shared else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.failedToCreateWorkspace
|
|
return nil
|
|
}
|
|
|
|
if let targetWindow = command.evaluatedArguments?["window"] as? ScriptWindow {
|
|
guard let workspaceId = appDelegate.addWorkspace(windowId: targetWindow.windowId, bringToFront: false) else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.failedToCreateWorkspace
|
|
return nil
|
|
}
|
|
return ScriptTab(windowId: targetWindow.windowId, tabId: workspaceId)
|
|
}
|
|
|
|
if let frontWindow = scriptWindows.first,
|
|
let workspaceId = appDelegate.addWorkspace(windowId: frontWindow.windowId, bringToFront: false) {
|
|
return ScriptTab(windowId: frontWindow.windowId, tabId: workspaceId)
|
|
}
|
|
|
|
let windowId = appDelegate.createMainWindow()
|
|
return ScriptWindow(windowId: windowId).selectedTab
|
|
}
|
|
|
|
@objc(handleQuitScriptCommand:)
|
|
func handleQuitScriptCommand(_ command: NSScriptCommand) {
|
|
guard validateScript(command: command) else { return }
|
|
terminate(nil)
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
@objc(CmuxScriptWindow)
|
|
final class ScriptWindow: NSObject {
|
|
let windowId: UUID
|
|
|
|
init(windowId: UUID) {
|
|
self.windowId = windowId
|
|
}
|
|
|
|
private var state: AppDelegate.ScriptableMainWindowState? {
|
|
AppDelegate.shared?.scriptableMainWindow(windowId: windowId)
|
|
}
|
|
|
|
@objc(id)
|
|
var idValue: String {
|
|
guard NSApp.isAppleScriptEnabled else { return "" }
|
|
return windowId.uuidString
|
|
}
|
|
|
|
@objc(title)
|
|
var title: String {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let state else {
|
|
return ""
|
|
}
|
|
|
|
let windowTitle = state.window?.title.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
if !windowTitle.isEmpty {
|
|
return windowTitle
|
|
}
|
|
|
|
return state.tabManager.selectedWorkspace?.title ?? ""
|
|
}
|
|
|
|
@objc(tabs)
|
|
var tabs: [ScriptTab] {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let state else {
|
|
return []
|
|
}
|
|
return state.tabManager.tabs.map { ScriptTab(windowId: windowId, tabId: $0.id) }
|
|
}
|
|
|
|
@objc(selectedTab)
|
|
var selectedTab: ScriptTab? {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let selectedId = state?.tabManager.selectedTabId else {
|
|
return nil
|
|
}
|
|
return ScriptTab(windowId: windowId, tabId: selectedId)
|
|
}
|
|
|
|
@objc(terminals)
|
|
var terminals: [ScriptTerminal] {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let state else {
|
|
return []
|
|
}
|
|
return state.tabManager.tabs.flatMap { workspace in
|
|
workspace.scriptingTerminalPanels().map {
|
|
ScriptTerminal(workspaceId: workspace.id, terminalId: $0.id)
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc(valueInTabsWithUniqueID:)
|
|
func valueInTabs(uniqueID: String) -> ScriptTab? {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let tabId = UUID(uuidString: uniqueID),
|
|
let state,
|
|
state.tabManager.tabs.contains(where: { $0.id == tabId }) else {
|
|
return nil
|
|
}
|
|
return ScriptTab(windowId: windowId, tabId: tabId)
|
|
}
|
|
|
|
@objc(valueInTerminalsWithUniqueID:)
|
|
func valueInTerminals(uniqueID: String) -> ScriptTerminal? {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let terminalId = UUID(uuidString: uniqueID),
|
|
let state else {
|
|
return nil
|
|
}
|
|
|
|
for workspace in state.tabManager.tabs where workspace.terminalPanel(for: terminalId) != nil {
|
|
return ScriptTerminal(workspaceId: workspace.id, terminalId: terminalId)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
@objc(handleActivateWindowCommand:)
|
|
func handleActivateWindow(_ command: NSScriptCommand) -> Any? {
|
|
guard NSApp.validateScript(command: command) else { return nil }
|
|
|
|
guard AppDelegate.shared?.focusScriptableMainWindow(windowId: windowId, bringToFront: true) == true else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.windowUnavailable
|
|
return nil
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
@objc(handleCloseWindowCommand:)
|
|
func handleCloseWindow(_ command: NSScriptCommand) -> Any? {
|
|
guard NSApp.validateScript(command: command) else { return nil }
|
|
|
|
guard let window = state?.window else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.windowUnavailable
|
|
return nil
|
|
}
|
|
|
|
window.performClose(nil)
|
|
return nil
|
|
}
|
|
|
|
override var objectSpecifier: NSScriptObjectSpecifier? {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let appClassDescription = NSApplication.shared.classDescription as? NSScriptClassDescription else {
|
|
return nil
|
|
}
|
|
|
|
return NSUniqueIDSpecifier(
|
|
containerClassDescription: appClassDescription,
|
|
containerSpecifier: nil,
|
|
key: "scriptWindows",
|
|
uniqueID: windowId.uuidString
|
|
)
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
@objc(CmuxScriptTab)
|
|
final class ScriptTab: NSObject {
|
|
let windowId: UUID
|
|
let tabId: UUID
|
|
|
|
init(windowId: UUID, tabId: UUID) {
|
|
self.windowId = windowId
|
|
self.tabId = tabId
|
|
}
|
|
|
|
private var state: AppDelegate.ScriptableMainWindowState? {
|
|
AppDelegate.shared?.scriptableMainWindow(windowId: windowId)
|
|
}
|
|
|
|
private var workspace: Workspace? {
|
|
state?.tabManager.tabs.first(where: { $0.id == tabId })
|
|
}
|
|
|
|
private var window: ScriptWindow {
|
|
ScriptWindow(windowId: windowId)
|
|
}
|
|
|
|
@objc(id)
|
|
var idValue: String {
|
|
guard NSApp.isAppleScriptEnabled else { return "" }
|
|
return tabId.uuidString
|
|
}
|
|
|
|
@objc(title)
|
|
var title: String {
|
|
guard NSApp.isAppleScriptEnabled else { return "" }
|
|
return workspace?.title ?? ""
|
|
}
|
|
|
|
@objc(index)
|
|
var index: Int {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let state,
|
|
let idx = state.tabManager.tabs.firstIndex(where: { $0.id == tabId }) else {
|
|
return 0
|
|
}
|
|
return idx + 1
|
|
}
|
|
|
|
@objc(selected)
|
|
var selected: Bool {
|
|
guard NSApp.isAppleScriptEnabled else { return false }
|
|
return state?.tabManager.selectedTabId == tabId
|
|
}
|
|
|
|
@objc(focusedTerminal)
|
|
var focusedTerminal: ScriptTerminal? {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let terminalId = workspace?.focusedTerminalPanel?.id else {
|
|
return nil
|
|
}
|
|
return ScriptTerminal(workspaceId: tabId, terminalId: terminalId)
|
|
}
|
|
|
|
@objc(terminals)
|
|
var terminals: [ScriptTerminal] {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let workspace else {
|
|
return []
|
|
}
|
|
return workspace.scriptingTerminalPanels().map {
|
|
ScriptTerminal(workspaceId: tabId, terminalId: $0.id)
|
|
}
|
|
}
|
|
|
|
@objc(valueInTerminalsWithUniqueID:)
|
|
func valueInTerminals(uniqueID: String) -> ScriptTerminal? {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let workspace,
|
|
let terminalId = UUID(uuidString: uniqueID),
|
|
workspace.terminalPanel(for: terminalId) != nil else {
|
|
return nil
|
|
}
|
|
return ScriptTerminal(workspaceId: tabId, terminalId: terminalId)
|
|
}
|
|
|
|
@objc(handleSelectTabCommand:)
|
|
func handleSelectTab(_ command: NSScriptCommand) -> Any? {
|
|
guard NSApp.validateScript(command: command) else { return nil }
|
|
|
|
guard let state,
|
|
let workspace else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.workspaceUnavailable
|
|
return nil
|
|
}
|
|
|
|
state.tabManager.selectWorkspace(workspace)
|
|
return nil
|
|
}
|
|
|
|
@objc(handleCloseTabCommand:)
|
|
func handleCloseTab(_ command: NSScriptCommand) -> Any? {
|
|
guard NSApp.validateScript(command: command) else { return nil }
|
|
|
|
guard let state,
|
|
let workspace else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.workspaceUnavailable
|
|
return nil
|
|
}
|
|
|
|
if state.tabManager.tabs.count > 1 {
|
|
state.tabManager.closeWorkspace(workspace)
|
|
return nil
|
|
}
|
|
|
|
guard let window = state.window else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.windowUnavailable
|
|
return nil
|
|
}
|
|
|
|
window.performClose(nil)
|
|
return nil
|
|
}
|
|
|
|
override var objectSpecifier: NSScriptObjectSpecifier? {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let windowClassDescription = window.classDescription as? NSScriptClassDescription,
|
|
let windowSpecifier = window.objectSpecifier else {
|
|
return nil
|
|
}
|
|
|
|
return NSUniqueIDSpecifier(
|
|
containerClassDescription: windowClassDescription,
|
|
containerSpecifier: windowSpecifier,
|
|
key: "tabs",
|
|
uniqueID: tabId.uuidString
|
|
)
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
@objc(CmuxScriptTerminal)
|
|
final class ScriptTerminal: NSObject {
|
|
let workspaceId: UUID
|
|
let terminalId: UUID
|
|
|
|
init(workspaceId: UUID, terminalId: UUID) {
|
|
self.workspaceId = workspaceId
|
|
self.terminalId = terminalId
|
|
}
|
|
|
|
private var state: AppDelegate.ScriptableMainWindowState? {
|
|
AppDelegate.shared?.scriptableMainWindowForTab(workspaceId)
|
|
}
|
|
|
|
private var workspace: Workspace? {
|
|
state?.tabManager.tabs.first(where: { $0.id == workspaceId })
|
|
}
|
|
|
|
private var terminal: TerminalPanel? {
|
|
workspace?.terminalPanel(for: terminalId)
|
|
}
|
|
|
|
@objc(id)
|
|
var stableID: String {
|
|
guard NSApp.isAppleScriptEnabled else { return "" }
|
|
return terminalId.uuidString
|
|
}
|
|
|
|
@objc(title)
|
|
var title: String {
|
|
guard NSApp.isAppleScriptEnabled else { return "" }
|
|
return terminal?.displayTitle ?? ""
|
|
}
|
|
|
|
@objc(workingDirectory)
|
|
var workingDirectory: String {
|
|
guard NSApp.isAppleScriptEnabled else { return "" }
|
|
return terminal?.directory ?? ""
|
|
}
|
|
|
|
func input(text: String) -> Bool {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let terminal else {
|
|
return false
|
|
}
|
|
terminal.sendText(text)
|
|
return true
|
|
}
|
|
|
|
func perform(action: String) -> Bool {
|
|
guard NSApp.isAppleScriptEnabled else { return false }
|
|
return terminal?.performBindingAction(action) ?? false
|
|
}
|
|
|
|
@objc(handleSplitCommand:)
|
|
func handleSplit(_ command: NSScriptCommand) -> Any? {
|
|
guard NSApp.validateScript(command: command) else { return nil }
|
|
|
|
guard let directionCode = command.evaluatedArguments?["direction"] as? UInt32,
|
|
let direction = ScriptSplitDirection(code: directionCode)?.splitDirection else {
|
|
command.scriptErrorNumber = errAEParamMissed
|
|
command.scriptErrorString = AppleScriptStrings.missingSplitDirection
|
|
return nil
|
|
}
|
|
|
|
guard let state,
|
|
let workspace,
|
|
terminal != nil else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.terminalUnavailable
|
|
return nil
|
|
}
|
|
|
|
guard let newPanelId = state.tabManager.newSplit(tabId: workspaceId, surfaceId: terminalId, direction: direction),
|
|
workspace.terminalPanel(for: newPanelId) != nil else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.failedToCreateSplit
|
|
return nil
|
|
}
|
|
|
|
return ScriptTerminal(workspaceId: workspaceId, terminalId: newPanelId)
|
|
}
|
|
|
|
@objc(handleFocusCommand:)
|
|
func handleFocus(_ command: NSScriptCommand) -> Any? {
|
|
guard NSApp.validateScript(command: command) else { return nil }
|
|
|
|
guard let state,
|
|
let workspace,
|
|
terminal != nil else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.terminalUnavailable
|
|
return nil
|
|
}
|
|
|
|
if let app = AppDelegate.shared {
|
|
_ = app.focusScriptableMainWindow(windowId: state.windowId, bringToFront: true)
|
|
}
|
|
state.tabManager.selectWorkspace(workspace)
|
|
workspace.focusPanel(terminalId)
|
|
return nil
|
|
}
|
|
|
|
@objc(handleCloseCommand:)
|
|
func handleClose(_ command: NSScriptCommand) -> Any? {
|
|
guard NSApp.validateScript(command: command) else { return nil }
|
|
|
|
guard let state,
|
|
let workspace,
|
|
terminal != nil else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.terminalUnavailable
|
|
return nil
|
|
}
|
|
|
|
if workspace.panels.count == 1 {
|
|
if state.tabManager.tabs.count > 1 {
|
|
state.tabManager.closeWorkspace(workspace)
|
|
return nil
|
|
}
|
|
|
|
guard let window = state.window else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.windowUnavailable
|
|
return nil
|
|
}
|
|
|
|
window.performClose(nil)
|
|
return nil
|
|
}
|
|
|
|
guard workspace.closePanel(terminalId, force: true) else {
|
|
command.scriptErrorNumber = errAEEventFailed
|
|
command.scriptErrorString = AppleScriptStrings.terminalUnavailable
|
|
return nil
|
|
}
|
|
|
|
AppDelegate.shared?.notificationStore?.clearNotifications(forTabId: workspaceId, surfaceId: terminalId)
|
|
return nil
|
|
}
|
|
|
|
override var objectSpecifier: NSScriptObjectSpecifier? {
|
|
guard NSApp.isAppleScriptEnabled,
|
|
let appClassDescription = NSApplication.shared.classDescription as? NSScriptClassDescription else {
|
|
return nil
|
|
}
|
|
|
|
return NSUniqueIDSpecifier(
|
|
containerClassDescription: appClassDescription,
|
|
containerSpecifier: nil,
|
|
key: "terminals",
|
|
uniqueID: terminalId.uuidString
|
|
)
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
@objc(CmuxScriptInputTextCommand)
|
|
final class ScriptInputTextCommand: NSScriptCommand {
|
|
override func performDefaultImplementation() -> Any? {
|
|
guard NSApp.validateScript(command: self) else { return nil }
|
|
|
|
guard let text = directParameter as? String else {
|
|
scriptErrorNumber = errAEParamMissed
|
|
scriptErrorString = AppleScriptStrings.missingInputText
|
|
return nil
|
|
}
|
|
|
|
guard let terminal = evaluatedArguments?["terminal"] as? ScriptTerminal else {
|
|
scriptErrorNumber = errAEParamMissed
|
|
scriptErrorString = AppleScriptStrings.missingTerminalTarget
|
|
return nil
|
|
}
|
|
|
|
guard terminal.input(text: text) else {
|
|
scriptErrorNumber = errAEEventFailed
|
|
scriptErrorString = AppleScriptStrings.terminalUnavailable
|
|
return nil
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
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: SplitDirection {
|
|
switch self {
|
|
case .right: return .right
|
|
case .left: return .left
|
|
case .down: return .down
|
|
case .up: return .up
|
|
}
|
|
}
|
|
}
|