Skip to content

The serializer escapes a marker run too short to open a thematic break #373

Description

@Azganoth

Summary

Saving escapes a ** written on its own line, where CommonMark needs three or more markers to open a thematic break. The line is literal text as written and as escaped, so the document is unchanged, but the file gains two backslashes the author did not write. corpus/commonmark/blocks.md carries the line under the heading Too few or unsupported markers remain text, which is the property being measured.

Steps to reproduce

  1. Open a document whose own line holds **.
  2. Save it without editing.
  3. Read the file.

Expected behavior

**, unchanged. Two markers cannot open a thematic break, so nothing needs holding literal, as ++ + two lines below it already stays bare.

Actual behavior

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

Document Saved
** \*\*

Related context

Done when

  • A marker run too short to open a thematic break is written without an escape.
  • A run that can open one still keeps what it needs, and ***, ---, and _ _ _ still round-trip as thematic breaks.
  • 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

opensBlockConstruct in src/features/editor/utils/markdownText.ts tests the line's character class without its length:

const thematicBreak = THEMATIC_BREAK_PATTERNS[run.character].test(line);

THEMATIC_BREAK_PATTERNS is { "*": /^[*\t ]*$/u, _: /^[_\t ]*$/u }, which ** satisfies, so a run too short to open the construct is treated as one that could and keeps its escape. The tilde branch a few lines above already makes the length check this pattern omits, returning run.end - run.start >= 3.

An underscore run reaches the same check through the _ pattern and behaves identically, measured against 8bc36754: _ is written \_ and __ is written \_\_. The length test that relaxes ** relaxes both, so this issue covers the underscore as well as the asterisk.

A single * is not affected, because nothing escapes it in the first place and these passes only remove escapes.

Out of scope

  • The -- two lines below in the same file, which is also escaped on save. A hyphen is not in ATTENTION_CHARACTERS, so it never reaches this check and is held by a different path whose cause is not established.
  • The escaped backticks under Block structure takes precedence over inline parsing in the same file, which are a code span crossing a list-item boundary rather than a block marker.

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