Skip to content

Saving inserts a blank line between blocks the author wrote adjacent #324

Description

@Azganoth

Summary

Saving inserts a blank line between blocks the author wrote adjacent. CommonMark does not require the blank line wherever the second block already interrupts the first, so the file grows lines the author did not write and the document is unchanged.

This is the most widespread of the classes under #251 by file count: it appears in five of the sixteen scoped corpus files, and it is the only remaining difference in corpus/commonmark/html.md.

Steps to reproduce

  1. Open a document containing a paragraph line followed immediately by <section class="garden"> with no blank line between them.
  2. Save it without editing.
  3. Read the file.

Expected behavior

The two lines stay adjacent.

Actual behavior

Measured against 83e12b19 by driving the editor mount used by the plugin tests. Each row is a pair of adjacent lines that gains a blank line between them:

Document File
paragraph text followed by a block-level tag corpus/commonmark/html.md
[same]: /first followed by [same]: /second corpus/commonmark/blocks.md
[forward reference]: /forward "Forward title" followed by [never referenced]: /unused "Unused title" corpus/commonmark/blocks.md
a paragraph followed by the *** that interrupts it corpus/commonmark/blocks.md
consecutive ATX headings corpus/commonmark/blocks.md
a quoted paragraph followed by a heading outside the quote corpus/commonmark/lists-and-blockquotes.md
a paragraph followed by the list that interrupts it corpus/commonmark/lists-and-blockquotes.md
a table followed by the blockquote that terminates it corpus/gfm/tables.md
a paragraph followed by an unclosed fence corpus/commonmark/code.md

Every one of these is a case where the second block interrupts the first without needing a blank line, which is why the corpus carries them: the headings above them state that the interruption is the behavior under test.

Related context

Done when

  • Two blocks authored adjacent are written adjacent wherever the second interrupts the first without a blank line.
  • Blocks authored with a blank line between them keep it, and blocks that require a separator still get one.
  • Coverage asserts the document is unchanged on the next read for each pairing above, since removing a separator is the direction that can merge two blocks.
  • corpus/commonmark/html.md round-trips byte-identically, which this class alone should achieve for that file.
  • corpus/commonmark/blocks.md, corpus/commonmark/code.md, corpus/commonmark/lists-and-blockquotes.md, and corpus/gfm/tables.md lose these differences.

Notes, logs, screenshots

corpus/commonmark/html.md is the cheapest place to start: it has exactly one difference, this one, and fixing it moves a fifth file to byte identity.

Implementation direction

serializeMarkdownRoot in the handlers registered on remarkStringifyOptionsCtx already assembles the document and resolves deferred decisions against the assembled text, which is the seam where the separator between two blocks is decidable — it needs both blocks, which no single node handler has.

Interacts with #198: a blank-line run is already carried as a blank paragraph, so the fix must distinguish a separator the serializer adds from a blank line the author wrote, and must not reintroduce a blank paragraph where the author wrote none.

Out of scope

Activity

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

Metadata

Metadata

Assignees

Labels

BugSomething isn't working

Projects

  • Status
    Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions