aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-07-21 22:44:49 +0800
committer魏曹先生 <1992414357@qq.com>2026-07-21 22:44:49 +0800
commit368ababb633453b2be6c9f207ed4584341c7768b (patch)
tree9b35bb1cb75056f3d64e1a321f5d1e898db66cb3
parent83ba4cd9e9df069e3002e19cfb252e65aabe6eab (diff)
docs(spec): update scroll margin to 2 and clarify CJK/IME handling
-rw-r--r--ANSI-DRAW.md86
1 files changed, 49 insertions, 37 deletions
diff --git a/ANSI-DRAW.md b/ANSI-DRAW.md
index 8695754..45f049d 100644
--- a/ANSI-DRAW.md
+++ b/ANSI-DRAW.md
@@ -23,7 +23,11 @@
2. 为每个模块编写测试(测试核心逻辑:光标移动、滚动检查、命令解析、ANSI 解析和序列化的对称性、各个编辑模式的行为)
3. 执行 `cargo build`、`cargo test`,保证能构建且测试全部通过
4. 执行 `cargo clippy -- -D warnings` 检查代码质量,修复所有警告直到输出为空。不允许添加任何 clippy 抑制属性
-5. 如果你有子 Agent 能力,生成两个子 Agent,分别对代码做 Review。Review 的重点:是否违反本规范中的硬性约束,是否存在遗漏的边界情况
+5. 使用子 Agent 进行 Review(如果可用)。这一步**非常重要**——你写完代码后会陷入「实现者视角」,对自己的决策有路径依赖,看不见盲区。子 Agent 没有写过这些代码,能**换一个视角**审视你的工作,发现你视而不见的问题。具体做法:
+ - 生成两个子 Agent(不要用同一个子 Agent 做两次,两个独立的 Agent 才可能发现不同的问题)
+ - 将整个 `src/` 目录的代码发给它们,同时告诉它们本文档中的「硬性约束」和「边缘情况处理规则」
+ - 让它们 Review 的重点:是否违反硬性约束、是否有遗漏的边界情况、是否有逻辑矛盾(如加载和保存的格式不对称)
+ - 子 Agent 返回后,认真对待每一条意见,确认问题属实后立即修复。如果意见是误报,理解原因后忽略
6. 将已完成的部分以简洁的要点形式写入根目录的 `DONE.md` 文件(写入即可,不需要读取)
7. 读取 `DONE.md` 和本规范对比,检查是否有遗漏的功能点或偏差。不要写入任何文件
8. 执行 `git status` 确认 `ANSI-DRAW.md` 没有任何变化(即你的工作没有修改本文件)
@@ -374,9 +378,9 @@ cargo clippy -- -D warnings
### 滚动行为
-边距常量:8。
+边距常量:2。
-当光标移动后,检查光标是否位于视口的「边缘区域」。边缘区域定义为视口内距离边界 8 格以内的范围。
+当光标移动后,检查光标是否位于视口的「边缘区域」。边缘区域定义为视口内距离边界 2 格以内的范围。
如果光标移动到了边缘区域之外(即离某一侧边界的距离小于 8),则相机跟随光标移动,使光标回到边缘区域内。具体规则:
@@ -389,7 +393,7 @@ cargo clippy -- -D warnings
### 加载文件时的初始位置
-加载文件后,将相机位置设置为:相机 x = 0,相机 y = 0。然后执行一次滚动检查(使第一个字符 `(0, 0)` 位于距离视口右上角 8 格的位置)。
+加载文件后,将相机位置设置为:相机 x = 0,相机 y = 0。然后执行一次滚动检查(使第一个字符 `(0, 0)` 位于距离视口右上角 2 格的位置)。
---
@@ -407,6 +411,14 @@ cargo clippy -- -D warnings
- 在画布坐标计算中,所有坐标使用「格子索引」而非「终端列数」。即两个相邻格子坐标的差值是 1(不论格子中的字符宽度是多少)。Unicode 宽度只在渲染和光标移动时用于计算终端列数偏移量
- 选区计算:矩形选区的边界基于格子索引,不受字符宽度影响
+### 中日韩文字与 IME 输入
+
+- 「可打印字符」的定义范围是:所有非控制字符(不是 ASCII 控制字符 0x00-0x1F 的 Unicode 字符)。包括但不限于 ASCII 字母数字、标点、空格、中日韩统一表意文字(CJK)、emoji 等
+- 绑定表中「任何可打印 Unicode 字符」作用于替换/输入/插入模式时,对每个输入的字符产生一个独立的 `InputChar` 命令
+- 输入法(IME)的选词弹出窗口由终端/操作系统管理,ANSI-DRAW 不做干预。IME 确认提交(commit)后,每个提交的字符作为一个独立的 `KeyCode::Char` 事件到达程序,逐一处理
+- 终端键盘自动连发(按住一个键持续输入)由终端驱动层处理,每个重复的按键事件独立到达,逐一产生 `InputChar` 命令
+- 宽度为 2 的字符(如大部分 CJK 文字)在光标移动和渲染时占 2 个终端列,但画布坐标仍以一个格子计数
+
---
## 命令输入语法
@@ -595,38 +607,38 @@ Hello,A[B] World
以下表格定义了所有按键绑定。每个条目表示在某模式下按下某按键后应执行的命令序列。
-| 按键 | 模式 | 命令序列 |
-| ---------------------- | ----------------------------------------- | ---------------------------------------------------------------------------- |
-| 左箭头 KeyLeft | 所有模式 | [MoveLeft](然后执行通用滚动检查) |
-| 右箭头 KeyRight | 所有模式 | [MoveRight](然后执行通用滚动检查) |
-| 上箭头 KeyUp | 所有模式 | [MoveUp](然后执行通用滚动检查) |
-| 下箭头 KeyDown | 所有模式 | [MoveDown](然后执行通用滚动检查) |
-| ESC | 插入/输入/替换/命令/前景绘画/背景绘画模式 | [ModeNavigate] |
-| ESC | 选择模式 | [ModeNavigate, CancelSelection] |
-| R | 导览模式 | [ModeReplace] |
-| I | 导览模式 | [ModeInsert] |
-| A | 导览模式 | [ModeInput] |
-| F | 导览模式 | [ModePaintFg] |
-| B | 导览模式 | [ModePaintBg] |
-| : | 导览模式 | [ModeCommand] |
-| V | 导览模式 | [ModeVisual] |
-| Y | 插入/输入/替换模式 | [Yank] |
-| Y | 选择模式 | [VisualYank, CancelSelection] |
-| D | 选择模式 | [VisualDelete] |
-| P | 插入/输入/替换模式 | [Paste](Paste 的行为依当前模式而定) |
-| Backspace | 插入模式 | [BackspaceSquash] |
-| Backspace | 输入/替换模式 | [Backspace] |
-| 可打印字符(含空格) | 替换模式 | [InputChar(该字符)]——InputChar 命令的执行逻辑见替换模式定义 |
-| 可打印字符(含空格) | 输入模式 | [InputChar(该字符)]——执行逻辑见输入模式定义 |
-| 可打印字符(含空格) | 插入模式 | [InputChar(该字符)]——执行逻辑见插入模式定义 |
-| 可打印字母(a-Z、A-Z) | 前景绘画模式 | [SetColor(对应颜色)] |
-| 可打印字母(a-Z、A-Z) | 背景绘画模式 | [SetColor(对应颜色)] |
-| 回车键 Enter | 命令输入模式 | 解析 cmd_buffer 得到命令列表,顺序执行,然后 [ModeNavigate],清空 cmd_buffer |
-| ESC | 命令输入模式 | 清空 cmd_buffer,[ModeNavigate] |
-| Backspace | 命令输入模式 | 删除 cmd_buffer 最后一个字符 |
-| 可打印字符(含空格) | 命令输入模式 | 追加到 cmd_buffer |
-
-注意:「命令输入模式」下的可打印字符不产生 InputChar 命令,而是直接修改 cmd_buffer 字符串。这不是通过命令系统完成的,而是对 App 状态的直接操作。
+| 按键 | 模式 | 命令序列 |
+| ----------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------------- |
+| 左箭头 KeyLeft | 所有模式 | [MoveLeft](然后执行通用滚动检查) |
+| 右箭头 KeyRight | 所有模式 | [MoveRight](然后执行通用滚动检查) |
+| 上箭头 KeyUp | 所有模式 | [MoveUp](然后执行通用滚动检查) |
+| 下箭头 KeyDown | 所有模式 | [MoveDown](然后执行通用滚动检查) |
+| ESC | 插入/输入/替换/命令/前景绘画/背景绘画模式 | [ModeNavigate] |
+| ESC | 选择模式 | [ModeNavigate, CancelSelection] |
+| R | 导览模式 | [ModeReplace] |
+| I | 导览模式 | [ModeInsert] |
+| A | 导览模式 | [ModeInput] |
+| F | 导览模式 | [ModePaintFg] |
+| B | 导览模式 | [ModePaintBg] |
+| : | 导览模式 | [ModeCommand] |
+| V | 导览模式 | [ModeVisual] |
+| Y | 插入/输入/替换模式 | [Yank] |
+| Y | 选择模式 | [VisualYank, CancelSelection] |
+| D | 选择模式 | [VisualDelete] |
+| P | 插入/输入/替换模式 | [Paste](Paste 的行为依当前模式而定) |
+| Backspace | 插入模式 | [BackspaceSquash] |
+| Backspace | 输入/替换模式 | [Backspace] |
+| 任何可打印 Unicode 字符(含空格、中文等) | 替换模式 | [InputChar(该字符)]——InputChar 命令的执行逻辑见替换模式定义 |
+| 任何可打印 Unicode 字符(含空格、中文等) | 输入模式 | [InputChar(该字符)]——执行逻辑见输入模式定义 |
+| 任何可打印 Unicode 字符(含空格、中文等) | 插入模式 | [InputChar(该字符)]——执行逻辑见插入模式定义 |
+| 可打印字母(a-Z、A-Z) | 前景绘画模式 | [SetColor(对应颜色)] |
+| 可打印字母(a-Z、A-Z) | 背景绘画模式 | [SetColor(对应颜色)] |
+| 回车键 Enter | 命令输入模式 | 解析 cmd_buffer 得到命令列表,顺序执行,然后 [ModeNavigate],清空 cmd_buffer |
+| ESC | 命令输入模式 | 清空 cmd_buffer,[ModeNavigate] |
+| Backspace | 命令输入模式 | 删除 cmd_buffer 最后一个字符 |
+| 任何可打印 Unicode 字符 | 命令输入模式 | 追加到 cmd_buffer |
+
+注意:「命令输入模式」下的任何可打印 Unicode 字符不产生 InputChar 命令,而是直接追加到 cmd_buffer 字符串。这不是通过命令系统完成的,而是对 App 状态的直接操作。
---
@@ -636,7 +648,7 @@ Hello,A[B] World
1. 解析命令行参数。如果提供了一个参数,将其作为文件路径存入 `file_path`,读取文件内容并调用 ANSI 解析函数加载到画布。如果文件不存在或读取失败,设置 `msg` 为错误描述,画布保持为空
2. 如果没有提供参数,画布为空,`file_path` 为无值
-3. 相机初始位置为 (0, 0)。如果加载了文件,执行一次滚动检查(使 (0, 0) 位于距右上角 8 格的位置)
+3. 相机初始位置为 (0, 0)。如果加载了文件,执行一次滚动检查(使 (0, 0) 位于距右上角 2 格的位置)
4. 模式为导览模式
5. 所有其他字段为初始默认值