Terminal Surface
TerminalViewState
Main SwiftUI state container. Available on iOS 15, macOS 13, Mac Catalyst 15, and visionOS 1.
@MainActor
public final class TerminalViewState: ObservableObject {
public convenience init()
public convenience init(configFilePath: String?)
public init(
configSource: TerminalController.ConfigSource = .none,
theme: TerminalTheme = .default,
terminalConfiguration: TerminalConfiguration = .init()
)
public init(controller: TerminalController)
@Published public internal(set) var title: String { get }
@Published public internal(set) var surfaceSize: TerminalGridMetrics? { get }
@Published public internal(set) var isFocused: Bool { get }
@Published public internal(set) var bellCount: Int { get }
@Published public internal(set) var lastBellAt: Date? { get }
@Published public internal(set) var lastDesktopNotificationTitle: String? { get }
@Published public internal(set) var lastDesktopNotificationBody: String? { get }
@Published public internal(set) var lastDesktopNotificationAt: Date? { get }
@Published public internal(set) var workingDirectory: String? { get }
@Published public internal(set) var lastCommandExitCode: Int? { get }
@Published public internal(set) var lastCommandDurationNanos: UInt64? { get }
@Published public internal(set) var scrollbar: TerminalScrollbar? { get }
public internal(set) weak var surface: TerminalSurface? { get }
@Published public var configuration: TerminalSurfaceOptions
/// False stops rendering for a surface kept mounted but hidden; the
/// grid, scrollback, and session are kept.
@Published public var isSurfaceVisible: Bool
public var onClose: ((Bool) -> Void)?
@Published public internal(set) var controller: TerminalController { get }
/// The platform view presenting this state; nil while none does.
public var attachedPlatformView: TerminalView? { get }
/// Factory for a TerminalView subclass; read once, when the surface
/// view is made.
public var makePlatformView: (@MainActor () -> TerminalView)?
#if canImport(UIKit)
#if !targetEnvironment(macCatalyst)
/// nil shows TerminalInputAccessoryItem.defaultItems; [] hides the bar.
@Published public var inputAccessoryItems: [TerminalInputAccessoryItem]?
#endif
#endif
/// Presents OSC 52 reads/writes and flagged pastes; nil denies a
/// program's request silently and allows a user paste.
public var onClipboardConfirmationRequest: ((TerminalClipboardConfirmationRequest) -> Void)?
/// The URL of the highlighted link under the pointer, nil as it leaves;
/// called before the sendMousePos that found it returns.
public var onHoverLink: ((String?) -> Void)?
/// A cmd-clicked link; true when the host opened it. nil (or false)
/// leaves it to Ghostty, which opens no terminal link on macOS or iOS.
public var onOpenURL: ((_ url: String, _ kind: TerminalOpenURLKind) -> Bool)?
public var renderedConfig: String { get }
public var effectiveColorScheme: TerminalColorScheme { get }
public var theme: TerminalTheme { get }
public var terminalConfiguration: TerminalConfiguration { get }
public func paste(text: String) -> Bool
public func sendKey(_ press: TerminalKeyPress) -> Bool
public func sendKey(_ key: TerminalKey, modifiers: TerminalInputModifiers = []) -> Bool
@available(*, deprecated, renamed: "paste(text:)")
public func send(_ text: String) -> Bool
public func requestFocus()
public func performBindingAction(_ action: String) -> Bool
public func jumpToPrompt(by offset: Int16) -> Bool
public func scrollToRow(_ row: UInt) -> Bool
public var isMouseCaptured: Bool { get }
public func sendMousePos(x: Double, y: Double, modifiers: TerminalInputModifiers = [])
public func sendMouseButton(
state: ghostty_input_mouse_state_e,
button: ghostty_input_mouse_button_e,
modifiers: TerminalInputModifiers = []
) -> Bool
public func sendMouseScroll(
x: Double,
y: Double,
mods: TerminalScrollModifiers = TerminalScrollModifiers(precision: true)
)
public func adopt(colorScheme: ColorScheme)
public func adopt(terminalColorScheme colorScheme: TerminalColorScheme)
public func setTheme(_ theme: TerminalTheme) -> Bool
public func setTerminalConfiguration(_ configuration: TerminalConfiguration) -> Bool
}
controller exposes a projected publisher for source compatibility. SwiftUI integrations should observe configuration changes through TerminalViewState and mutate the view state rather than the controller.
TerminalSurfaceView
public struct TerminalSurfaceView: View {
public init(context: TerminalViewState)
}
TerminalView
#if canImport(UIKit)
public typealias TerminalView = UITerminalView
#elseif canImport(AppKit)
public typealias TerminalView = AppTerminalView
#endif
TerminalController
@MainActor
public final class TerminalController {
public enum ConfigSource: Sendable, Hashable {
case none
case file(String)
case generated(String)
}
public var currentConfigSource: ConfigSource { get }
public var renderedConfig: String { get }
public private(set) var terminalConfiguration: TerminalConfiguration { get }
public private(set) var theme: TerminalTheme { get }
public private(set) var effectiveColorScheme: TerminalColorScheme { get }
public internal(set) var lastConfigurationIssue: String? { get }
public static let shared: TerminalController
/// The default configuration.
public convenience init()
/// A fully custom configuration, rendered as the config source.
public convenience init(
configuration: TerminalConfiguration,
theme: TerminalTheme = .default
)
/// Commands composed on top of the default configuration.
public convenience init(
theme: TerminalTheme = .default,
configure: (inout TerminalConfiguration.Builder) -> Void
)
/// Loads the configuration from a file; nil means no file.
public convenience init(
configFilePath: String?,
theme: TerminalTheme = .default
)
/// Low-level initialiser for full control over the config source.
public init(
configSource: ConfigSource = .none,
theme: TerminalTheme = .default,
terminalConfiguration: TerminalConfiguration = .init()
)
public func setColorScheme(_ scheme: TerminalColorScheme)
public func setTheme(_ theme: TerminalTheme) -> Bool
public func setTerminalConfiguration(_ configuration: TerminalConfiguration) -> Bool
public func tick()
}
InMemoryTerminalSession
public final class InMemoryTerminalSession: @unchecked Sendable {
public init(
write: @escaping @Sendable (Data) -> Void,
resize: @escaping @Sendable (InMemoryTerminalViewport) -> Void
)
public func readViewportText() -> String?
public func receive(_ data: Data)
public func receive(_ string: String)
public func receiveReplay(_ data: Data)
@discardableResult public func discardPendingOutput() -> Int
public func sendInput(_ data: Data)
public func finish(exitCode: UInt32, runtimeMilliseconds: UInt64)
}
Delegates
@MainActor public protocol TerminalSurfaceTitleDelegate {
func terminalDidChangeTitle(_ title: String)
}
@MainActor public protocol TerminalSurfaceGridResizeDelegate {
func terminalDidResize(_ size: TerminalGridMetrics)
}
@MainActor public protocol TerminalSurfaceBellDelegate {
func terminalDidRingBell()
}
@MainActor public protocol TerminalSurfaceCloseDelegate {
func terminalDidClose(processAlive: Bool)
}
@MainActor public protocol TerminalSurfaceLifecycleDelegate {
func terminalDidAttachSurface(_ surface: TerminalSurface)
func terminalDidDetachSurface()
}
// Takes every link: Ghostty is told the host opened it.
@MainActor public protocol TerminalSurfaceOpenURLDelegate {
func terminalDidRequestOpenURL(_ url: String, kind: TerminalOpenURLKind)
}
// Decides per link; false leaves it to Ghostty's opener.
@MainActor public protocol TerminalSurfaceOpenURLHandlingDelegate {
func terminalShouldHandleOpenURL(_ url: String, kind: TerminalOpenURLKind) -> Bool
}