Files

124 lines
4.6 KiB
Swift

// SPDX-FileCopyrightText: 2026 Kaede Akino
// SPDX-License-Identifier: GPL-3.0-only
import Foundation
/// Runtime identity, deliberately unrelated to session ownership or recovery.
public nonisolated struct TerminalContextIdentity: Hashable, Sendable {
public let backend: String
public let server: String
public let session: String
public let pane: String
public let shellInstance: String
public init(backend: String, server: String, session: String, pane: String, shellInstance: String) {
self.backend = backend
self.server = server
self.session = session
self.pane = pane
self.shellInstance = shellInstance
}
}
public nonisolated struct TerminalContextCapabilities: OptionSet, Sendable, Equatable {
public let rawValue: Int
public init(rawValue: Int) { self.rawValue = rawValue }
public static let directory = Self(rawValue: 1 << 0)
public static let commandLifecycle = Self(rawValue: 1 << 1)
public static let readDraft = Self(rawValue: 1 << 2)
public static let replaceDraft = Self(rawValue: 1 << 3)
}
public nonisolated enum TerminalDirectorySource: Sendable, Equatable {
case shell, nativePane, process
}
public nonisolated enum TerminalRuntimeIssue: Sendable, Equatable {
case clientUnbound, paneAmbiguous, directoryUnavailable, shellIntegrationUnavailable
case unsupportedVersion, nestedMultiplexer, inspectionUnavailable
}
public nonisolated struct TerminalShellContext: Sendable, Equatable {
public let identity: TerminalContextIdentity
public var shell: String
/// Last cwd reported by this shell instance, independent of foreground/input readiness.
public var directory: String?
public var directorySource: TerminalDirectorySource?
public var home: String?
public var historyPath: String?
public var promptReady: Bool
public var sequence: UInt64
public var capabilities: TerminalContextCapabilities
/// Nil means unverified; an empty path explicitly disables file-backed history.
public var historySource: ShellHistorySource? {
guard let shell = ShellHistorySource.Shell(rawValue: shell),
let historyPath, historyPath.isEmpty || historyPath.hasPrefix("/"),
!historyPath.contains("\0")
else { return nil }
return .init(shell: shell, path: historyPath)
}
public init(
identity: TerminalContextIdentity, shell: String, directory: String?, home: String?,
promptReady: Bool, sequence: UInt64, capabilities: TerminalContextCapabilities, historyPath: String? = nil,
directorySource: TerminalDirectorySource? = .shell
) {
self.identity = identity
self.shell = shell
self.directory = directory
self.directorySource = directory == nil ? nil : directorySource
self.home = home
self.historyPath = historyPath
self.promptReady = promptReady
self.sequence = sequence
self.capabilities = capabilities
}
}
public nonisolated struct TerminalContextEvent: Sendable, Equatable {
public enum Payload: Sendable, Equatable {
case commandStarted(String)
case commandFinished(Int32, duration: TimeInterval?)
case promptReady
case directory(String)
case draft(request: String, value: String)
}
public let context: TerminalContextIdentity
public let sequence: UInt64
public let payload: Payload
public init(context: TerminalContextIdentity, sequence: UInt64, payload: Payload) {
self.context = context
self.sequence = sequence
self.payload = payload
}
}
public nonisolated struct TerminalRuntimeUpdate: Sendable, Equatable {
public enum Status: Sendable, Equatable {
case ordinary, multiplexer, unknown, unavailable
}
public var status: Status
public var clientIdentity: String?
public var active: TerminalContextIdentity?
public var contexts: [TerminalShellContext]
public var events: [TerminalContextEvent]
public var backend: SessionPersistenceBackendID?
public var issue: TerminalRuntimeIssue?
public init(
status: Status, clientIdentity: String? = nil, active: TerminalContextIdentity? = nil,
contexts: [TerminalShellContext] = [], events: [TerminalContextEvent] = [],
backend: SessionPersistenceBackendID? = nil, issue: TerminalRuntimeIssue? = nil
) {
self.status = status
self.clientIdentity = clientIdentity
self.active = active
self.contexts = contexts
self.events = events
self.backend = backend
self.issue = issue
}
}