Summary
Saving rewrites the leading whitespace a paragraph's continuation line was authored with, in both directions. A blockquote's lazy continuation line gains its >, a line continuing a list item's paragraph gains the item's indentation, and a line indented inside a paragraph that carries on across it loses that indentation. Every case reads back as the same document, so this is form rather than content, but each is a line whose leading whitespace the author chose.
Steps to reproduce
- Open a document containing a blockquote whose second line carries no
>.
- Save it without editing.
- Read the file.
Expected behavior
The continuation line stays lazy.
Actual behavior
The first two rows were measured against 83e12b19 and still reproduce at 15e6a74b; the third was measured at 15e6a74b. Both by driving the editor mount used by the plugin tests.
| Document |
Saved |
> First quoted line / lazy continuation without another marker |
> First quoted line / > lazy continuation without another marker |
- [x]missing following whitespace / [ ] not a list item |
* [x]missing following whitespace / [ ] not a list item |
#no separator / ####### seven hashes / # indented as code |
the third line saves as \# indented as code |
The second row's - to * change belongs to the bullet-marker class; the added two-space indent on the following line is this issue.
The third row is the opposite direction and was hidden until the blank-line class landed in #378, which removed the cascade burying it. All three lines are one paragraph: neither a bare # nor seven hashes opens a heading, and indented code cannot interrupt a paragraph, so the third line is a continuation of the first. Dropping its four spaces puts # indented as code at a line start, where it would open a heading, so the serializer escapes the hash to hold the document together. The escape is a consequence rather than a defect of its own: writing the authored indentation back removes the need for it. This is the only remaining difference in corpus/commonmark/blocks.md outside the two escape classes #374 and #375.
Related context
Done when
Notes, logs, screenshots
Implementation direction
The leading whitespace of a continuation line is a property of a line inside a paragraph rather than of a node, so the recorded form belongs on the paragraph and has to survive as a per-line record. One record answers all three rows: what each continuation line was authored with, whether that was nothing or an indent. Check first whether node.position gives enough to reconstruct it; if it does not, that is the finding to record, and this issue may resolve as accepted rather than fixed.
Of the classes filed under #251, this is the one most likely to be unreachable, and it is worth settling that before spending on it. What has changed since that was written is the cost of leaving it: this class alone now keeps corpus/gfm/task-lists.md from byte identity, is one of two remaining in corpus/commonmark/lists-and-blockquotes.md, and is the only non-escape difference left in corpus/commonmark/blocks.md. Resolving it as accepted therefore removes three files from the group's identity target rather than one, which is a larger decision than it was.
Out of scope
- The blank line the serializer inserts between a quoted paragraph and the block that follows it, which belongs to the blank-line class.
- The bullet marker on the item, which belongs to the bullet-marker class.
Summary
Saving rewrites the leading whitespace a paragraph's continuation line was authored with, in both directions. A blockquote's lazy continuation line gains its
>, a line continuing a list item's paragraph gains the item's indentation, and a line indented inside a paragraph that carries on across it loses that indentation. Every case reads back as the same document, so this is form rather than content, but each is a line whose leading whitespace the author chose.Steps to reproduce
>.Expected behavior
The continuation line stays lazy.
Actual behavior
The first two rows were measured against
83e12b19and still reproduce at15e6a74b; the third was measured at15e6a74b. Both by driving the editor mount used by the plugin tests.> First quoted line/lazy continuation without another marker> First quoted line/> lazy continuation without another marker- [x]missing following whitespace/[ ] not a list item* [x]missing following whitespace/[ ] not a list item#no separator/####### seven hashes/# indented as code\# indented as codeThe second row's
-to*change belongs to the bullet-marker class; the added two-space indent on the following line is this issue.The third row is the opposite direction and was hidden until the blank-line class landed in #378, which removed the cascade burying it. All three lines are one paragraph: neither a bare
#nor seven hashes opens a heading, and indented code cannot interrupt a paragraph, so the third line is a continuation of the first. Dropping its four spaces puts# indented as codeat a line start, where it would open a heading, so the serializer escapes the hash to hold the document together. The escape is a consequence rather than a defect of its own: writing the authored indentation back removes the need for it. This is the only remaining difference incorpus/commonmark/blocks.mdoutside the two escape classes #374 and #375.Related context
corpus/commonmark/blocks.mdwith it.Scope;corpus/commonmark/lists-and-blockquotes.md, whoseLazy blockquote continuationandLazy continuation cannot begin a new blockheadings state the behavior being measured, andcorpus/commonmark/blocks.mdunderATX headings require valid spacing and depth.Done when
>is written back without it.corpus/commonmark/lists-and-blockquotes.md,corpus/gfm/task-lists.md, andcorpus/commonmark/blocks.mdlose these differences, or the reason they cannot is recorded.Notes, logs, screenshots
Implementation direction
The leading whitespace of a continuation line is a property of a line inside a paragraph rather than of a node, so the recorded form belongs on the paragraph and has to survive as a per-line record. One record answers all three rows: what each continuation line was authored with, whether that was nothing or an indent. Check first whether
node.positiongives enough to reconstruct it; if it does not, that is the finding to record, and this issue may resolve as accepted rather than fixed.Of the classes filed under #251, this is the one most likely to be unreachable, and it is worth settling that before spending on it. What has changed since that was written is the cost of leaving it: this class alone now keeps
corpus/gfm/task-lists.mdfrom byte identity, is one of two remaining incorpus/commonmark/lists-and-blockquotes.md, and is the only non-escape difference left incorpus/commonmark/blocks.md. Resolving it as accepted therefore removes three files from the group's identity target rather than one, which is a larger decision than it was.Out of scope