Skip to content

fix(user-input-fold): 修复嵌套与波浪号代码块的定界符解析,防止折叠预览泄漏未闭合 fence - #336

Open
wswsadadbaba123 wants to merge 1 commit into
openpi-dev:mainfrom
wswsadadbaba123:main
Open

fix(user-input-fold): 修复嵌套与波浪号代码块的定界符解析,防止折叠预览泄漏未闭合 fence#336
wswsadadbaba123 wants to merge 1 commit into
openpi-dev:mainfrom
wswsadadbaba123:main

Conversation

@wswsadadbaba123

Copy link
Copy Markdown

Problem

extensions/user-input-foldparseSegments() 使用硬编码正则匹配代码块定界符:

  • FENCE_CLOSE 接受任意 ≥3 个反引号的行,违反 CommonMark §4.5(N 个反引号开起的代码块只能由 ≥N 个反引号闭合)。粘贴包含内部 ``` 代码块的 ```` 模板(如 prompt 模板)时,外层代码块被提前闭合,后续内容误判为 Prose,折叠输出泄漏未闭合的 ````markdown,导致 TUI 中折叠标记 `… folded` 之后的所有终端消息排版被吞噬进未闭合代码块。
  • FENCE_OPEN 仅匹配反引号,波浪号(~~~)代码块完全不被识别,被整体当作普通段落截取,折叠时同样泄漏未闭合代码块。

受影响对象:粘贴长 Markdown(嵌套 fence 或波浪号 fence)并触发折叠的 TUI 用户。模型可见 Context 与 Session 原始记录不受影响(本扩展仅改渲染层)。

Value

  • 修复两类粘贴场景下 TUI 渲染流崩溃:嵌套反引号代码块与波浪号代码块是粘贴 prompt 模板、日志的常见形态;
  • 折叠预览在所有路径下保证输出配对 Markdown(包括未闭合 fence 截断到消息末尾的情况),消除"一个未闭合 fence 吞掉后续整个终端界面"的级联故障;
  • 与 CommonMark 规范对齐,降低后续维护中围绕定界符语义的歧义。

Approach

extensions/user-input-fold/index.ts 中:

  1. 定界符按字符种类 + 长度匹配:新增 openFence() 解析开起 fence 的字符(`~)与长度 N(并按规范拒绝 info string 含反引号的反引号 fence);新增 isCloseFence() 要求闭合 fence 与开起 fence 字符相同且长度 ≥ N。内部 ``` 不再提前闭合 ```` 块,反引号与波浪号互不闭合。
  2. 未闭合 fence 改为代码块 + 合成闭合 fence:旧逻辑将未闭合 fence 的整条消息回退为纯文本,反而把未闭合 fence 泄漏进折叠预览;新逻辑按 CommonMark 将其视为延续到消息末尾的代码块,并在折叠时补齐匹配的闭合 fence,保证预览永远是配对 Markdown。
  3. 保持纯函数与无副作用foldUserMessage 不变式不变——输入不可变、确定性输出、模型接收完整原文。

测试更新:原有一个测试固化了"未闭合 fence 泄漏"的 bug 行为,改为断言合成闭合 fence;新增 4 个回归测试(嵌套 fence、更长闭合 fence、波浪号 fence、反引号/波浪号互不闭合)。

Validation

本机未安装 bun(bun 不在 PATH),以下均以 package.json 中对应脚本的底层 node 命令等价执行:

  • node --test tests/extensions/user-input-fold/index.test.ts:25/25 通过(含 4 个新增回归测试);
  • tsc --noEmit(typecheck):通过;
  • biome lint .:通过;biome format(两个改动文件):通过;
  • node scripts/check-config-contract.mjs / node scripts/check-discipline-ledger.mjs:通过;
  • 用户报告的最小复现脚本(嵌套 + 内部 ``` 场景):修复前泄漏未闭合 `markdown 且内容误判为 Prose;修复后正确输出闭合的 ```` ```` ```` 配对与… folded 18 lines` 标记;
  • 全量 node scripts/run-tests.mjs:1117 个 node 测试中 27 个失败,全部为预先存在的 Windows 环境问题(git-info 测试用 #!/bin/sh stub + : PATH 分隔符导致挂起、symlink 权限、taskkill 时序抖动),已通过 stash 对照确认在干净 HEAD 上同样失败,与本 PR 无关;vitest(file-search)28 过 2 败,同样经 stash 对照确认与 HEAD 一致。

未运行:bun run check 原样(bun 未安装);建议 CI(Linux)完整跑一遍作为最终仲裁。

Impact

  • user-visible behavior:嵌套/波浪号/未闭合 fence 的长消息折叠预览不再破坏 TUI 渲染;短消息(低于折叠阈值)行为完全不变(既有 round-trip 测试覆盖)。
  • model-visible context/tools:None。registerMarkdownTransformer 仅改渲染层,模型接收的原始文本不变。
  • runtime/lifecycle:None。纯函数解析逻辑,无新增状态、IO 或依赖。
  • persisted config/data:None。
  • compatibility or risk:低。唯一行为变更是"未闭合 fence 的长消息"从纯文本截断改为带合成闭合 fence 的代码块预览——旧渲染本身就是 bug(泄漏未闭合 fence)。既有测试中仅一个断言旧 bug 行为的用例被更新。

本次提交修复了问题 #334 感谢@hasak21

@github-actions github-actions Bot added the area:ui Terminal UI, rendering, themes, or visual assets label Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ui Terminal UI, rendering, themes, or visual assets

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant