Skip to content

Fix cell/outline breakage after single-line display math with attributes#1063

Open
max-nothacker wants to merge 1 commit into
quarto-dev:mainfrom
max-nothacker:bugfix/single-line-math-attr
Open

Fix cell/outline breakage after single-line display math with attributes#1063
max-nothacker wants to merge 1 commit into
quarto-dev:mainfrom
max-nothacker:bugfix/single-line-math-attr

Conversation

@max-nothacker

Copy link
Copy Markdown

Fixes #976

Problem

A single-line display math expression with a cross-reference label, e.g.

$$1+1$$ {#eq-spec0}

breaks the extension for the rest of the document: headings disappear from the Outline, LaTeX preview buttons vanish, and later code cells lose their Run Cell button ("Editor selection is not within an executable cell").

Root cause

In math_block() (packages/core/src/markdownit/math.ts), the single-line close check was

if (firstLine.trim().slice(-2) === "$$") {

which fails when an attribute block trails the closing $$. The rule then falls through to the multi-line scan looking for /^\$\$\s*(\{.*\})?\s*$/ on a later line — which never matches — so the loop runs to the end of the document and the math token swallows everything after the equation. Nothing downstream (headings, fences) is tokenized again. Full analysis in #976 (comment).

Fix

Recognize an optional trailing attribute block in the single-line case, mirroring the multi-line close regex, and store it in token.info the same way the multi-line path does (so single-line labeled equations also pick up the math preview decoration):

let attrStr = undefined;
const singleLineMatch = firstLine.trim().match(/^(.*)\$\$\s*(\{.*\})?\s*$/);
if (singleLineMatch) {
  firstLine = singleLineMatch[1];
  attrStr = singleLineMatch[2];
  found = true;
}

Unlabeled single-line math ($$1+1$$) takes the same path it did before ((.*) is greedy, so interior $$ behave as with the previous slice(-2) check), and the multi-line branch is untouched.

Tests

Added packages/core/test/markdownit-math.test.ts (same harness as the existing markdownit-divs.test.ts):

  1. single-line labeled equation followed by a {python} fence → one math_block with info === "{#eq-spec0}", fence still tokenized (the Quarto extension display math edge cases stops extension functionality for rest of document #976 symptom)
  2. single-line unlabeled equation → unchanged behavior
  3. multi-line equation with label on the closing line → unchanged behavior

yarn test in packages/core passes (5/5), and tsc --noEmit is clean.

🤖 Generated with Claude Code in the session with id 6b8b182e

The single-line close check in math_block() only recognized lines ending
in "$$", so "$$1+1$$ {#eq-spec0}" fell through to the multi-line scan,
which never finds a closing line and consumes the remainder of the
document into one math token. Everything after the equation (headings,
code cells) was no longer tokenized: no outline entries, no LaTeX
preview, and "Editor selection is not within an executable cell" when
running later cells.

Recognize an optional trailing attribute block in the single-line case,
mirroring the multi-line close regex, and store it in token.info the
same way. Adds unit tests for the single-line labeled, single-line
unlabeled, and multi-line labeled cases.

Fixes quarto-dev#976

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> in the session with id 6b8b182e
@posit-snyk-bot

posit-snyk-bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

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.

Quarto extension display math edge cases stops extension functionality for rest of document

2 participants