Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,10 @@ final class MacTerminalTransport: NSObject, TerminalTransport, @preconcurrency L
ProcessInfo.processInfo.environment["SHELL"] ?? "/bin/zsh"
}

var termProgramVersion: String? {
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
}

func defaultEnvironment() -> [String: String] {
ProcessInfo.processInfo.environment
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ public protocol TerminalTransport: AnyObject {
var processID: Int32? { get }
var shellName: String { get }
var nativeView: AnyObject { get }
/// Product version advertised through `TERM_PROGRAM_VERSION`. Windows
/// already reports the packaged app version; hosts that cannot expose one
/// keep the variable unset.
var termProgramVersion: String? { get }
var onTermination: ((Int32?) -> Void)? { get set }
/// Raw bytes received from the child process before terminal emulation.
/// Hosts may mirror this output into another product surface.
Expand Down Expand Up @@ -87,6 +91,7 @@ public protocol TerminalTransport: AnyObject {
}

public extension TerminalTransport {
var termProgramVersion: String? { nil }
func stopAndWait() async { stop() }
func runningPrograms() -> [TerminalRunningProgram] { [] }
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ public final class TerminalSession: ObservableObject, Identifiable {
environment["TERM"] = "xterm-256color"
environment["COLORTERM"] = "truecolor"
environment["TERM_PROGRAM"] = "Lithe"
// Direct assignment drops any value inherited from the outer terminal when the transport cannot report one.
environment["TERM_PROGRAM_VERSION"] = transport.termProgramVersion
for change in changes {
if let value = change.value {
environment[change.name] = value
Expand Down
36 changes: 35 additions & 1 deletion macos/Tests/LitheTerminalModuleTests/TerminalModuleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,36 @@ struct TerminalModuleTests {
#expect(!output.joined().contains("�"))
feature.stopAllSessions()
}

@Test
func interactiveShellEnvironmentReportsTermProgramVersion() {
let transport = TestTransport()
transport.termProgramVersion = "9.9.9"
let feature = TerminalFeatureModel(terminalFactory: { transport })
defer { feature.stopAllSessions() }
feature.createSession(in: URL(fileURLWithPath: "/workspace"), shellPath: "/bin/zsh")
#expect(transport.shellEnvironments.last?["TERM_PROGRAM"] == "Lithe")
#expect(transport.shellEnvironments.last?["TERM_PROGRAM_VERSION"] == "9.9.9")
}

@Test
func interactiveShellEnvironmentOmitsUnknownTermProgramVersion() {
let transport = TestTransport()
let feature = TerminalFeatureModel(terminalFactory: { transport })
defer { feature.stopAllSessions() }
feature.createSession(in: URL(fileURLWithPath: "/workspace"), shellPath: "/bin/zsh")
#expect(transport.shellEnvironments.last?["TERM_PROGRAM_VERSION"] == nil)
}

@Test
func interactiveShellEnvironmentClearsInheritedTermProgramVersionWhenUnknown() {
let transport = TestTransport()
transport.inheritedEnvironment["TERM_PROGRAM_VERSION"] = "3.5.13"
let feature = TerminalFeatureModel(terminalFactory: { transport })
defer { feature.stopAllSessions() }
feature.createSession(in: URL(fileURLWithPath: "/workspace"), shellPath: "/bin/zsh")
#expect(transport.shellEnvironments.last?["TERM_PROGRAM_VERSION"] == nil)
}
}

@MainActor
Expand All @@ -208,7 +238,10 @@ private final class TestTransport: TerminalTransport {
var isRunning = false
var processID: Int32? { isRunning ? 1234 : nil }
var shellName = "Shell"
var termProgramVersion: String?
var shellStarts: [String] = []
var shellEnvironments: [[String: String]] = []
var inheritedEnvironment: [String: String] = ["REMOVE_ME": "old"]
var startError: Error?
var onTermination: ((Int32?) -> Void)?
var onOutput: ((Data) -> Void)?
Expand All @@ -221,9 +254,10 @@ private final class TestTransport: TerminalTransport {
var sentInputs: [String] = []
var outputOnStart: String?
func defaultShellPath() -> String { "/bin/zsh" }
func defaultEnvironment() -> [String: String] { ["REMOVE_ME": "old"] }
func defaultEnvironment() -> [String: String] { inheritedEnvironment }
func start(workingDirectory: String, shellPath: String, environment: [String: String]) throws {
shellStarts.append(shellPath)
shellEnvironments.append(environment)
if let startError { throw startError }
isRunning = true
}
Expand Down
6 changes: 4 additions & 2 deletions shared/platform-feature-matrix/features/terminal-shell.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"macos/Sources/Lithe/Models/Settings/AppSettings.swift",
"macos/Sources/Lithe/Platform/MacOS/Terminal/MacTerminalTransport.swift",
"macos/Tests/LitheTests/TerminalScrollbackSettingsTests.swift",
"macos/Tests/LitheTests/SettingsSearchVocabularyTests.swift"
"macos/Tests/LitheTests/SettingsSearchVocabularyTests.swift",
"macos/Sources/LitheTerminalModule/Runtime/TerminalSession.swift",
"macos/Tests/LitheTerminalModuleTests/TerminalModuleTests.swift"
],
"implementationStatus": "implemented",
"verificationStatus": "pending"
Expand All @@ -28,5 +30,5 @@
"verificationStatus": "pending"
},
"owner": "Terminal",
"verification": "验证设置页默认 Shell 选项与终端「新建终端」菜单检测到的 Shell 一致、可选 Git Bash 并生效;macOS 新建终端下拉框复用 Project 下拉框的共享菜单样式,菜单操作与原有 Shell 选择、重新检测功能一致;验证环境变量、工作目录和不可用 Shell 的提示。 设置页终端分组新增回滚行数配置(默认 2000,范围 100–50000,步进 500),读取、写入、恢复默认均做上下限夹取,对新建会话生效(TerminalScrollbackSettingsTests);设置搜索按界面名称 Terminal scrollback/终端回滚行数/行数 均可命中终端页(SettingsSearchVocabularyTests)。"
"verification": "验证设置页默认 Shell 选项与终端「新建终端」菜单检测到的 Shell 一致、可选 Git Bash 并生效;macOS 新建终端下拉框复用 Project 下拉框的共享菜单样式,菜单操作与原有 Shell 选择、重新检测功能一致;验证环境变量、工作目录和不可用 Shell 的提示。 设置页终端分组新增回滚行数配置(默认 2000,范围 100–50000,步进 500),读取、写入、恢复默认均做上下限夹取,对新建会话生效(TerminalScrollbackSettingsTests);设置搜索按界面名称 Terminal scrollback/终端回滚行数/行数 均可命中终端页(SettingsSearchVocabularyTests)。 macOS 终端环境随 TERM_PROGRAM=Lithe 一并导出 TERM_PROGRAM_VERSION(取应用打包版本,无法取得时不写入),与 Windows 端一致,供工具按版本门控终端能力(TerminalModuleTests)。"
}
Loading