Files
BakNRet/docs/adr/0010-zero-dependency-tui.md
T
Shuery 60f2ae3e0f docs: TUI 与入口重组的设计记录(4 条 ADR + 验收锚点)
grilling 三轮把设计树走完了,这里把它落成文件,避免决策只活在对话里。

ADR-0010 零依赖自研 TUI:三个候选库全部实测排除 —— ConsoleGuiTools 的 PSGallery 元数据声明最低 7.2(5.1 装不上);Spectre.Console 0.49.1 能在 5.1 加载但要塞 4 个第三方 DLL 且不支持鼠标;Terminal.Gui 1.15.0 能反射接线到真的渲染出窗口,但 Application.Shutdown() 在两端都抛 NRE。同时记下两条实测坑:无控制台时 $Host.UI.SupportsVirtualTerminal 会撒谎返回 True(第一道闸门必须是 [Console]::IsOutputRedirected),以及 5.1 的 RawUI.LengthInBufferCells 对中文返回 2、对边框字符返回 6(都不能用来排版)。

ADR-0011 进度回调这个例外:它是注入点不是状态,无头路径为 $null 时行为与今天完全一致。

ADR-0012 入口改名与垫片:这次留垫片而 Common.psm1 直接删,是因为前者是外部接口(断了是静默没用)后者是内部实现(断了当场报错)。并纠正了自己的一个伪前提 —— 本机实测没有注册任何 BakNRet 计划任务。

ADR-0013 TUI 写配置:外科式改写 + 校验通过才原子替换。硬事实是 SoftwareCatalog.psd1 根本不能被 Import-PowerShellDataFile 读入(动态表达式),任何"解析成对象再序列化"的方案都会毁掉表达式与注释。

.scratch/tui/spec.md 是这次改造的验收锚点:9 条已定决策 + 三轮的判据 + 风险表。

验收:Parse 两版仍绿。
2026-09-27 15:27:01 +08:00

35 lines
2.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TUI 用零依赖自研,不引入任何 TUI 库
三个候选库**全部实测排除**(不是偏好,是硬障碍):
- **`Microsoft.PowerShell.ConsoleGuiTools`(`Out-ConsoleGridView`)**:PSGallery 元数据声明
`PowerShellVersion = 7.2`,**5.1 装不上**。
- **`Spectre.Console` 0.49.1(netstandard2.0)**:能在 5.1 上加载并渲染,但必须往仓库塞
**4 个第三方 DLL**(`System.Memory` / `System.Runtime.CompilerServices.Unsafe` /
`System.Buffers` / `System.Numerics.Vectors`)——直接违反 README 的"运行备份/恢复不需要任何
模块"承诺。而且它**不支持鼠标**。(最新稳定版 0.57.2 还要多两个依赖,所以连版本都得钉在 0.49.1。)
- **`Terminal.Gui` 1.15.0(net472)**:反射接线后 `Window` + `Label` + `Button` 在 5.1 与 7 上
**真的渲染出来了**,但 `Application.Init()` 在这个版本没有无参重载,`NetMainLoop` 是 `internal`,
且 **`Application.Shutdown()` 在两端都抛 `NullReferenceException`** —— 不能用于生产。
所以自研,只用四样东西:`$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')`、
`[Console]::SetCursorPosition`、`Write-Host -ForegroundColor`、自算的 `Get-CellWidth`。
零依赖承诺因此保住;代价是**不支持鼠标、不做复杂控件**。
## 两条必须记住、都实测过的坑
**一、无控制台时 `$Host.UI.SupportsVirtualTerminal` 会撒谎。** 它返回 `True`,而同一时刻
`GetConsoleMode` 已经因句柄无效而失败;`[Console]::SetCursorPosition` / `WindowWidth` /
`KeyAvailable` 全部抛异常;`$Host.UI.RawUI.WindowSize` 不抛错但**静默返回假的 `160x40`**。所以:
- 唯一可靠的第一道闸门是 **`[Console]::IsOutputRedirected`**,不是那个属性;
- **TUI 的异常绝不改退出码** —— 退出码只属于 `$failed` 语义(计划任务靠它判断成败)。
**二、中文列宽必须自己算。** `.Length` 是 UTF-16 code unit(中文 1 个 char、2 列);而 5.1 的
`$Host.UI.RawUI.LengthInBufferCells('中文')` 返回 **2**(把中文当单列)、对边框字符返回 **6**(把
制表符当宽字符)——**5.1 上绝对不能拿它排版**,7 上它是对的,所以这个坑只在一边出现、更危险。
自建的 East-Asian-Wide 表必须覆盖全角拉丁、半角片假名(后者是 1 列)、emoji(代理对)。
另注:VT 在本机**默认已启用**(新 conhost 与 Windows Terminal 的 `STDOUT mode` 都是 `0x7`),
所以彩色与光标定位不需要 `SetConsoleMode`;但代码里保留"无 VT 时退化"的分支以防老环境。