Files
terminalX/vendor/libghostty-spm/Sources/GhosttyTerminal/Surface/TerminalSurfaceViewDelegate.swift
kid aa92d0e676 初始提交:terminalX 可运行态(M0/M1/M1.5 已真机验证)
- M0: libghostty SSH 终端(渲染/输入/连接)+ 白屏修复(OutputGate) + 会话状态机/自动重连
- M1: tsnet 用户态组网 + SSH-over-tsnet(fd 桥),shell 级真机验证;R5(Go+gvisor+C+++Swift 同进程) retire
- M1.5: tmux -CC 原生 tab(MVP)
- 结构: packages/(TXCore·TXTransport), apps/TerminalX, vendor/(libghostty-spm/libssh2/mbedtls/tsnet-bridge), artifacts/
- 文档: CLAUDE.md + docs/HANDOFF.md(新会话入口)
- 环境: 认证代理→依赖 vendor 本地化;Go 在 ~/.local/go;仅模拟器/未签名
- 待续: M2 mosh, tmux 多 pane, M4 安全(host key/SE)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 10:20:46 +08:00

169 lines
5.4 KiB
Swift

//
// TerminalSurfaceViewDelegate.swift
// libghostty-spm
//
// Created by Lakr233 on 2026/3/16.
//
import CoreGraphics
import Foundation
import GhosttyKit
@MainActor
public protocol TerminalSurfaceViewDelegate: AnyObject {}
@MainActor
public protocol TerminalSurfaceTitleDelegate: TerminalSurfaceViewDelegate {
func terminalDidChangeTitle(_ title: String)
}
@MainActor
public protocol TerminalSurfaceGridResizeDelegate: TerminalSurfaceViewDelegate {
func terminalDidResize(_ size: TerminalGridMetrics)
}
@MainActor
public protocol TerminalSurfaceResizeDelegate: TerminalSurfaceViewDelegate {
func terminalDidResize(columns: Int, rows: Int)
}
@MainActor
public protocol TerminalSurfaceFocusDelegate: TerminalSurfaceViewDelegate {
func terminalDidChangeFocus(_ focused: Bool)
}
@MainActor
public protocol TerminalSurfaceBellDelegate: TerminalSurfaceViewDelegate {
func terminalDidRingBell()
}
@MainActor
public protocol TerminalSurfaceCloseDelegate: TerminalSurfaceViewDelegate {
func terminalDidClose(processAlive: Bool)
}
// MARK: - Extended action delegates
/// State of an OSC 9;4 / DECSET progress report.
public enum TerminalProgressState: Sendable {
case remove
case set
case error
case indeterminate
case pause
init?(_ raw: ghostty_action_progress_report_state_e) {
switch raw {
case GHOSTTY_PROGRESS_STATE_REMOVE: self = .remove
case GHOSTTY_PROGRESS_STATE_SET: self = .set
case GHOSTTY_PROGRESS_STATE_ERROR: self = .error
case GHOSTTY_PROGRESS_STATE_INDETERMINATE: self = .indeterminate
case GHOSTTY_PROGRESS_STATE_PAUSE: self = .pause
default: return nil
}
}
}
/// OSC 9;4 progress report (state + 0-100 percent, nil percent when the
/// emitter didn't provide one e.g. INDETERMINATE / REMOVE).
@MainActor
public protocol TerminalSurfaceProgressReportDelegate: TerminalSurfaceViewDelegate {
func terminalDidReportProgress(state: TerminalProgressState, percent: Int?)
}
/// Fires when a shell-integration-aware command exits. `exitCode` is nil
/// when not reported; `duration` is the wall clock in nanoseconds.
@MainActor
public protocol TerminalSurfaceCommandFinishedDelegate: TerminalSurfaceViewDelegate {
func terminalDidFinishCommand(exitCode: Int?, durationNanos: UInt64)
}
/// OSC 9 (iTerm2) / OSC 777 (rxvt-unicode) desktop notification.
/// Empty title/body surface as empty strings rather than nil.
@MainActor
public protocol TerminalSurfaceDesktopNotificationDelegate: TerminalSurfaceViewDelegate {
func terminalDidRequestDesktopNotification(title: String, body: String)
}
public enum TerminalOpenURLKind: Sendable {
case unknown
case text
case html
init(_ raw: ghostty_action_open_url_kind_e) {
switch raw {
case GHOSTTY_ACTION_OPEN_URL_KIND_TEXT: self = .text
case GHOSTTY_ACTION_OPEN_URL_KIND_HTML: self = .html
default: self = .unknown
}
}
}
/// User activated (cmd-clicked) a hyperlink inside the terminal grid.
@MainActor
public protocol TerminalSurfaceOpenURLDelegate: TerminalSurfaceViewDelegate {
func terminalDidRequestOpenURL(_ url: String, kind: TerminalOpenURLKind)
}
/// Mouse hovered over a recognized hyperlink. nil = hover ended / link lost.
@MainActor
public protocol TerminalSurfaceHoverLinkDelegate: TerminalSurfaceViewDelegate {
func terminalDidUpdateHoverLink(_ url: String?)
}
/// OSC 7 working-directory update.
@MainActor
public protocol TerminalSurfacePwdDelegate: TerminalSurfaceViewDelegate {
func terminalDidChangeWorkingDirectory(_ path: String)
}
/// Scrollbar geometry reported by the terminal, in rows: `offset` rows are
/// scrolled off above the viewport, `len` rows are visible, out of `total`
/// rows of content (scrollback + screen).
public struct TerminalScrollbar: Equatable, Sendable {
public let total: UInt64
public let offset: UInt64
public let len: UInt64
public init(total: UInt64, offset: UInt64, len: UInt64) {
self.total = total
self.offset = offset
self.len = len
}
}
/// The scrollbar geometry changed (the viewport scrolled or the content grew).
@MainActor
public protocol TerminalSurfaceScrollbarDelegate: TerminalSurfaceViewDelegate {
func terminalDidUpdateScrollbar(_ scrollbar: TerminalScrollbar)
}
/// User long-pressed to request a selection-page presentation.
public struct TerminalTextSelectionRequest: Sendable {
/// Viewport text snapshot. Lines separated by `\n`.
public let text: String
/// Recommended pre-selection range in UTF-16 units, suitable for direct
/// assignment to `UITextView.selectedRange`. `nil` means the host should
/// `selectAll` instead.
public let anchorRange: NSRange?
/// Long-press point in the terminal view's coordinate space (points).
/// Hosts may use this as a popover anchor.
public let sourcePoint: CGPoint
}
@MainActor
public protocol TerminalSurfaceTextSelectionRequestDelegate: TerminalSurfaceViewDelegate {
func terminalDidRequestTextSelection(_ request: TerminalTextSelectionRequest)
}
/// Notifies a delegate when the underlying ``TerminalSurface`` is created or
/// torn down. Useful when a consumer needs surface-level APIs (e.g.
/// ``TerminalSurface/sendText(_:)``) reachable from outside the platform view.
@MainActor
public protocol TerminalSurfaceLifecycleDelegate: TerminalSurfaceViewDelegate {
func terminalDidAttachSurface(_ surface: TerminalSurface)
func terminalDidDetachSurface()
}