c435df9fcd
ci / restore build format test pack (push) Failing after 22s
- migrate remaining text and component smoke assertions into TinyTUI.Tests - remove legacy TextChecks and ComponentChecks projects from solution - update README test guidance to use the unified xUnit suite
118 lines
5.2 KiB
Markdown
118 lines
5.2 KiB
Markdown
# TinyTUI
|
|
|
|
TinyTUI 是一个面向 .NET 的轻量终端 UI 框架。当前版本已经具备组件树、终端会话、输入解析、keybinding、差分渲染、overlay、ANSI 感知文本工具、自动补全基础、终端图像 fallback 和 xUnit 回归测试基础。
|
|
|
|
它的设计目标是让应用代码只描述组件和状态变化,框架负责把组件输出合成为终端行数组,并通过渲染器同步到真实终端。
|
|
|
|
## 快速开始
|
|
|
|
当前仓库使用 .NET 10。
|
|
|
|
```powershell
|
|
dotnet restore ttui.slnx
|
|
dotnet run --project src/Example/Example.csproj
|
|
```
|
|
|
|
最小应用结构如下:
|
|
|
|
```csharp
|
|
using TinyTUI.Components;
|
|
using TinyTUI.Input;
|
|
using TinyTUI.Rendering;
|
|
using TinyTUI.Runtime;
|
|
using TinyTUI.Terminal;
|
|
using TinyTUI.Text;
|
|
|
|
using var terminal = new ConsoleTerminalSession();
|
|
var parser = new DefaultInputParser();
|
|
var textMeasurer = new TerminalTextMeasurer();
|
|
var renderer = new DifferentialRenderer(terminal, textMeasurer);
|
|
using var runtime = new TuiRuntime(terminal, parser, renderer);
|
|
|
|
var input = new Input(textMeasurer) { Prompt = "> " };
|
|
var done = new ManualResetEventSlim();
|
|
|
|
input.OnSubmitted = value =>
|
|
{
|
|
runtime.Add(new Text($"submitted: {value}"));
|
|
input.Clear();
|
|
};
|
|
input.OnCanceled = done.Set;
|
|
|
|
runtime.Add(new Text("TinyTUI demo"));
|
|
runtime.Add(input);
|
|
runtime.SetFocus(input);
|
|
|
|
runtime.Start();
|
|
done.Wait();
|
|
runtime.Stop();
|
|
```
|
|
|
|
## 核心 API
|
|
|
|
`ITerminalSession` 是终端生命周期入口,负责输入事件、输出、尺寸、bracketed paste、光标和终端状态恢复。真实程序通常使用 `ConsoleTerminalSession`,测试可以实现同一个接口。
|
|
|
|
`TuiRuntime` 管理组件树、焦点、overlay、输入分发和渲染请求。应用通过 `Add`、`Remove`、`SetFocus`、`ShowOverlay`、`HideOverlay` 和 `RequestRender` 驱动界面。
|
|
|
|
`IComponent` 是最小组件接口,`Render(int width)` 返回终端行数组。组件输出的每一行都应该控制在 `width` 内;如果需要截断、切片或换行,优先使用 `ITextMeasurer`。
|
|
|
|
`IInputComponent` 表示可接收输入的组件,`IFocusableComponent` 表示渲染时可能输出硬件光标 marker 的组件。焦点由 runtime 统一设置,组件只根据 `Focused` 决定是否输出 marker。
|
|
|
|
`DifferentialRenderer` 维护上一帧、视口和变化范围,默认使用 synchronized output、行尾 SGR reset 和 OSC 8 reset 降低闪烁和样式泄漏。`FullScreenRenderer` 适合需要全量刷新策略的场景。
|
|
|
|
## 组件和能力
|
|
|
|
内置组件包括 `Text`、`Markdown`、`Box`、`Spacer`、`TruncatedText`、`Input`、`Editor`、`SelectList`、`Loader`、`CancellableLoader` 和 `Image`。
|
|
|
|
Overlay 通过 `runtime.ShowOverlay(component, options)` 显示,支持 anchor、百分比宽度、最大高度、margin 和 non-capturing tooltip。Overlay 在虚拟行数组阶段合成,因此仍复用同一套差分渲染路径。
|
|
|
|
Keybinding 通过 `KeybindingRegistry` 和 `TuiKeybindings` 描述动作到按键的映射。组件内部优先匹配动作名,而不是直接散落比较具体按键字符串。
|
|
|
|
文本工具集中在 `TerminalTextMeasurer`,提供 ANSI/OSC 感知的宽度计算、截断、按列切片和换行。自定义组件不要使用 `string.Length` 判断终端宽度。
|
|
|
|
自动补全通过 `IAutocompleteProvider` 扩展。当前 `Editor` 已支持 slash command provider,并复用 `SelectList` 展示候选。
|
|
|
|
图像能力通过 `ITerminalImageService` 选择 Kitty、iTerm2 或文本 fallback。渲染管线会识别图像行,避免把大段协议序列当普通文本截断。
|
|
|
|
## 自定义组件约束
|
|
|
|
自定义组件应该只返回行数组,不要直接写 stdout。终端写入、清屏、光标移动和 synchronized output 都应该交给 renderer。
|
|
|
|
如果组件会缓存渲染结果,需要实现 `Invalidate()` 并在内容、宽度、主题或焦点变化后清理缓存。
|
|
|
|
如果组件包含输入框或编辑器并需要 IME 光标定位,容器组件应该实现 `IFocusableComponent` 并把 `Focused` 传给内部输入组件。
|
|
|
|
## 工程命令
|
|
|
|
```powershell
|
|
dotnet restore ttui.slnx
|
|
dotnet build ttui.slnx --configuration Release --no-restore
|
|
dotnet format ttui.slnx --verify-no-changes --no-restore
|
|
dotnet test ttui.slnx --configuration Release --no-build
|
|
dotnet pack src/TinyTUI/TinyTUI.csproj --configuration Release --no-build
|
|
```
|
|
|
|
`test/TinyTUI.Tests` 是统一的 xUnit 回归测试项目,覆盖文本、输入、overlay、renderer、组件、自动补全和终端图像相关回归。
|
|
|
|
## 压力示例
|
|
|
|
仓库提供不依赖真实终端交互的 benchmark/pressure console 项目,用于观察渲染管线在典型高压输入下是否稳定。
|
|
|
|
```powershell
|
|
dotnet run --project benchmark/TinyTUI.Benchmarks/TinyTUI.Benchmarks.csproj --configuration Release
|
|
```
|
|
|
|
当前场景覆盖大文本测量和截断、Markdown render、overlay compose、差分渲染频繁刷新,以及 Kitty/iTerm2 图像行检测保护。该项目会写出每个场景的耗时、分配量和关键计数,只作为本地观察入口,不替代 xUnit 回归测试,也不作为默认 CI test gate。
|
|
|
|
## 调试
|
|
|
|
渲染器支持环境变量调试日志:
|
|
|
|
```powershell
|
|
$env:TINYTUI_DEBUG_REDRAW = "1"
|
|
$env:TINYTUI_DEBUG_RENDER = "1"
|
|
dotnet run --project src/Example/Example.csproj
|
|
```
|
|
|
|
日志默认写入临时目录下的 `tinytui` 子目录。
|