Skip to content

markdown: Add LaTeX math rendering support - #53150

Closed
n-WN wants to merge 6 commits into
zed-industries:mainfrom
n-WN:feature/markdown-latex-math
Closed

markdown: Add LaTeX math rendering support#53150
n-WN wants to merge 6 commits into
zed-industries:mainfrom
n-WN:feature/markdown-latex-math

Conversation

@n-WN

@n-WN n-WN commented Apr 4, 2026

Copy link
Copy Markdown

Summary

  • Parse InlineMath/DisplayMath events from pulldown-cmark instead of silently discarding them (add ENABLE_MATH to parser options)
  • Implement a custom GPUI backend for the ReX LaTeX typesetting engine, converting glyph outlines to Path primitives and fraction bars/rules to Quad primitives
  • Bundle XITS Math font (OFL-licensed) for OpenType MATH table support
  • Add async rendering with OnceLock caching following the existing mermaid diagram pattern
  • Display math ($$...$$) renders as centered block elements via ReX vector paths
  • Inline math ($...$) converts LaTeX to Unicode text and renders as italic styled text, preserving natural text flow

Screenshot

<img width="1648" height="977" alt="LaTeX math rendering in Zed markdown preview"" src="https://github.com/user-attachments/assets/dfe3f7e9-e04f-4cbc-8650-500cc7094a88" />

Architecture

Inline math ($...$):
  LaTeX source → latex_to_unicode() → italic styled text via push_text()

Display math ($$...$$):
  LaTeX source → pulldown-cmark → DisplayMath event
    → ReX parser → ReX layout engine → GpuiMathBackend
    → gpui::Path (glyph outlines) + gpui::Quad (rules/bars)
    → canvas element with paint_path() / paint_quad()

Display math rendering is cached per unique expression and runs on a background thread to avoid blocking the UI. Text color automatically adapts to the current theme (light/dark).

Known Limitations

  • Inline math uses Unicode approximation (superscripts ²³, Greek α β, operators ∩⊥·×) rather than full typeset rendering, since GPUI lacks inline replaced element support
  • Uses lnay's ReX fork with ttfparser-fontparser feature — ideally this would be upstreamed or vendored
  • Some LaTeX commands not supported by ReX (e.g. \begin{matrix} with escaped brackets) fall back to showing raw source

Closes #10899

Test plan

  • Verify display math ($$E = mc^2$$) renders as centered formula
  • Verify inline math ($x^2 + y^2$) renders within paragraph text flow
  • Verify complex expressions (fractions, subscripts, superscripts, radicals, matrices)
  • Verify error fallback shows raw LaTeX source when parsing fails
  • Verify rendering in both light and dark themes
  • Verify caching works (same expression not re-rendered on scroll)
  • Verify markdown preview in assistant panel with LLM-generated math

Release Notes:

  • Added LaTeX math rendering in markdown preview ($inline$ and $$display$$ math)

@cla-bot

cla-bot Bot commented Apr 4, 2026

Copy link
Copy Markdown

We require contributors to sign our Contributor License Agreement, and we don't have @n-WN on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@zed-community-bot zed-community-bot Bot added the first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions label Apr 4, 2026
@zed-codeowner-coordinator
zed-codeowner-coordinator Bot requested review from a team, nathansobo and osiewicz and removed request for a team April 4, 2026 14:16
Implement LaTeX math rendering in the markdown preview using the ReX
typesetting engine with a custom GPUI backend that converts glyph
outlines to Path primitives and rules to Quad primitives.

- Parse InlineMath/DisplayMath events from pulldown-cmark (previously discarded)
- Create GpuiMathBackend implementing ReX's Backend trait for native rendering
- Bundle XITS Math font for OpenType MATH table support
- Add async rendering with OnceLock caching (following the mermaid pattern)
- Display math renders as centered block elements
- Inline math renders as inline elements with text color adaptation

Closes zed-industries#10899

Release Notes:

- Added LaTeX math rendering in markdown preview ($inline$ and $$display$$ math)
@n-WN
n-WN force-pushed the feature/markdown-latex-math branch from 8b7da29 to 714ac56 Compare April 4, 2026 14:22
@cla-bot

cla-bot Bot commented Apr 4, 2026

Copy link
Copy Markdown

We require contributors to sign our Contributor License Agreement, and we don't have @n-WN on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@n-WN

n-WN commented Apr 4, 2026

Copy link
Copy Markdown
Author

I have read and signed the CLA at https://zed.dev/cla

@cla-bot check

@cla-bot

cla-bot Bot commented Apr 4, 2026

Copy link
Copy Markdown

We require contributors to sign our Contributor License Agreement, and we don't have @n-WN on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@cla-bot

cla-bot Bot commented Apr 4, 2026

Copy link
Copy Markdown

The cla-bot has been summoned, and re-checked this pull request!

@n-WN

n-WN commented Apr 4, 2026

Copy link
Copy Markdown
Author

@cla-bot check

@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Apr 4, 2026
@cla-bot

cla-bot Bot commented Apr 4, 2026

Copy link
Copy Markdown

The cla-bot has been summoned, and re-checked this pull request!

n-WN added 4 commits April 5, 2026 02:19
- Add Options::ENABLE_MATH to PARSE_OPTIONS so pulldown-cmark
  actually emits InlineMath/DisplayMath events
- Scale math rendering based on the actual base_text_style font size
  instead of hardcoded values
- Render at native ReX scale (1.0) and apply font-size scaling at
  display time for correct proportions

Release Notes:

- N/A
Instead of rendering inline math as a separate canvas element (which
breaks text flow), convert LaTeX to Unicode characters and render as
italic text via push_text. This preserves natural text reflow.

Covers superscripts, subscripts, Greek letters, common math operators,
and set theory symbols. Display math still uses canvas rendering.

Release Notes:

- N/A
Compute actual bounding box from rendered paths/rects instead of
relying on ReX layout dimensions, which underestimate size for
matrices and large delimiters. Normalize coordinates to start at
origin (0,0) so the canvas element properly allocates space.

Release Notes:

- N/A
ReX uses Y-down convention (matching screen coordinates), so the
layout-to-canvas transform should not flip Y. The previous sy: -scale
caused bracket and delimiter positions to be vertically mirrored
relative to matrix content. Font glyph outlines (Y-up) still flip
correctly via the separate glyph transform.

Release Notes:

- N/A
@n-WN

n-WN commented Apr 4, 2026

Copy link
Copy Markdown
Author

Screenshot

left fallback

截屏2026-04-05 上午4 27 29

- Fix extract_group to handle \command after ^ and _ (e.g. G^\perp → G⊥)
- Recursively convert LaTeX to Unicode inside super/subscript groups
- Preprocess \[ → [ and \] → ] for escaped bracket delimiters
- Style failed math rendering as monospace code blocks with background
  instead of raw plaintext

Release Notes:

- N/A
@BrannonKing

Copy link
Copy Markdown

Thanks for working on this! I'm really looking forward to real math equations in the AI chat window. Did you have some list of latex functions that you were working from? Or how did you decide which latex functions to support for the inline unicode translation? The unicode fraction slash character might be an interesting next step, as "frac" takes two parameters not one.

@MrSubidubi

Copy link
Copy Markdown
Member

Thank you very much for this and the time and effort that went into this! Furthermore, sorry for no reply yet - we are always cautious with such big changes and thus takes us some more time to get back here sometimes, more than we'd like.

Unfortunately, I am gonna close this out in favor of #54668 - that PR brings some Windows fixes already as well as an overall less invasive approach for the issue at hand. Thus, I decided we'll push that PR to completion. However, I already informed the contributor there that we should also take learnings from this Pr so that your effort here does not go to waste.

Hope you can understand that, in any case, thank you very much for this PR!

@MrSubidubi MrSubidubi closed this May 7, 2026
@n-WN

n-WN commented May 7, 2026

Copy link
Copy Markdown
Author

Thank you very much for this and the time and effort that went into this! Furthermore, sorry for no reply yet - we are always cautious with such big changes and thus takes us some more time to get back here sometimes, more than we'd like.

Unfortunately, I am gonna close this out in favor of #54668 - that PR brings some Windows fixes already as well as an overall less invasive approach for the issue at hand. Thus, I decided we'll push that PR to completion. However, I already informed the contributor there that we should also take learnings from this Pr so that your effort here does not go to waste.

Hope you can understand that, in any case, thank you very much for this PR!

I'm happy to see his effect, but do I have a chance to be a co-author, as some experimental attempts.

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

Labels

cla-signed The user has signed the Contributor License Agreement first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Markdown math support (Latex)

4 participants