Skip to content

Typeset block $$…$$ math in display style, not text style - #153

Open
manemajef wants to merge 1 commit into
nodes-app:mainfrom
manemajef:fix/block-latex-display-style
Open

Typeset block $$…$$ math in display style, not text style#153
manemajef wants to merge 1 commit into
nodes-app:mainfrom
manemajef:fix/block-latex-display-style

Conversation

@manemajef

@manemajef manemajef commented Aug 12, 2026

Copy link
Copy Markdown

The problem

SwiftMathBridge hardcodes labelMode = .text, so $$ … $$ blocks are typeset in
text style — the style meant for math sitting inside a line of prose. Block math
should be typeset in display style. The visible difference:

image

Limits sit beside \sum and \int instead of above and below them, fractions
render at script size, and large operators don't scale up.

The engine already knows which is which — MarkdownToken.kind distinguishes
.inlineLatex from .blockLatex, and block LaTeX is already laid out as a
centered standalone block. The information just stopped at the LatexRenderer
boundary: both styling paths call render(latex:fontSize:theme:) with the
delimiter-free content, so $E=mc^2$ and $$E=mc^2$$ produce byte-identical
calls into the renderer.

The change

  • LatexRenderMode (.inline / .display), passed to a new mode-aware
    LatexRenderer.render overload.
  • Both styling call sites route their existing token kind:
    MarkdownStyler+Latex.swift sends .display for block and .inline for body
    math, MarkdownStyler+Tables.swift sends .inline for math in table cells.
  • SwiftMathBridge maps the mode onto labelMode, and folds it into both the
    in-memory cache key and the SHA-256 disk-cache filename — without that, a
    warmed inline entry would be served back for the same formula in display mode.

Compatibility

Both overloads have default implementations, so a conformer implements whichever
one it cares about and existing renderers keep compiling untouched. The
mode-aware default forwards to the mode-less method; the mode-less default
returns nil, which bottoms out the chain and is already the documented
"cannot produce an image" result. The engine only ever calls the mode-aware
overload.

Embedders using the bundled SwiftMathBridge will see their block math reflow on
upgrade — that's the fix, but it is a visible change: for $$\sum_{i=1}^{n} x_i$$
at 40pt the image goes from 130×51 to 97×102. Direct render(latex:fontSize:theme:)
callers are unaffected and still get text style. Happy to gate this behind a
BlockLatexStyle flag if you'd rather it be opt-in.

Tests

New MarkdownEngineLatexTests target for the tests that need SwiftMath, so the
core MarkdownEngineTests target stays free of that transitive dependency as
Package.swift describes. Mode routing itself is tested in MarkdownEngineTests
against a stub renderer, no SwiftMath needed.

  • swift build
  • swift test --parallel — 348 tests in 60 suites, plus 3 in MarkdownEngineLatexTests

Rebased onto f6137df.

@manemajef
manemajef marked this pull request as ready for review August 12, 2026 23:41
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.

1 participant