初始提交: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>
This commit is contained in:
40
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/GhosttyConfigRenderer.swift
vendored
Normal file
40
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/GhosttyConfigRenderer.swift
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// GhosttyConfigRenderer.swift
|
||||
// libghostty-spm
|
||||
//
|
||||
// Created by Lakr233 on 2026/3/17.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum GhosttyConfigRenderer {
|
||||
static func render(
|
||||
baseContents: String,
|
||||
configuration: TerminalConfiguration,
|
||||
theme: TerminalConfiguration
|
||||
) -> String {
|
||||
var sections: [String] = []
|
||||
|
||||
let normalizedBase = normalize(baseContents)
|
||||
if !normalizedBase.isEmpty {
|
||||
sections.append(normalizedBase)
|
||||
}
|
||||
|
||||
let configurationLines = configuration.commands.map(\.renderedLine)
|
||||
if !configurationLines.isEmpty {
|
||||
sections.append(configurationLines.joined(separator: "\n"))
|
||||
}
|
||||
|
||||
let themeLines = theme.commands.map(\.renderedLine)
|
||||
if !themeLines.isEmpty {
|
||||
sections.append(themeLines.joined(separator: "\n"))
|
||||
}
|
||||
|
||||
guard !sections.isEmpty else { return "" }
|
||||
return sections.joined(separator: "\n") + "\n"
|
||||
}
|
||||
|
||||
private static func normalize(_ contents: String) -> String {
|
||||
contents.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
}
|
||||
}
|
||||
21
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/TerminalColorScheme+SwiftUI.swift
vendored
Normal file
21
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/TerminalColorScheme+SwiftUI.swift
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// TerminalColorScheme+SwiftUI.swift
|
||||
// libghostty-spm
|
||||
//
|
||||
// Created by Lakr233 on 2026/3/17.
|
||||
//
|
||||
|
||||
#if canImport(SwiftUI)
|
||||
import SwiftUI
|
||||
|
||||
extension TerminalColorScheme {
|
||||
init(_ colorScheme: ColorScheme) {
|
||||
switch colorScheme {
|
||||
case .dark:
|
||||
self = .dark
|
||||
default:
|
||||
self = .light
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
18
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/TerminalColorScheme.swift
vendored
Normal file
18
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/TerminalColorScheme.swift
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// TerminalColorScheme.swift
|
||||
// libghostty-spm
|
||||
//
|
||||
|
||||
import GhosttyKit
|
||||
|
||||
public enum TerminalColorScheme: Sendable {
|
||||
case light
|
||||
case dark
|
||||
|
||||
var ghosttyValue: ghostty_color_scheme_e {
|
||||
switch self {
|
||||
case .light: GHOSTTY_COLOR_SCHEME_LIGHT
|
||||
case .dark: GHOSTTY_COLOR_SCHEME_DARK
|
||||
}
|
||||
}
|
||||
}
|
||||
360
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/TerminalConfiguration.swift
vendored
Normal file
360
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/TerminalConfiguration.swift
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
//
|
||||
// TerminalConfiguration.swift
|
||||
// libghostty-spm
|
||||
//
|
||||
// Created by Lakr233 on 2026/3/17.
|
||||
//
|
||||
|
||||
public enum TerminalCursorStyle: String, Sendable, Hashable {
|
||||
case block
|
||||
case bar
|
||||
case underline
|
||||
}
|
||||
|
||||
public enum TerminalConfigCommand: Sendable, Hashable {
|
||||
// Font
|
||||
case fontFamily(String)
|
||||
case fontSize(Float)
|
||||
case fontThicken(Bool)
|
||||
case fontThickenStrength(Int)
|
||||
|
||||
// Cursor
|
||||
case cursorStyle(TerminalCursorStyle)
|
||||
case cursorStyleBlink(Bool)
|
||||
case cursorColor(String)
|
||||
case cursorText(String)
|
||||
case cursorOpacity(Double)
|
||||
|
||||
// Colors
|
||||
case background(String)
|
||||
case foreground(String)
|
||||
case selectionBackground(String)
|
||||
case selectionForeground(String)
|
||||
case boldColor(String)
|
||||
case palette(index: Int, color: String)
|
||||
case minimumContrast(Double)
|
||||
|
||||
// Background
|
||||
case backgroundOpacity(Double)
|
||||
case backgroundBlur(Int)
|
||||
|
||||
// Layout
|
||||
case windowPaddingX(Int)
|
||||
case windowPaddingY(Int)
|
||||
|
||||
/// Escape hatch
|
||||
case custom(key: String, value: String)
|
||||
|
||||
var renderedLine: String {
|
||||
switch self {
|
||||
case let .fontFamily(value):
|
||||
"font-family = \(value)"
|
||||
|
||||
case let .fontSize(value):
|
||||
"font-size = \(value.formatted(.number.precision(.fractionLength(0 ... 2))))"
|
||||
|
||||
case let .fontThicken(enabled):
|
||||
"font-thicken = \(enabled)"
|
||||
|
||||
case let .fontThickenStrength(value):
|
||||
"font-thicken-strength = \(value)"
|
||||
|
||||
case let .cursorStyle(style):
|
||||
"cursor-style = \(style.rawValue)"
|
||||
|
||||
case let .cursorStyleBlink(enabled):
|
||||
"cursor-style-blink = \(enabled)"
|
||||
|
||||
case let .cursorColor(value):
|
||||
"cursor-color = \(value)"
|
||||
|
||||
case let .cursorText(value):
|
||||
"cursor-text = \(value)"
|
||||
|
||||
case let .cursorOpacity(value):
|
||||
"cursor-opacity = \(value.formatted(.number.precision(.fractionLength(0 ... 3))))"
|
||||
|
||||
case let .background(value):
|
||||
"background = \(value)"
|
||||
|
||||
case let .foreground(value):
|
||||
"foreground = \(value)"
|
||||
|
||||
case let .selectionBackground(value):
|
||||
"selection-background = \(value)"
|
||||
|
||||
case let .selectionForeground(value):
|
||||
"selection-foreground = \(value)"
|
||||
|
||||
case let .boldColor(value):
|
||||
"bold-color = \(value)"
|
||||
|
||||
case let .palette(index, color):
|
||||
"palette = \(index)=\(color)"
|
||||
|
||||
case let .minimumContrast(value):
|
||||
"minimum-contrast = \(value.formatted(.number.precision(.fractionLength(0 ... 2))))"
|
||||
|
||||
case let .backgroundOpacity(value):
|
||||
"background-opacity = \(value.formatted(.number.precision(.fractionLength(0 ... 3))))"
|
||||
|
||||
case let .backgroundBlur(value):
|
||||
"background-blur = \(value)"
|
||||
|
||||
case let .windowPaddingX(value):
|
||||
"window-padding-x = \(value)"
|
||||
|
||||
case let .windowPaddingY(value):
|
||||
"window-padding-y = \(value)"
|
||||
|
||||
case let .custom(key, value):
|
||||
"\(key) = \(value)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct TerminalConfiguration: Sendable, Hashable {
|
||||
public struct Builder {
|
||||
var commands: [TerminalConfigCommand] = []
|
||||
|
||||
public init() {}
|
||||
|
||||
init(commands: [TerminalConfigCommand]) {
|
||||
self.commands = commands
|
||||
}
|
||||
|
||||
/// Font
|
||||
public mutating func withFontFamily(_ value: String) {
|
||||
commands.append(.fontFamily(value))
|
||||
}
|
||||
|
||||
public mutating func withFontSize(_ value: Float) {
|
||||
commands.append(.fontSize(value))
|
||||
}
|
||||
|
||||
public mutating func withFontThicken(_ enabled: Bool) {
|
||||
commands.append(.fontThicken(enabled))
|
||||
}
|
||||
|
||||
public mutating func withFontThickenStrength(_ value: Int) {
|
||||
commands.append(.fontThickenStrength(value))
|
||||
}
|
||||
|
||||
/// Cursor
|
||||
public mutating func withCursorStyle(_ style: TerminalCursorStyle) {
|
||||
commands.append(.cursorStyle(style))
|
||||
}
|
||||
|
||||
public mutating func withCursorStyleBlink(_ enabled: Bool) {
|
||||
commands.append(.cursorStyleBlink(enabled))
|
||||
}
|
||||
|
||||
public mutating func withCursorColor(_ value: String) {
|
||||
commands.append(.cursorColor(value))
|
||||
}
|
||||
|
||||
public mutating func withCursorText(_ value: String) {
|
||||
commands.append(.cursorText(value))
|
||||
}
|
||||
|
||||
public mutating func withCursorOpacity(_ value: Double) {
|
||||
commands.append(.cursorOpacity(value))
|
||||
}
|
||||
|
||||
/// Colors
|
||||
public mutating func withBackground(_ value: String) {
|
||||
commands.append(.background(value))
|
||||
}
|
||||
|
||||
public mutating func withForeground(_ value: String) {
|
||||
commands.append(.foreground(value))
|
||||
}
|
||||
|
||||
public mutating func withSelectionBackground(_ value: String) {
|
||||
commands.append(.selectionBackground(value))
|
||||
}
|
||||
|
||||
public mutating func withSelectionForeground(_ value: String) {
|
||||
commands.append(.selectionForeground(value))
|
||||
}
|
||||
|
||||
public mutating func withBoldColor(_ value: String) {
|
||||
commands.append(.boldColor(value))
|
||||
}
|
||||
|
||||
public mutating func withPalette(_ index: Int, color: String) {
|
||||
commands.append(.palette(index: index, color: color))
|
||||
}
|
||||
|
||||
public mutating func withMinimumContrast(_ value: Double) {
|
||||
commands.append(.minimumContrast(value))
|
||||
}
|
||||
|
||||
/// Background
|
||||
public mutating func withBackgroundOpacity(_ value: Double) {
|
||||
commands.append(.backgroundOpacity(value))
|
||||
}
|
||||
|
||||
public mutating func withBackgroundBlur(_ value: Int) {
|
||||
commands.append(.backgroundBlur(value))
|
||||
}
|
||||
|
||||
/// Layout
|
||||
public mutating func withWindowPaddingX(_ value: Int) {
|
||||
commands.append(.windowPaddingX(value))
|
||||
}
|
||||
|
||||
public mutating func withWindowPaddingY(_ value: Int) {
|
||||
commands.append(.windowPaddingY(value))
|
||||
}
|
||||
|
||||
/// Escape hatch
|
||||
public mutating func withCustom(_ key: String, _ value: String) {
|
||||
commands.append(.custom(key: key, value: value))
|
||||
}
|
||||
}
|
||||
|
||||
let commands: [TerminalConfigCommand]
|
||||
|
||||
public init() {
|
||||
commands = []
|
||||
}
|
||||
|
||||
public init(configure: (inout Builder) -> Void) {
|
||||
self.init(startingFrom: .init(), configure: configure)
|
||||
}
|
||||
|
||||
public init(
|
||||
startingFrom base: TerminalConfiguration,
|
||||
configure: (inout Builder) -> Void
|
||||
) {
|
||||
var builder = Builder(commands: base.commands)
|
||||
configure(&builder)
|
||||
commands = builder.commands
|
||||
}
|
||||
|
||||
public func appending(_ command: TerminalConfigCommand) -> TerminalConfiguration {
|
||||
TerminalConfiguration(commands: commands + [command])
|
||||
}
|
||||
|
||||
// MARK: - Font
|
||||
|
||||
public func fontFamily(_ value: String) -> TerminalConfiguration {
|
||||
appending(.fontFamily(value))
|
||||
}
|
||||
|
||||
public func fontSize(_ value: Float) -> TerminalConfiguration {
|
||||
appending(.fontSize(value))
|
||||
}
|
||||
|
||||
public func fontThicken(_ enabled: Bool) -> TerminalConfiguration {
|
||||
appending(.fontThicken(enabled))
|
||||
}
|
||||
|
||||
public func fontThickenStrength(_ value: Int) -> TerminalConfiguration {
|
||||
appending(.fontThickenStrength(value))
|
||||
}
|
||||
|
||||
// MARK: - Cursor
|
||||
|
||||
public func cursorStyle(_ style: TerminalCursorStyle) -> TerminalConfiguration {
|
||||
appending(.cursorStyle(style))
|
||||
}
|
||||
|
||||
public func cursorStyleBlink(_ enabled: Bool) -> TerminalConfiguration {
|
||||
appending(.cursorStyleBlink(enabled))
|
||||
}
|
||||
|
||||
public func cursorColor(_ value: String) -> TerminalConfiguration {
|
||||
appending(.cursorColor(value))
|
||||
}
|
||||
|
||||
public func cursorText(_ value: String) -> TerminalConfiguration {
|
||||
appending(.cursorText(value))
|
||||
}
|
||||
|
||||
public func cursorOpacity(_ value: Double) -> TerminalConfiguration {
|
||||
appending(.cursorOpacity(value))
|
||||
}
|
||||
|
||||
// MARK: - Colors
|
||||
|
||||
public func background(_ value: String) -> TerminalConfiguration {
|
||||
appending(.background(value))
|
||||
}
|
||||
|
||||
public func foreground(_ value: String) -> TerminalConfiguration {
|
||||
appending(.foreground(value))
|
||||
}
|
||||
|
||||
public func selectionBackground(_ value: String) -> TerminalConfiguration {
|
||||
appending(.selectionBackground(value))
|
||||
}
|
||||
|
||||
public func selectionForeground(_ value: String) -> TerminalConfiguration {
|
||||
appending(.selectionForeground(value))
|
||||
}
|
||||
|
||||
public func boldColor(_ value: String) -> TerminalConfiguration {
|
||||
appending(.boldColor(value))
|
||||
}
|
||||
|
||||
public func palette(_ index: Int, color: String) -> TerminalConfiguration {
|
||||
appending(.palette(index: index, color: color))
|
||||
}
|
||||
|
||||
public func minimumContrast(_ value: Double) -> TerminalConfiguration {
|
||||
appending(.minimumContrast(value))
|
||||
}
|
||||
|
||||
// MARK: - Background
|
||||
|
||||
public func backgroundOpacity(_ value: Double) -> TerminalConfiguration {
|
||||
appending(.backgroundOpacity(value))
|
||||
}
|
||||
|
||||
public func backgroundBlur(_ value: Int) -> TerminalConfiguration {
|
||||
appending(.backgroundBlur(value))
|
||||
}
|
||||
|
||||
// MARK: - Layout
|
||||
|
||||
public func windowPaddingX(_ value: Int) -> TerminalConfiguration {
|
||||
appending(.windowPaddingX(value))
|
||||
}
|
||||
|
||||
public func windowPaddingY(_ value: Int) -> TerminalConfiguration {
|
||||
appending(.windowPaddingY(value))
|
||||
}
|
||||
|
||||
// MARK: - Escape Hatch
|
||||
|
||||
public func custom(_ key: String, _ value: String) -> TerminalConfiguration {
|
||||
appending(.custom(key: key, value: value))
|
||||
}
|
||||
|
||||
// MARK: - Defaults
|
||||
|
||||
public static let `default` = TerminalConfiguration { builder in
|
||||
builder.withCursorStyle(.block)
|
||||
builder.withCursorStyleBlink(true)
|
||||
#if os(iOS)
|
||||
builder.withFontSize(10)
|
||||
#else
|
||||
builder.withFontSize(14)
|
||||
#endif
|
||||
builder.withFontThicken(true)
|
||||
}
|
||||
|
||||
public var rendered: String {
|
||||
commands.map(\.renderedLine).joined(separator: "\n")
|
||||
}
|
||||
|
||||
var isEmpty: Bool {
|
||||
commands.isEmpty
|
||||
}
|
||||
|
||||
init(commands: [TerminalConfigCommand]) {
|
||||
self.commands = commands
|
||||
}
|
||||
}
|
||||
70
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/TerminalTheme+Defaults.swift
vendored
Normal file
70
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/TerminalTheme+Defaults.swift
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// TerminalTheme+Defaults.swift
|
||||
// libghostty-spm
|
||||
//
|
||||
|
||||
public extension TerminalTheme {
|
||||
/// Afterglow (dark) + Alabaster (light) default theme.
|
||||
static let `default` = TerminalTheme(
|
||||
light: .alabaster,
|
||||
dark: .afterglow
|
||||
)
|
||||
}
|
||||
|
||||
public extension TerminalConfiguration {
|
||||
/// Alabaster — light terminal theme.
|
||||
///
|
||||
/// Background: #F7F7F7, Foreground: #000000
|
||||
static let alabaster = TerminalConfiguration { builder in
|
||||
builder.withBackground("F7F7F7")
|
||||
builder.withForeground("000000")
|
||||
builder.withCursorColor("007ACC")
|
||||
builder.withSelectionBackground("C9D0D9")
|
||||
// Normal colors (0-7)
|
||||
builder.withPalette(0, color: "#000000")
|
||||
builder.withPalette(1, color: "#AA3731")
|
||||
builder.withPalette(2, color: "#448C27")
|
||||
builder.withPalette(3, color: "#CB8800")
|
||||
builder.withPalette(4, color: "#325CC0")
|
||||
builder.withPalette(5, color: "#7A3E9D")
|
||||
builder.withPalette(6, color: "#0083B2")
|
||||
builder.withPalette(7, color: "#F7F7F7")
|
||||
// Bright colors (8-15)
|
||||
builder.withPalette(8, color: "#777777")
|
||||
builder.withPalette(9, color: "#F03E31")
|
||||
builder.withPalette(10, color: "#60CB00")
|
||||
builder.withPalette(11, color: "#FFBC5D")
|
||||
builder.withPalette(12, color: "#007ACC")
|
||||
builder.withPalette(13, color: "#E64CE6")
|
||||
builder.withPalette(14, color: "#00AACB")
|
||||
builder.withPalette(15, color: "#F7F7F7")
|
||||
}
|
||||
|
||||
/// Afterglow — dark terminal theme.
|
||||
///
|
||||
/// Background: #212121, Foreground: #D0D0D0
|
||||
static let afterglow = TerminalConfiguration { builder in
|
||||
builder.withBackground("212121")
|
||||
builder.withForeground("D0D0D0")
|
||||
builder.withCursorColor("D0D0D0")
|
||||
builder.withSelectionBackground("303030")
|
||||
// Normal colors (0-7)
|
||||
builder.withPalette(0, color: "#151515")
|
||||
builder.withPalette(1, color: "#AC4142")
|
||||
builder.withPalette(2, color: "#7E8E50")
|
||||
builder.withPalette(3, color: "#E4B567")
|
||||
builder.withPalette(4, color: "#6C99BB")
|
||||
builder.withPalette(5, color: "#9F4E86")
|
||||
builder.withPalette(6, color: "#7DD5CF")
|
||||
builder.withPalette(7, color: "#D0D0D0")
|
||||
// Bright colors (8-15)
|
||||
builder.withPalette(8, color: "#505050")
|
||||
builder.withPalette(9, color: "#AC4142")
|
||||
builder.withPalette(10, color: "#7E8E50")
|
||||
builder.withPalette(11, color: "#E4B567")
|
||||
builder.withPalette(12, color: "#6C99BB")
|
||||
builder.withPalette(13, color: "#9F4E86")
|
||||
builder.withPalette(14, color: "#7DD5CF")
|
||||
builder.withPalette(15, color: "#F5F5F5")
|
||||
}
|
||||
}
|
||||
32
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/TerminalTheme.swift
vendored
Normal file
32
vendor/libghostty-spm/Sources/GhosttyTerminal/Configuration/TerminalTheme.swift
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// TerminalTheme.swift
|
||||
// libghostty-spm
|
||||
//
|
||||
// Created by Lakr233 on 2026/3/17.
|
||||
//
|
||||
|
||||
public struct TerminalTheme: Sendable, Hashable {
|
||||
public var light: TerminalConfiguration
|
||||
public var dark: TerminalConfiguration
|
||||
|
||||
public init(
|
||||
light: TerminalConfiguration = .init(),
|
||||
dark: TerminalConfiguration = .init()
|
||||
) {
|
||||
self.light = light
|
||||
self.dark = dark
|
||||
}
|
||||
|
||||
var isEmpty: Bool {
|
||||
light.isEmpty && dark.isEmpty
|
||||
}
|
||||
|
||||
func configuration(for colorScheme: TerminalColorScheme) -> TerminalConfiguration {
|
||||
switch colorScheme {
|
||||
case .light:
|
||||
light
|
||||
case .dark:
|
||||
dark
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user