Skip to content

Extract KaTeX sources before Pandoc and render placeholders in plugin#1585

Closed
davidmerfield wants to merge 1 commit into
masterfrom
codex/add-katex-source-extraction-helper
Closed

Extract KaTeX sources before Pandoc and render placeholders in plugin#1585
davidmerfield wants to merge 1 commit into
masterfrom
codex/add-katex-source-extraction-helper

Conversation

@davidmerfield

Copy link
Copy Markdown
Owner

Motivation

  • Ensure KaTeX TeX sources are preserved across Pandoc conversion by replacing balanced $$...$$ with Pandoc-safe HTML placeholders containing only the raw TeX (no $$), so the KaTeX plugin can render them reliably after conversion.
  • Avoid restoring literal $$...$$ after Pandoc and keep the existing -tex_math_dollars Pandoc extension to prevent Pandoc from interfering with math handling.

Description

  • Added a reusable helper extractMathSources(input) in app/build/plugins/katex/source.js that finds balanced $$...$$, leaves unmatched $$ untouched, stores only the TeX source (no delimiters), HTML-escapes &, <, and >, and emits inline placeholders <span class="blot-katex-source" data-display="false">...</span> or display placeholders <pre class="blot-katex-source" data-display="true">...</pre> depending on block shape.
  • Wired the helper into app/build/converters/markdown/convert.js so extraction runs before the indentation pass and before writing to pandoc.stdin via text = safely(extractMathSources, text);.
  • Updated the KaTeX plugin in app/build/plugins/katex/index.js to render preserved placeholders directly with a new renderSourcePlaceholders($) step that replaces .blot-katex-source elements with katex.renderToString output based on the element body and data-display attribute, rather than restoring $$-delimited text.
  • Kept the existing -tex_math_dollars Pandoc extension active so Pandoc will not produce its own math output.

Testing

  • Ran inline Node assertions that exercise extractMathSources behavior for inline, display, and unmatched cases; these assertions passed (node - <<'NODE' ... NODE).
  • Performed syntax checks with node -c on app/build/plugins/katex/source.js, app/build/converters/markdown/convert.js, and app/build/plugins/katex/index.js, all of which succeeded.
  • Attempted to run the plugin integration test script (./scripts/tests/invoke.sh app/build/plugins/katex) but it could not complete in this environment because Docker is not available (test runner requires Docker).

Codex Task

@cursor

cursor Bot commented Jul 17, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c70a7dff10

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// indentation in text! More discussion of this issue:
// https://github.com/jgm/pandoc/issues/1841
debug("Pre-katex-source", text);
text = safely(extractMathSources, text);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Respect disabled KaTeX before extracting placeholders

When a markdown/txt entry contains $$...$$ and the blog has plugins.katex.enabled = false, this unconditional conversion still rewrites the source to .blot-katex-source HTML before the plugin stage decides to skip KaTeX. The build pipeline runs converters before Plugins.convert, and the existing disabled-plugin case in app/build/tests/plugins.js:125-135 expects the literal $$a+b$$ to remain; with this change the final HTML leaks <span class="blot-katex-source" ...> instead. Gate this extraction on the plugin being enabled or restore the original delimiters when the plugin is skipped.

Useful? React with 👍 / 👎.

let position = 0;

while (position < input.length) {
const start = input.indexOf(delimiter, position);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip code regions when extracting math sources

For markdown inputs that document TeX literally, such as raw <code>$$a+b$$</code>/<pre>$$a+b$$</pre> or fenced/backtick code, this raw string scan replaces the delimiters before Pandoc has identified code regions. That bypasses the renderer's SKIP_TAGS behavior and the existing KaTeX fixtures (skip-code.txt, skip-pre.txt) will either render math inside code/pre or show placeholder HTML in code blocks instead of the literal $$...$$. The extractor needs to be Markdown/HTML-context aware or run only on eligible text nodes.

Useful? React with 👍 / 👎.

const display = isDisplayMath(input, start, sourceStart, afterEnd);

output += input.slice(position, start);
output += placeholder(source, display);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid injecting placeholders into attributes

When a markdown entry contains literal dollar pairs inside an HTML attribute, such as <img alt="price $$x$$"> or a link/image title, this replacement inserts a quoted <span class="blot-katex-source" ...> fragment into the attribute before Pandoc parses the HTML. The previous renderer only visited parsed text nodes, so attributes stayed literal; this now terminates the attribute value early and can leave malformed HTML or stray placeholder nodes in the output. Limit extraction to real text content rather than scanning attribute strings.

Useful? React with 👍 / 👎.

const escaped = escapeHtml(source);

if (display) {
return '<pre class="blot-katex-source" data-display="true">' + escaped + "</pre>";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve paragraph context for display math

For a normal standalone display equation such as $$\nE=mc^2\n$$, this emits a block-level <pre> before Pandoc runs, so Pandoc preserves it as raw HTML instead of producing the paragraph that the existing KaTeX display fixture expects (<p><span class="katex-display">...). When the KaTeX plugin later replaces the <pre>, the result is a top-level display span and surrounding Markdown paragraph/list structure can change. Use an inline-safe placeholder or rewrap display output to keep the converter's prior HTML shape.

Useful? React with 👍 / 👎.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant