Terminal surface

TerminalViewState

Main SwiftUI state container. Available on iOS 15, macOS 13, and Mac Catalyst 15.

@MainActor
public final class TerminalViewState: ObservableObject {
    @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 }
    public internal(set) weak var surface: TerminalSurface? { get }

    @Published public var configuration: TerminalSurfaceOptions
    public var onClose: ((Bool) -> Void)?
    @Published public internal(set) var controller: TerminalController { get }

    public var renderedConfig: String { get }
    public var effectiveColorScheme: TerminalColorScheme { get }
    public var theme: TerminalTheme { get }
    public var terminalConfiguration: TerminalConfiguration { get }

    public func send(_ text: String) -> Bool
    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, but controller-owned configuration changes are observable through TerminalViewState mutation methods. SwiftUI integrations should mutate through the view state rather than the controller directly.

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 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 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 TerminalSurfaceTextSelectionRequestDelegate {
    func terminalDidRequestTextSelection(_ request: TerminalTextSelectionRequest)
}

@MainActor public protocol TerminalSurfaceLifecycleDelegate {
    func terminalDidAttachSurface(_ surface: TerminalSurface)
    func terminalDidDetachSurface()
}