chore: udpate target
This commit is contained in:
@@ -10,3 +10,6 @@ feat: this is a example feat commit
|
||||
```
|
||||
|
||||
- 每次写完代码都要给我总结你写了什么,为什么这么写,我要怎么看懂你的代码
|
||||
- 像是private的方法,重要/复杂的也添加summary注释
|
||||
- 一些关键代码,特殊的判断原因或者写法之类的,增加行间注释
|
||||
- 如果当前已经在运行了,就不用再次编译检测了
|
||||
|
||||
@@ -1,65 +1,151 @@
|
||||
# TODO
|
||||
|
||||
## Success Criteria
|
||||
## 当前定位
|
||||
|
||||
最终成功应该具备这些能力:
|
||||
TinyTUI 现在已经不是空项目,已经具备一个最小可运行的 C# TUI 类库骨架
|
||||
|
||||
- 能作为一个 C# TUI 类库被其他控制台程序引用。
|
||||
- 能启动和停止终端运行时,并在退出时恢复终端状态。
|
||||
- 能读取键盘输入,并把普通字符、方向键、组合键、回车、退格、Esc 等转换成统一事件。
|
||||
- 能处理粘贴输入,避免大段粘贴被拆成混乱的按键事件。
|
||||
- 能监听终端窗口尺寸变化,并触发重新布局和重新渲染。
|
||||
- 能用组件树描述界面,而不是让组件直接写控制台。
|
||||
- 能支持焦点管理,让当前焦点组件接收输入。
|
||||
- 能渲染基础组件,包括文本、容器、单行输入框、多行编辑器、选择列表和加载状态。
|
||||
- 能支持 overlay 弹层,用于菜单、弹窗、提示框和临时输入。
|
||||
- 能正确显示中文、emoji、ANSI 样式文本,并避免宽度计算错位。
|
||||
- 能进行全量渲染,保证最小版本可以稳定显示。
|
||||
- 能进行差分渲染,只刷新变化的行,减少闪烁。
|
||||
- 能提供一组示例程序,展示输入、编辑、列表选择、overlay 和动态刷新。
|
||||
- 能提供测试覆盖核心模块,包括输入解析、宽度计算、渲染输出和组件行为。
|
||||
- 能在 Windows Terminal / PowerShell 环境下稳定运行。
|
||||
当前目标应该从“搭架子”切换到“补真实终端能力和组件细节”
|
||||
|
||||
## Architecture
|
||||
参考项目是 `tmp/tui`,它已经覆盖了更成熟的终端输入、差分渲染、overlay、编辑器、选择列表、Markdown、虚拟终端测试和图像能力
|
||||
|
||||
整体分成几个大模块:
|
||||
## 已完成
|
||||
|
||||
- STDIO 模块:负责读取键盘输入、监听窗口尺寸变化、管理 raw mode 和生命周期。
|
||||
- STDOUT 模块:负责向终端输出文本和 ANSI 控制序列。
|
||||
- Input 模块:负责把原始输入转换成统一的按键、粘贴、控制事件。
|
||||
- Runtime 模块:负责管理组件树、焦点、事件分发和渲染调度。
|
||||
- Renderer 模块:负责把组件输出同步到终端,先全量渲染,后续升级成差分渲染。
|
||||
- Text Width 模块:负责计算终端显示宽度,处理 ANSI、中文、emoji、截断和换行。
|
||||
- Component 模块:负责提供 Text、Input、Container、Box 等基础 UI 组件。
|
||||
- Overlay 模块:负责弹层显示、遮盖合成、焦点切换和恢复。
|
||||
- Example 模块:负责验证框架 API 和真实交互流程。
|
||||
- Test 模块:负责覆盖输入解析、渲染输出、宽度计算和组件行为。
|
||||
- 已定义核心模块边界:STDIO、STDOUT、Input、Runtime、Renderer、Text、Component、Overlay、Example
|
||||
- 已实现 console 输入输出封装,包括输入事件、窗口尺寸和基础生命周期
|
||||
- 已实现默认输入解析器,支持普通文本、常见方向键、功能键、回车、退格、Esc、bracketed paste
|
||||
- 已实现组件树运行时,支持根组件、焦点组件、输入分发、重新渲染
|
||||
- 已实现全量渲染器
|
||||
- 已实现差分渲染器,支持按行更新和硬件光标定位
|
||||
- 已实现文本宽度模块,能处理 ANSI、OSC、APC、中文、emoji、截断
|
||||
- 已实现基础组件:`Text`、`Container`、`Box`、`Input`
|
||||
- 已实现第一版高级组件:`Editor`、`SelectList`、`Markdown`、`Loader`
|
||||
- 已实现第一版 Overlay 管理器,支持弹层显示、隐藏、合成和焦点恢复
|
||||
- 已更新 Example,启动后能直接展示 Markdown、Loader、SelectList,并通过命令验证 overlay、选择列表和编辑器
|
||||
|
||||
大致依赖方向:
|
||||
## 当前缺口
|
||||
|
||||
```text
|
||||
Example
|
||||
-> Runtime
|
||||
-> Component
|
||||
-> Overlay
|
||||
-> Renderer
|
||||
-> STDOUT
|
||||
-> Text Width
|
||||
-> Input
|
||||
-> STDIO
|
||||
```
|
||||
- 输入层还缺 `tmp/tui/src/stdin-buffer.ts` 这种输入缓冲器,真实终端可能把 escape sequence 拆成多个 chunk
|
||||
- 输入层还缺 Kitty keyboard protocol / modifyOtherKeys 这类高级键盘协议协商,组合键识别还不够完整
|
||||
- Runtime 的焦点模型比较简单,还没有焦点栈、非捕获 overlay、overlay focus/unfocus 这类能力
|
||||
- Overlay 目前固定居中,缺少 `width`、`minWidth`、`maxHeight`、`anchor`、`row`、`col`、`margin`、`visible`、`nonCapturing` 等选项
|
||||
- Overlay 合成还比较简单,需要继续处理 ANSI/OSC 样式文本、宽字符边界、终端边缘覆盖和底层样式泄漏
|
||||
- Editor 目前只是基础多行输入,还缺历史记录、撤销重做、kill ring、词级移动、自动补全、粘贴摘要、软换行和更完整的光标布局
|
||||
- SelectList 目前只是字符串列表,还缺 value/label/description、过滤、描述列、滚动提示、wrap-around、选择变化事件和主题样式
|
||||
- Markdown 目前只是轻量纯文本转换,还缺真正 token 解析、行内样式、代码块、链接、引用块、列表缩进、文本换行和缓存
|
||||
- Text Width 还需要补 grapheme cluster 级别处理,尤其是 ZWJ emoji、regional indicator、variation selector、tab、ANSI 包裹换行
|
||||
- 渲染层还缺虚拟终端测试和复杂回归场景,比如 viewport 覆盖、短内容覆盖长内容、样式泄漏、宽字符边界
|
||||
- 示例目前只有一个 Example,后续需要拆成多个真实场景示例
|
||||
- 暂时不做测试项目,当前阶段先用 Example 手动验证功能方向,等功能形态稳定后再补测试
|
||||
|
||||
## Steps
|
||||
## 下一阶段优先级
|
||||
|
||||
1. 定义核心模块边界:STDIO/STDOUT、输入解析、运行时、渲染器、组件、示例。
|
||||
2. 实现终端 IO 模块,统一封装控制台输入、输出、尺寸和生命周期。
|
||||
3. 实现输入解析模块,把原始按键和控制序列转换成框架事件。
|
||||
4. 实现组件运行时,管理组件树、焦点、事件分发和渲染请求。
|
||||
5. 实现基础渲染器,先完成全量渲染和清屏重画。
|
||||
6. 实现文本宽度模块,统一处理 ANSI、中文、emoji 和截断。
|
||||
7. 实现差分渲染器,只更新变化的终端行。
|
||||
8. 实现基础组件集,包括 Text、Input、Container 和 Box。
|
||||
9. 实现 Overlay 模块,支持弹层显示、遮盖合成和焦点切换。
|
||||
10. 实现高级组件集,包括 Editor、SelectList、Markdown 和 Loader。
|
||||
11. 完善示例程序,用真实场景验证输入、渲染、焦点和 overlay。
|
||||
12. 补齐测试和基准,覆盖输入解析、宽度计算、渲染输出和组件行为。
|
||||
### 1. 输入缓冲和按键解析
|
||||
|
||||
先做这个,因为后续 Editor、SelectList、Overlay 都依赖稳定输入
|
||||
|
||||
- 新增 `StdinBuffer`,负责把 stdin chunk 拆成完整输入序列
|
||||
- 支持完整 CSI、OSC、DCS、APC、SS3、Meta key 序列判断
|
||||
- 支持 bracketed paste 跨 chunk 收集
|
||||
- 避免 ESC 被误判,给不完整 escape sequence 设置短超时或明确 fallback
|
||||
- 补充组合键名称表达,例如 `ctrl+x`、`alt+x`、`shift+tab`
|
||||
- 参考 `tmp/tui/src/stdin-buffer.ts`、`tmp/tui/src/keys.ts`、`tmp/tui/test/stdin-buffer.test.ts`、`tmp/tui/test/keys.test.ts`
|
||||
|
||||
### 2. Overlay 选项和焦点策略
|
||||
|
||||
Overlay 是菜单、提示、选择列表、编辑器弹窗的基础
|
||||
|
||||
- 新增 `OverlayOptions`
|
||||
- 支持宽度百分比、最小宽度、最大高度
|
||||
- 支持 anchor 定位:center、top-left、top-right、bottom-left、bottom-right、top-center、bottom-center、left-center、right-center
|
||||
- 支持 row / column 绝对值和百分比定位
|
||||
- 支持 margin
|
||||
- 支持 visible 条件
|
||||
- 支持 nonCapturing overlay,不抢焦点但参与渲染
|
||||
- 支持 overlay handle 的 `Hide`、`SetHidden`、`Focus`、`Unfocus`、`IsFocused`
|
||||
- 参考 `tmp/tui/src/tui.ts`、`tmp/tui/test/overlay-options.test.ts`、`tmp/tui/test/overlay-non-capturing.test.ts`
|
||||
|
||||
### 3. Editor 升级
|
||||
|
||||
Editor 是后续交互体验的核心组件
|
||||
|
||||
- 增加提交事件和取消事件的清晰语义
|
||||
- 支持历史记录浏览
|
||||
- 支持 Home / End / Ctrl+A / Ctrl+E
|
||||
- 支持词级移动和删除
|
||||
- 支持 undo / redo
|
||||
- 支持 kill ring
|
||||
- 支持软换行和按终端宽度布局
|
||||
- 支持粘贴大段文本时生成 paste marker 或摘要
|
||||
- 支持 autocomplete provider 和补全列表 overlay
|
||||
- 参考 `tmp/tui/src/components/editor.ts`、`tmp/tui/src/undo-stack.ts`、`tmp/tui/src/kill-ring.ts`、`tmp/tui/src/word-navigation.ts`、`tmp/tui/src/autocomplete.ts`
|
||||
|
||||
### 4. SelectList 升级
|
||||
|
||||
SelectList 应该从简单字符串列表升级成可用于命令菜单
|
||||
|
||||
- 引入 `SelectItem`,包含 `Value`、`Label`、`Description`
|
||||
- 支持 filter
|
||||
- 支持 selected index 外部设置
|
||||
- 支持 selection changed 回调
|
||||
- 支持描述列布局
|
||||
- 支持滚动窗口和滚动提示
|
||||
- 支持上下循环选择
|
||||
- 支持空结果展示
|
||||
- 参考 `tmp/tui/src/components/select-list.ts`、`tmp/tui/test/select-list.test.ts`
|
||||
|
||||
### 5. Markdown 升级
|
||||
|
||||
Markdown 暂时只做展示,不要急着做完整渲染器,但需要比当前纯字符串替换更可靠
|
||||
|
||||
- 支持标题层级
|
||||
- 支持无序列表和有序列表
|
||||
- 支持引用块
|
||||
- 支持代码块和行内代码
|
||||
- 支持链接文本和 URL 展示
|
||||
- 支持粗体、斜体、删除线、下划线的 ANSI 样式
|
||||
- 支持按终端宽度换行
|
||||
- 支持缓存,避免每帧重复解析
|
||||
- 参考 `tmp/tui/src/components/markdown.ts`、`tmp/tui/test/markdown.test.ts`
|
||||
|
||||
### 6. 文本宽度和换行
|
||||
|
||||
这是渲染正确性的底座,需要在测试前先稳定实现
|
||||
|
||||
- 用 grapheme cluster 而不是单个 Rune 计算宽度
|
||||
- 处理 ZWJ emoji、肤色、variation selector、regional indicator
|
||||
- 处理 tab 宽度
|
||||
- 提供 `VisibleWidth`、`TruncateToWidth`、`SliceByColumn`、`WrapTextWithAnsi`
|
||||
- 截断和换行时保持 ANSI / OSC 序列不被破坏
|
||||
- 参考 `tmp/tui/src/utils.ts`、`tmp/tui/test/truncate-to-width.test.ts`、`tmp/tui/test/wrap-ansi.test.ts`、`tmp/tui/test/regression-regional-indicator-width.test.ts`
|
||||
|
||||
### 7. 渲染回归场景
|
||||
|
||||
等输入、overlay、文本宽度更稳定后再做测试项目
|
||||
|
||||
- 引入虚拟终端或 fake terminal output
|
||||
- 覆盖全量渲染和差分渲染
|
||||
- 覆盖短行覆盖长行
|
||||
- 覆盖 resize 后 full redraw
|
||||
- 覆盖 cursor marker 提取
|
||||
- 覆盖 overlay 覆盖 styled base content
|
||||
- 覆盖宽字符在边界截断
|
||||
- 参考 `tmp/tui/test/virtual-terminal.ts`、`tmp/tui/test/tui-render.test.ts`、`tmp/tui/test/viewport-overwrite-repro.ts`
|
||||
|
||||
## 暂缓
|
||||
|
||||
- Kitty 图像协议和 terminal image
|
||||
- 主题系统
|
||||
- Benchmark
|
||||
- 正式测试项目
|
||||
- NuGet 包发布配置
|
||||
|
||||
## 近期执行顺序
|
||||
|
||||
1. 实现 `StdinBuffer` 并接入 `ConsoleTerminalInput`
|
||||
2. 扩展 `DefaultInputParser` 的组合键解析
|
||||
3. 升级 `OverlayManager` 的 `OverlayOptions`
|
||||
4. 用 Example 验证输入拆包、粘贴、overlay 定位和焦点恢复
|
||||
5. 升级 `Editor` 的历史记录和词级移动
|
||||
6. 升级 `SelectList` 的 item model、filter 和描述列
|
||||
7. 升级 Markdown 和 Text Width
|
||||
8. 功能形态稳定后再引入测试项目
|
||||
|
||||
@@ -113,18 +113,12 @@ public sealed class TuiRuntime : ITuiRuntime
|
||||
_terminalInput.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理终端原始输入并分发为标准化输入事件
|
||||
/// </summary>
|
||||
private void OnDataReceived(object? sender, string data)
|
||||
{
|
||||
foreach (var inputEvent in _inputParser.Parse(data))
|
||||
Dispatch(inputEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将尺寸变化转成 Runtime 内部输入事件
|
||||
/// </summary>
|
||||
private void OnResized(object? sender, TerminalSize size)
|
||||
=> Dispatch(new TuiInputEvent(TuiInputEventKind.Resize, $"{size.Columns}x{size.Rows}"));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user