Skip to content

fix(x-markdown): 识别带 0-3 个前导空格的围栏代码块(缩进 fence) - #2018

Open
Xuepoo wants to merge 1 commit into
ant-design:mainfrom
Xuepoo:fix/indented-fence-state
Open

fix(x-markdown): 识别带 0-3 个前导空格的围栏代码块(缩进 fence)#2018
Xuepoo wants to merge 1 commit into
ant-design:mainfrom
Xuepoo:fix/indented-fence-state

Conversation

@Xuepoo

@Xuepoo Xuepoo commented Aug 7, 2026

Copy link
Copy Markdown

🤔 这个变动的性质是?

  • 🐞 Bug 修复

🔗 相关 Issue

fix #2017

💡 需求背景和解决方案

问题feedFenceStatepackages/x-markdown/src/XMarkdown/hooks/useStreaming.ts)只在行首为列 0 时识别围栏代码块(fenced code block)。CommonMark 允许 fence 前有 0-3 个空格(例如列表项内嵌套的代码块),但前导空格会先命中 else 分支置 lineFenceRunEnded = true,反引号不再累积——缩进的 opening fence 不可见,之后顶格的 closing fence 被误认为新的 opening,inFenced 永久 latch。流式中间态下缩进代码块内容不受 isInCodeBlock 保护,[/</$ 开头的内容被挂起(闪烁 / 占位符抖动),且最终输出可能丢失 closing fence 的字符。

方案:在 FenceState 中新增 lineFenceIndent(当前行已消费的前导空格数),feedFenceState 在 fence run 开始前容忍 0-3 个空格;第 4 个空格或任何非 fence 字符仍会结束 run(4 空格缩进代码块、普通缩进文本不受影响)。lineFenceIndent 随其他行内状态在 \n 时重置。

验证

  • 状态机级:原始版 vs 修复版逐字符对照(11 个用例),2/3 空格、波浪线、closing 尾随空格、fence 内反引号内容行等场景原始版全部 latch inFenced=true,修复版全部正确开合;无缩进对照与 4 空格缩进代码(非 fence)行为不变。
  • 端到端:真实 useStreaming(流式模式,hasNextChunk: true)下, ```js\nconst a = [1,2];\n ``` 原始版输出丢失 closing fence(以 `` 结尾),修复版输出与输入逐字一致。
  • 新增 6 个 fencedCodeTestCases(2/3 空格缩进开合、缩进波浪线、列表项内 fence、closing 后带尾随空格、4 空格反向用例),本地 jest 全量通过(102/102,含存量 4 个 fence 回归用例)。

📝 更新日志

语言 更新描述
🇺🇸 英文 Fix feedFenceState not recognizing fenced code blocks with 0-3 leading spaces (e.g. inside list items) during streaming, which caused incomplete-token churn and a stuck fence state.
🇨🇳 中文 修复流式渲染时无法识别带 0-3 个前导空格(如列表项内)的围栏代码块,导致的未完成 token 抖动与 fence 状态卡死问题。

Summary by CodeRabbit

  • Bug 修复
    • 改进流式 Markdown 中代码围栏的识别,支持最多 3 个空格缩进。
    • 正确处理列表项内的反引号或波浪线代码围栏,以及闭合围栏后的尾随空格。
    • 4 个空格缩进的内容将继续按缩进代码块处理,避免错误识别。
    • 确保流式输出保持原始输入内容不变。

…aces

feedFenceState only recognised an opening fence at column 0, so an
indented fence (e.g. inside a list item) was invisible: the leading
whitespace ended the fence run before the backticks accumulated, and a
later top-of-column closing fence was re-consumed as a new opening,
latching inFenced forever.

Track leading spaces consumed per line (0-3, per CommonMark) and let the
fence run start after them. A 4th space or any non-fence character still
ends the run, so indented code and plain text are unaffected.
@dosubot dosubot Bot added the bug Something isn't working label Aug 7, 2026
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

本次变更修复流式 Markdown 围栏代码块的缩进识别。解析器现在支持 0 至 3 个前导空格,并区分 4 个空格缩进的代码内容。新增测试覆盖反引号、波浪线、列表嵌套和尾随空格。

Changes

流式围栏缩进识别

Layer / File(s) Summary
围栏状态与解析逻辑
packages/x-markdown/src/XMarkdown/hooks/useStreaming.ts
FenceState 新增行缩进计数。feedFenceState 允许最多 3 个前导空格后识别反引号或波浪线围栏,并在新行时重置计数。
围栏场景测试
packages/x-markdown/src/XMarkdown/__tests__/hooks.test.tsx
新增测试,覆盖不同缩进、两种围栏字符、列表项内围栏、闭合围栏尾随空格,以及 4 个空格缩进不识别为围栏。

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

  • ant-design/x#1972:修改相同的 useStreaming.ts 围栏检测状态机及相关测试。

Suggested labels: javascript

Suggested reviewers: div627

Poem

我是兔子,轻敲代码门,
三格空格也能认出围栏。
反引号与波浪线并肩,
四格缩进回到代码田。
流式字符完整抵达终点。

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次修复,明确说明 x-markdown 支持带 0–3 个前导空格的围栏代码块。
Linked Issues check ✅ Passed 实现允许围栏前 0–3 个空格,保留 4 个空格代码块行为,并新增测试覆盖缩进围栏及流式内容一致性,符合 Issue #2017
Out of Scope Changes check ✅ Passed 变更仅涉及流式围栏解析逻辑及其测试,均服务于 Issue #2017 的修复目标,未发现无关改动。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/x-markdown/src/XMarkdown/__tests__/hooks.test.tsx`:
- Around line 301-305: 修正测试夹具“4-space indent is indented code, not a
fence”:在该用例的 input 和 output 中为 code 行及末尾围栏都添加 4 个前导空格,确保整个字符串保持连续的 4 空格缩进代码块。
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e1828e82-a91d-4b4e-a055-5306e2735380

📥 Commits

Reviewing files that changed from the base of the PR and between b529d8e and 26fcadb.

📒 Files selected for processing (2)
  • packages/x-markdown/src/XMarkdown/__tests__/hooks.test.tsx
  • packages/x-markdown/src/XMarkdown/hooks/useStreaming.ts

Comment on lines +301 to +305
{
title: '4-space indent is indented code, not a fence',
input: ' ```js\ncode\n```',
output: ' ```js\ncode\n```',
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

修正 4 空格测试夹具。

当前首行有 4 个空格,因此不会开启 fence。但末尾的无缩进围栏可能被解析为新的 opening fence。code 行也没有 4 个空格,因此该字符串不是连续的 4 空格缩进代码块。

请让代码行和末尾围栏也使用 4 个空格,或移除末尾的无缩进围栏。

建议修正
-    input: '    ```js\ncode\n```',
-    output: '    ```js\ncode\n```',
+    input: '    ```js\n    code\n    ```',
+    output: '    ```js\n    code\n    ```',

该建议依据 PR objective 对“保持 4 个空格缩进代码块及普通缩进文本的原有行为”的要求。

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
title: '4-space indent is indented code, not a fence',
input: ' ```js\ncode\n```',
output: ' ```js\ncode\n```',
},
{
title: '4-space indent is indented code, not a fence',
input: '
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/x-markdown/src/XMarkdown/__tests__/hooks.test.tsx` around lines 301
- 305, 修正测试夹具“4-space indent is indented code, not a fence”:在该用例的 input 和 output
中为 code 行及末尾围栏都添加 4 个前导空格,确保整个字符串保持连续的 4 空格缩进代码块。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[XMarkdown] 流式渲染无法识别带 0-3 空格缩进的围栏代码块,流式中间态内容丢失、fence 状态卡死

1 participant