Skip to content

The serializer escapes a run the multiple-of-three rule already leaves literal #372

Description

@Azganoth

Summary

The serializer escapes a ** run that cannot pair, writing _\*\*underscore and one asterisk stay literal* for a line the parser already reads as literal text. CommonMark matches an opener and a closer only when the sum of their run lengths is not a multiple of three, unless both lengths are; here a two-character opener and a one-character closer sum to three, so nothing pairs and the run stays literal on its own. The backslashes change nothing, measured below.

This is the class #252, #256, #257, #258, #271, #289, #292, #293, #336, and #353 removed, reaching the one pairing constraint none of them covered. It is the last escape difference in corpus/commonmark/emphasis.md, though not the last difference: the file also carries the two nesting-collapse lines #213 settled, which no serializer change reaches, so fixing this does not bring the file to byte identity.

Steps to reproduce

  1. Open a document containing _**underscore and one asterisk stay literal*.
  2. Save it without editing.
  3. Read the file.

Expected behavior

_**underscore and one asterisk stay literal*, unchanged. The run is held literal by the pairing rule rather than by a backslash, as ***two markers stay literal* on line 109 of the same file already is.

Actual behavior

Measured against 8bc36754 by driving the editor mount used by the plugin tests, on corpus/commonmark/emphasis.md line 121.

Document Saved
_**underscore and one asterisk stay literal* _\*\*underscore and one asterisk stay literal*

The escape is redundant rather than merely cosmetic. Both spellings parse to the same document, measured with mdast-util-from-markdown 2.0.3 from the project's dependency tree:

Source Document
_**underscore and one asterisk stay literal* paragraph("_**underscore and one asterisk stay literal*")
_\*\*underscore and one asterisk stay literal* paragraph("_**underscore and one asterisk stay literal*")

Closure and convergence both hold today, so neither the corpus round-trip guard nor the document-preservation guard can see this. What it costs is one of the three differences keeping corpus/commonmark/emphasis.md from byte identity.

The same save relaxes the neighbouring case, which is what makes this a defect rather than a house style: ***two markers stay literal* has a three-character opener and a one-character closer, sums to four, pairs, and is written back with no escape.

Related context

Done when

  • A delimiter run left literal because its length and its candidate closer's sum to a multiple of three is written without an escape.
  • A run that can still pair keeps its escape, including one whose lengths are both multiples of three.
  • Regression coverage asserts the saved bytes and the document the saved file reopens as, since closure already holds and cannot catch this.

Notes, logs, screenshots

Diagnosis

The serializer's safety check does not model the multiple-of-three constraint. It sees a left-flanking ** run and escapes it as though it could open strong emphasis, without asking whether any closer on the line can match it. The trailing * is the only candidate, and the sum of three rules the pair out.

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