From 91e54b5f48f0ff97fa10c68c7518e0c99784eaed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Wed, 14 Oct 2026 15:04:10 -0400 Subject: [PATCH] R4.7: block commands, reviewed three rounds, round-3 fixes in component 0558f0c Co-Authored-By: Claude Opus 5.5 (1M context) --- tasks/TASKS.md | 2 +- tasks/reviews/R4.7-r1.md | 27 +++++++++++++++++++++++++++ tasks/reviews/R4.7-r2.md | 25 +++++++++++++++++++++++++ tasks/reviews/R4.7-r3.md | 19 +++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tasks/reviews/R4.7-r1.md create mode 100644 tasks/reviews/R4.7-r2.md create mode 100644 tasks/reviews/R4.7-r3.md diff --git a/tasks/TASKS.md b/tasks/TASKS.md index 439e33b..67913a0 100644 --- a/tasks/TASKS.md +++ b/tasks/TASKS.md @@ -238,7 +238,7 @@ - [~] R4.4 ElyMark:导出 HTML、纯文本与富文本复制随 R4.2、R4.3,与可视所见一致(表情、提示块、目录、行内 HTML 的同一组标签)。组件 1251221 公开 `MarkdownReader`、`MarkdownBlock`,导出与可视同一读法。审查三轮未过(`tasks/reviews/R4.4-r1..r3.md`):r1 六项(自读行内状态与组件分歧、目录锚点缺、写出平方);r2 六项(空公式错位、链接里的脚注嵌套、脚注锚点、纯文本脚注标签、富文本复制失样式、长注释);r3 一项:每个脚注扫一遍已开格式查链接,深格式加多脚注为平方。r3 已修(随格式栈计数已开链接),回归测试在旧码失败(60 ms 到 912 ms),新码线性;轮数用尽,未再审。markdown-rs 对同一输入的解析仍随长度平方(上游,已记限制) - [~] R4.5 组件库:可视模式按下块时插入点落在所按的字处;右键不开块,把插入点放到所点处,以事件告知属主所点的目标(块的种类、链接地址、图片地址、是否在表格或代码块里)。组件 5af11fe 至 c35fdac(已推送):每段画出的文字记其原文范围与解码方式,从段尾倒着对回原文;右键发 `DocumentEvent::Pointed`。审查三轮未过(`tasks/reviews/R4.5-r1..r3.md`):r1 九项(引用续行、转义、缩进代码、提示块、HTML 块、定义与 front matter、空文档右键自开、写回改块、长注释);r2 四项(解码换行崩溃、CRLF 与 CR、删去的语法错位、写回改了定义);r3 五项:保留的缩进与 `>` 被当成换行吃掉、自动链接里的引用被解码、表格代码的 `\|`、解码出的空白不参与合并、数字引用的控制字符未按 markdown-rs 换成 U+FFFD。r3 已修(先比相同字符,再把画出的空格对行尾,空白不论是否解码都可略过;自动链接按原文,表格单元格的代码读 `\|`,数字引用照 markdown-rs),审查者的 17 个探针转为回归测试,14 个在旧码失败;轮数用尽,未再审。已打开块的输入框里右键不发事件,不在本条。ElyMark 的组件 pin 随 R4.10 再升 - [~] R4.6 组件库:行内格式命令(粗体、斜体、行内代码、删除线、下划线、链接、图片、清除格式),照 Typora:有选区即包住或去掉,无选区取插入点所在的词,空处插一对标记、插入点在其中;代码、公式、HTML、front matter 里拒绝并说明;一步撤销;打开的块照常可续写。组件 68d33b4 至 1d03545(已推送):`MarkdownDocument::format` 照 Typora 的 `toggleStyle`,跨块、跨链接或别的标记的选区拒绝(窄于 Typora 的拆分);格式一律在后台读,一次一个(另一个以 `Busy` 拒绝),文字、选区未变且不在预览才落下,后到的拒绝经 `DocumentEvent::FormatRefused`。审查三轮未过(`tasks/reviews/R4.6-r1..r3.md`):r1 七项(端点落在标记或地址里、行尾空格与空单元格、清除漏公式脚注转义、下划线隔着标签、长文卡界面、CR 行、跨块报错);r2 六项(嵌套标记与地址、自动链接的反斜杠、平方增长与 128 KiB 卡顿、连按丢失、后台拒绝无事件、长注释);r3 三项:格式后的同步重读超 100 毫秒、16 KiB 阈值使可视打开不在顶上、测试用了 std 的 Instant。r3 已修:格式不再在界面线程解析,文档的即时读取回到 128 KiB,计时用 `web_time::Instant`,两项回归在旧码失败;轮数用尽,未再审。遗留:128 KiB 以内的块多的文字,文档自身的同步重读仍可超 100 毫秒(markdown-rs 随节点数平方增长);超过 128 KiB 的文件以可视打开,首次后台读取落定时不在顶上(实测 140 KB 落在第 2 行,非 R4.6 所改,未修) -- [ ] R4.7 组件库:块命令(标题 1–6、段落、标题升降一级;引用、有序、无序、任务列表的切换;插入分隔线、代码块、公式块、目录、front matter、脚注、链接定义、前后空段落;删除块),一步撤销,拒绝说明原因 +- [~] R4.7 组件库:块命令(标题 1–6、段落、标题升降一级;引用、有序、无序、任务列表的切换;插入分隔线、代码块、公式块、目录、front matter、脚注、链接定义、前后空段落;删除块),一步撤销,拒绝说明原因。组件 58e212d 至 0558f0c(已推送):`MarkdownDocument::block` 照 Typora 的 `changeBlock`、`changeHeadingLevel`、`insertBlock`、`toggleIndent`、`insertParagraph`、`deleteBlock`,与格式共用一个后台执行器与 `EditRefusal`;同级标题保持不变(照 Typora 菜单),代码上的标题命令、任务首行的标题与引用拒绝(GFM 读作文字),前后空段落写成空行,越出打开的块先写回(多一步撤销)。审查三轮未过(`tasks/reviews/R4.7-r1..r3.md`):r1 十三项(标题标记里插入崩溃、任务框丢勾、列表里提示块拆开、拆分时行内标记断开、缩进代码改类型、列表项与脚注的前置段落、删除使邻段相接、尾部 `#` 与块起始符、任务首行、跨列表的选区、同级标题当开关);r2 十二项(拆分后重开标记成块语法、闭合 `#`、标记下一行的任务框、提示块的懒行与空行、标记与正文同行、Tab 缩进代码、任务列表包代码、引用里删除、拆分剩下的块起始符、长注释),r2 起标题与拆分写出前重新解析核对;r3 九项:核对忽略代码里的空白、按 mdast 而非可视读法核对(下划线、表情漏判)、提示块正文块失去缩进、按内容认围栏、非 ASCII 空白算缩进、去掉任务框露出块起始符、续行任务框解除时留下、空标题转段落误拒、转义的提示标记误拒。r3 已修:核对经 `MarkdownReader` 照绘制读(代码与公式里的空白计入),提示块的标记按提示读法判定、正文块保留缩进,围栏按源码结构认,缩进只数 ASCII 空格,去掉任务框时转义露出的起始符(续行同),空标题可转空段落;七项回归在 r3 的源码上失败(`.work/R4.7-fix3/red.md`);轮数用尽,未再审。遗留:列表与引用的切换不重新解析核对,只逐项修正 - [ ] R4.8 组件库:表格行列上下左右移动、整理表格源码;代码块取代码内容;与已有的增删行列同一套拒绝 - [ ] R4.9 ElyMark:“段落”“格式”菜单与 Typora 同项同键(Ctrl+1–6、Ctrl+0、Ctrl+=/-、Ctrl+B/I/U、Ctrl+Shift+`、Alt+Shift+5、Ctrl+K、Ctrl+Shift+I、Ctrl+\、Ctrl+T、Ctrl+Shift+K/M/Q/[/]);源码模式 Ctrl+/;字号 Ctrl+Shift+=/-/0;专注 F8、打字机 F9;表格菜单加移动行列;复制为 Markdown Ctrl+Shift+C、粘贴为纯文本 Ctrl+Shift+V - [ ] R4.10 ElyMark:右键菜单照 Typora 按目标变化:剪贴板行(剪切、复制、粘贴、删除)、复制/粘贴为 ▸(Markdown、HTML 代码、纯文本、粘贴为纯文本)、格式行、段落 ▸ 或表格 ▸ 或代码项、插入 ▸、链接(打开、复制地址)、图片(打开所在位置、删除图片)、删除块;预览只读时只留复制类 diff --git a/tasks/reviews/R4.7-r1.md b/tasks/reviews/R4.7-r1.md new file mode 100644 index 0000000..4fad147 --- /dev/null +++ b/tasks/reviews/R4.7-r1.md @@ -0,0 +1,27 @@ +FAIL + +1. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/insert.rs:32` — Inserting a block can panic at valid source carets in heading syntax. On `# alpha`, put the caret at byte 0 and run `Rule`: `back` slices `text[2..0]`. A caret within the closing hashes of `# alpha ###` similarly panics in `forth` at line 44. The heading body bounds exclude these valid caret positions, but the splitter assumes the selection is inside them. Validate/map syntax positions before slicing, or return an explicit refusal. Both paths were reproduced in `probes.log`. + +2. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/list.rs:190` — Converting a mixed GFM list to a task list clears existing completion states. With `- a\n- [x] b`, run `TaskList` on `b`: the result is `- [ ] a\n- [ ] b`. `marker` always emits an unchecked box. Typora's task conversion sets item style without clearing `checked`; this command is not a task-status command. Preserve existing checked values when adding task markers to the other items. + +3. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/quote.rs:70` — Unwrapping a nested alert deletes its enclosing list item's opener. On `- > [!NOTE]\n > a\n- b`, run `Quote` on `a`: the output is ` a\n- b`, which markdown-rs reads as a top-level paragraph followed by a one-item list. Deleting the complete marker line also deletes the outer `- `. Remove only the alert's own marker and transfer any enclosing container opener to the surviving content. + +4. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/insert.rs:304` — Splitting a paragraph ignores inline syntax crossing the caret. Insert `Rule` between `b` and `c` in `**abcd**`: the result is `**ab\n\n---\n\ncd**`, so both fragments lose bold and display literal asterisks. Typora's `splitAt` uses `smartSplit` to close and reopen inline pairs. Preserve those pairs across the inserted block, and explicitly refuse boundaries that cannot be split safely. + +5. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/list.rs:188` — Retyping a list consumes first-line code indentation as marker whitespace. `- code` contains an indented code block, but `OrderedList` produces `1. code`, whose item contains ordinary prose. The replacement removes every space after the marker, although CommonMark treats excess spaces as content indentation. Retain that excess indentation while replacing the list marker and adjusting continuation lines. + +6. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/insert.rs:331` — `ParagraphBefore` detaches the first paragraph from its list item. On `- a`, it produces `- \n\n a`; markdown-rs reads an empty list followed by a top-level paragraph, rather than retaining `a` inside the item. The existing test checks this exact string without checking its parsed structure. Handle a first child's container opener when making room, or refuse an unrepresentable insertion; preserve the original list membership. + +7. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/insert.rs:390` — Deleting a block can merge untouched neighboring paragraphs. In `p\n# h\nq`, delete the heading: the result is `p\nq`, one paragraph instead of the original two surrounding paragraphs. The deletion removes the only block boundary and never checks the resulting adjacency. Leave a separating blank line when removing the block would otherwise join its neighbors. + +8. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/heading.rs:107` — Turning prose into an ATX heading can remove visible text. `Heading(1)` on `alpha #` writes `# alpha #`; markdown-rs now treats the final hash as a closing delimiter and the heading text becomes only `alpha`. Protect literal text that acquires heading-syntax meaning when adding the opening hashes, and verify the parsed heading text remains unchanged. + +9. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/heading.rs:133` — `Paragraph` can create another block type instead of a paragraph. On `# - alpha`, removing the heading marker produces `- alpha`, a list item. Only removing the old syntax is insufficient when the remaining text is a block opener. Escape newly active block syntax while preserving the heading's inline content so the result actually parses as a paragraph. + +10. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/quote.rs:111` — Quoting a task item's first paragraph reports success but creates no quote. `Quote` on `- [ ] a` produces `- [ ] > a`; markdown-rs reads the task's text as literal `> a`, with no blockquote. This is the same GFM first-line restriction already handled for heading commands. Produce a valid nested block without changing the task, or return an explicit refusal instead of inserting an ineffective marker. + +11. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/insert.rs:282` — Inserting at the start of a task item's text also treats that text position as a block boundary. On `- [ ] ab`, put the caret before `a` and run `Rule`: the output is `- [ ] ---\n\n ab`, containing no thematic break. `CodeBlock` there similarly puts the opening fence in task text rather than creating the requested code block. Check this boundary before writing block syntax; preserve the task and emit a real block, or refuse explicitly. + +12. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/list.rs:47` — A selection starting in a list item bypasses sibling-range handling even when it ends outside that list. In `- a\n\nb`, select from `a` through `b` and run `OrderedList`: only the first list is retyped to `1. a`; the selected paragraph `b` is left outside. Determine the selection's common holder before taking the existing-list shortcut, and apply the command to all touched siblings as required by the accepted selection rule. + +13. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/heading.rs:21` — Selecting the current heading level incorrectly toggles it to a paragraph. `Heading(2)` on `## alpha` removes its heading. Typora's actual Paragraph menu calls `changeBlock(e)` with one argument; its same-level toggle requires a truthy third argument, so the menu leaves this heading unchanged. Executing the extracted function with that menu call confirmed zero mutations (`typora.log`). Make explicit heading-level commands idempotent, and correct the test and AGENTS.md claim that currently require the toggle. diff --git a/tasks/reviews/R4.7-r2.md b/tasks/reviews/R4.7-r2.md new file mode 100644 index 0000000..4c5f5bd --- /dev/null +++ b/tasks/reviews/R4.7-r2.md @@ -0,0 +1,25 @@ +FAIL + +1. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/split.rs:102` — Reopening an inline format can turn its text into block syntax. In `~~ab~cd~~`, insert `Rule` between `b` and the literal `~`: the result is `~~ab~~\n\n---\n\n~~~cd~~`. The last line becomes an opening code fence, so the visible `~cd` disappears. The new seam copies delimiters without checking how they combine with neighboring text. Escape the newly adjacent literal delimiters, or refuse an unsafe split; verify that both fragments retain their text and formatting. The same issue changes which underscores are bold in `__ab_cd__`. + +2. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/heading.rs:91` — The paragraph-opener check includes closing heading hashes that the edit subsequently removes. `Paragraph` on `# --- ###` succeeds with `---`, a thematic break; on `# [x]: /u ###` it produces a link definition and the displayed text disappears. Both original suffixes parse as prose while the closing hashes remain. Check the actual retained heading body, excluding closing syntax, before deciding whether to escape or refuse it. This leaves round-1 F9 incomplete. + +3. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/list.rs:193` — Checked-state preservation only handles a checkbox on the opener's physical line. `TaskList` on `1.\n [x] a` produces `- [ ] \n [x] a`: markdown-rs changes the checked item to unchecked and makes `[x]` part of its text. Preserve the parsed item's checkbox even when its first paragraph starts on a continuation line, without adding a second box. This leaves round-1 F2 incomplete. + +4. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/quote.rs:77` — Unwrapping an alert with a lazy continuation concatenates that line's indentation with the retained outer opener. `Quote` on `- > [!NOTE]\n a` produces `- a`, turning the original paragraph into indented code. With an enclosing quote, `> > [!NOTE]\n> a` becomes `> > a`, retaining the quote that was meant to be removed. Transfer the surviving content after consuming its enclosing-container prefix and appropriate continuation indentation. The explicit-prefix regression test does not cover this branch. + +5. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/quote.rs:76` — Leading blank lines in an alert can still detach its body from the enclosing item. `Quote` on `- > [!NOTE]\n >\n >\n > a` writes `- \n \n a`; markdown-rs reads an empty list followed by a top-level paragraph. The splice only transfers the first following line, even when that line is blank. Preserve the item's membership when removing the marker and leading quote-only lines, or refuse the unrepresentable edit. This is another unhandled case of round-1 F3. + +6. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/quote.rs:79` — Alert removal assumes the decoded marker ends at a physical newline. The existing `alert` reader recognizes `> [!NOTE] a` as a NOTE whose body is `a`, but `Quote` deletes the entire document because there is no following source line. Locate the marker's actual source extent using the same decoded interpretation, or refuse without editing; never remove the surviving body. The probe confirmed the reader's body before asserting the failed unwrap. + +7. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/list.rs:201` — Retyping still loses code indentation when marker whitespace contains tabs. `OrderedList` on `-\t\tcode` produces `1. \tcode`, changing its child from `Code("code")` to a paragraph. Removing a whole tab also removes its excess columns, and the remaining tab reaches a different stop after the new marker. Preserve indentation in columns, including the unused part of a consumed tab, and account for the new marker width. The spaces-only F5 regression misses this case. + +8. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/list.rs:201` — Converting an item with first-line indented code to a task list reports success while discarding the code block. `TaskList` on `- a` writes `- [ ] a`, parsed as task paragraph text rather than code. Keeping the spaces does not preserve code after a GFM checkbox. Retain the original child block in a representable task-item structure, or explicitly refuse this conversion as the other task-first-line commands do; add a task-list case to the code-preservation regression. + +9. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/insert.rs:304` — Deletion's join check still counts container openers that the deletion removes. In `p\n> # h\nq`, delete `h`: the result is `p\nq`, merging two untouched paragraphs. `joins_before(..., None)` sees the quote opener on the deleted line and suppresses the separating blank. Determine adjacency from the surviving prefixes and blocks, excluding openers removed with the target. The root-level heading test passes, but round-1 F7 remains for nested blocks. + +10. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/heading.rs:216` — Literal closing hashes are protected only by `to_heading`, leaving other paths that create ATX boundaries destructive. `Heading(3)` on `alpha #\n===` writes `### alpha #`, whose visible text loses `#`. Likewise, `split.rs:145` turns `# a # b`, with `Rule` inserted after the interior `#`, into `# a #\n\n---\n\n# b`, losing that literal hash. Apply the closing-hash protection whenever a heading line is created or shortened, and assert its parsed text. These leave round-1 F8 incomplete. + +11. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/split.rs:159` — Splitting a paragraph leaves newly active block openers unprotected in the surviving fragment. Insert `Rule` before `-` in `a - b`: the output is `a\n\n---\n\n- b`, so the original paragraph text becomes a list and its literal dash becomes syntax. The command should split the paragraph while retaining its content. Escape a fragment's newly active block syntax, or refuse if it cannot be represented safely, and test the resulting block kinds and text. + +12. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/heading.rs:89` — Four added comments exceed the explicit ten-word limit: this line, `block/list.rs:173`, and `block/split.rs:1` and `:69` each contain eleven words. For example, “The byte to escape if `at`'s line would open a block.” is eleven. Shorten each to at most ten words while retaining its single-line form. diff --git a/tasks/reviews/R4.7-r3.md b/tasks/reviews/R4.7-r3.md new file mode 100644 index 0000000..78ebc81 --- /dev/null +++ b/tasks/reviews/R4.7-r3.md @@ -0,0 +1,19 @@ +FAIL + +1. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/check.rs:59` — The reread comparison discards all whitespace, including literal whitespace inside code. `Heading(3)` on ``a `x\n y`‸\n===`` succeeds, changing the inline-code value from `x\n y` to `x y`. The real MarkdownReader comparison also fails: this changes the code while merely changing the heading level. Preserve significant whitespace when joining the heading, or refuse as `Misread`; the verification must compare it instead of filtering it out. + +2. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/check.rs:38` — The signature compares raw mdast nodes rather than the text and formats the component displays. Inserting `Rule` at `ab‸cd` succeeds with `ab\n\n---\n\ncd`, but MarkdownReader now renders `cd` without underline. Changing the first line of `a‸\nb` to a heading has the same loss. Likewise, splitting `x:smile: ‸:smile:` changes the second literal shortcode into an emoji. Verify the fragments through the same reader used for display, preserving its text and inline formats, or refuse the unsafe edit. + +3. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/quote.rs:93` — Alert unwrapping strips the surviving body's significant indentation. `Quote` with the caret in `code` in `> [!NOTE]\n>\n> code` succeeds with `code`, changing the alert's indented code block into a paragraph. An indented fenced block also changes its code value because only its opening line loses the indentation. Preserve the body's indentation relative to the removed quote, consistently across its lines, or refuse if its block kind and code value cannot survive. + +4. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/list.rs:214` — Retyping identifies a fence from the code's literal contents after discarding its indentation. `OrderedList` on ``- ```lang‸`` writes ``1. ```lang``: the original code value, three backticks followed by `lang`, becomes an empty fenced code block with language `lang`. Determine whether the original block is fenced from its source structure and indentation, not whether its content starts with backticks or tildes; retain the parsed code value. + +5. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/list.rs:220` — Code padding counts every Unicode whitespace character's UTF-8 bytes as indentation, then leaves that character in the source as well. For `-` followed by five ASCII spaces, U+00A0, and `code`, `OrderedList` adds two ASCII spaces to the parsed code value: `\u{00A0}code` becomes ` \u{00A0}code`. Count actual indentation in columns and preserve non-ASCII whitespace as code content; do not duplicate its byte length as spaces. + +6. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/list.rs:205` — Removing a task checkbox can activate block syntax in the retained paragraph. `BulletList` on `- [x] ---` succeeds with `- ---`, which parses as a thematic break: both the list and its displayed text disappear. `- [x] # h` similarly becomes a heading inside the item. Escape the newly active opener or refuse the conversion, and verify that removing the checkbox preserves the child's text and block kind. List retyping does not preserve these by construction. + +7. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/list.rs:149` — The continuation-line checkbox fix covers retyping but not unwrapping. `TaskList` on `-\n [x] a` toggles the task list off and produces `[x] a`, making the former checkbox literal paragraph text; the equivalent same-line task unwraps to `a`. Remove the parsed checkbox on its own physical line when unwrapping, as well as the list opener and continuation indentation. + +8. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/heading.rs:71` — The new guard requires a parsed paragraph node even when the valid result is an empty paragraph. `Paragraph` on `# ‸` now returns `EditRefusal::Misread` instead of removing the heading marks. Empty paragraphs have no mdast node, so `block_at` necessarily returns `None`. Recognize this valid empty result while continuing to reject results that actually reinterpret retained content. + +9. `C:/Users/zhang/Documents/Github/Ely-GPUI-Components/src/documents/document/block/quote.rs:75` — The same-line alert guard rejects safely removable markers that the existing alert reader decodes. `> \[!NOTE]\n> a` is recognized as an alert with body `a`, but `Quote` now returns `Misread` because the raw marker does not start with `[!`. Its marker occupies a physical line of its own; the decoded-newline refusal does not apply. Identify the marker using the reader's decoded interpretation and distinguish a marker-only line from a line that also contains body text.