Skip to content

feat(muya): support same-line display math#4935

Open
Renakoni wants to merge 2 commits into
marktext:developfrom
Renakoni:feature/same-line-display-math
Open

feat(muya): support same-line display math#4935
Renakoni wants to merge 2 commits into
marktext:developfrom
Renakoni:feature/same-line-display-math

Conversation

@Renakoni

@Renakoni Renakoni commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Closes #4904

Summary

MarkText only rendered $$...$$ display math when the $$ fences were on their own lines. This PR lets $$...$$ render as display math on the same line as surrounding text, matching pandoc and GitHub — so markdown copied from those sources (or from tools that emit inline $$) renders correctly on paste instead of showing raw $$.

For example, both of these now render:

$$ E=MC^2 $$

Energy is $$E=mc^2$$ in physics.

What this PR does

  • Tokenizes single-line $$...$$ as inline display math. A dedicated rule recognizes non-empty $$...$$ spans and is tried before the (unchanged) single-dollar $...$ rule. Empty $$$$, unclosed openers, and multiline $$ fences are not treated as inline display math — multiline fences still go through the existing block parser, and single-dollar math is untouched (including soft line breaks inside $...$).
  • Keeps the document model and markdown unchanged. Same-line $$ stays an inline token in paragraph state; it is not promoted to a math-block. Source round-trips losslessly and paste behavior is preserved, including adjacent formulas like $$a$$$$b$$.
  • Renders display mode with the correct layout. $$ spans render through KaTeX in display mode; a new .mu-display-math class shows the hidden preview as a full-width, centered block, while the editing state (caret inside) stays inline-block so the source is editable in place.
  • Uses the real marker width for offsets. Cursor/format offsets and the preview's content range are derived from the actual marker length (2 for $$) instead of a hardcoded 1, so selecting or toggling a $$x$$ span targets the content correctly.

Type of change

  • Bug fix (non-breaking, fixes an issue)
  • New feature (non-breaking, adds functionality)
  • Breaking change (causes existing functionality to change)
  • Documentation update

Test plan

  • New tests added
  • Manually tested on: Windows (Chromium)

Passing checks:

  • 48 Muya unit tests covering tokenization (adjacent formulas, empty/unclosed/multiline edge cases, escaping, single-dollar newlines), markdown round-trip, paste, and format/cursor offsets
  • 2 real-Chromium E2E tests for the display-block layout and the block → inline-block editing interaction
  • Muya tsc type check and ESLint (0 errors), plus targeted inlineSyntax.css stylelint

Notes for reviewers


By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.

@Renakoni

Copy link
Copy Markdown
Contributor Author

Pushed 7cf518c: the display-math rule is now a linear-time scanner instead of a regex.

A downstream review of this change flagged that inlineDisplayMathRule backtracked quadratically on malformed input — the \. content pairs overlap the (\*) trailing group, so $$ followed by 131,072 backslashes and a stray $ blocked the thread for ~10s (2.5s at 65,536). Since tryChunks runs synchronously during paragraph tokenization, one crafted line could freeze the window on open or paste, so this seemed worth fixing before merge rather than shipping another regexp/no-super-linear-backtracking suppression.

execInlineDisplayMath keeps the exact semantics: content ends at the first unescaped same-line $$; a backslash always escapes the next character (the regex's greedy pair-first behavior, so an escaped closer extends the content); a returned match always has an unescaped closer, so the isLengthEven(to[3]) gate is untouched — the parity group is always empty.

Evidence:

  • exhaustive parity sweep of all 349,525 strings of length ≤ 9 over {$, \, a, \n} (prefixed with $$), old regex (through the parity gate) vs scanner: 0 mismatches on both the accepted set and the matched content;
  • 131,072 backslashes: 10,045ms → 0ms (65,536: 2,581ms → 0ms);
  • 5 new unit tests, including the adversarial input asserted under 500ms and never tokenized as display math.

Re-verified: the touched suites 53/53, tsc --noEmit clean, ESLint 0 errors, CommonMark/GFM conformance unchanged (1344 passed; the same three #4934 round-trip baseline failures as clean develop).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Render formulas between two $$ on the same line

1 participant