diff --git a/news/changelog-1.12.md b/news/changelog-1.12.md index 1058d106591..5d06e8b9277 100644 --- a/news/changelog-1.12.md +++ b/news/changelog-1.12.md @@ -13,6 +13,7 @@ All changes included in 1.12: - ([jgm/pandoc#11831](https://github.com/jgm/pandoc/pull/11831)): HTML documents using `theme: pandoc` pick up Pandoc 3.13's style updates. Links now inherit the surrounding text color unless `linkcolor` is set, horizontal rules and table borders follow the text color, and printed output drops backgrounds and the fixed 12pt font size, rendering at the 11pt print size used by other Quarto HTML themes. Pandoc 3.13's automatic dark mode is not enabled for `theme: pandoc`. - ([jgm/pandoc#11845](https://github.com/jgm/pandoc/issues/11845)): In Word output, cross-reference targets are now hidden bookmarks with generated names instead of their Quarto id (`fig-plot`). Cross-reference links inside the document still work, but a link or script that looks a bookmark up by its Quarto id from outside the document, such as `report.docx#fig-plot` or `officer`, VBA or `python-docx` code, no longer finds it. - ([jgm/pandoc 3.13](https://github.com/jgm/pandoc/releases/tag/3.13)): A YAML bibliography file with a duplicated key, such as two `title` fields in one reference, now stops the render with an error giving the file, line and column. Before, the last value was kept silently. Remove the duplicate key to render again. + - ([jgm/pandoc@c73a35a](https://github.com/jgm/pandoc/commit/c73a35a2e7ed1144132f1e533b4f0ae4c3648143)): Support Pandoc's `--math-method` option in `quarto render`, so that `--math-method=katex` works with `--embed-resources` and keeps math intact in `llms.md` output, like `--katex` does. ## Accessibility diff --git a/src/command/render/flags.ts b/src/command/render/flags.ts index 10be31e5b33..9b3f89d1cc3 100644 --- a/src/command/render/flags.ts +++ b/src/command/render/flags.ts @@ -14,6 +14,7 @@ import { kDate, kEmbedResources, kListings, + kMathMethod, kNumberOffset, kNumberSections, kReferenceLocation, @@ -204,6 +205,18 @@ export async function parseRenderFlags(args: string[]) { arg = argsStack.shift(); break; + case `--${kMathMethod}`: { + // METHOD[:URL]; the URL itself contains ':', so split on the first one + arg = argsStack.shift(); + if (arg) { + const colon = arg.indexOf(":"); + flags[kMathMethod] = colon === -1 + ? { method: arg } + : { method: arg.slice(0, colon), url: arg.slice(colon + 1) }; + } + break; + } + case "--execute": flags.execute = true; arg = argsStack.shift(); diff --git a/src/command/render/template.ts b/src/command/render/template.ts index 7870e772728..55e2d9e9f06 100644 --- a/src/command/render/template.ts +++ b/src/command/render/template.ts @@ -26,6 +26,7 @@ import { normalizePath } from "../../core/path.ts"; import { isGlob } from "../../core/lib/glob.ts"; import { ProjectContext } from "../../project/types.ts"; import { isWindows } from "../../deno_ral/platform.ts"; +import { resolveHtmlMathMethod } from "../../format/html/format-html-math.ts"; export const kPatchedTemplateExt = ".patched"; export const kTemplatePartials = "template-partials"; @@ -214,11 +215,8 @@ function applyTemplatePatches( } function mathConfig(format: Format, flags?: RenderFlags) { - // if any command line math flags were passed then bail - if ( - flags?.mathjax || flags?.katex || flags?.webtex || flags?.gladtex || - flags?.mathml - ) { + // if a command line math flag chose the method, Pandoc handles it + if (resolveHtmlMathMethod(format, flags)?.fromFlag) { return undefined; } diff --git a/src/config/constants.ts b/src/config/constants.ts index d147fca885f..2637d251e03 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -609,6 +609,7 @@ export const kKatex = "katex"; export const kMathml = "mathml"; export const kGladtex = "gladtex"; export const kWebtex = "webtex"; +export const kMathMethod = "math-method"; // metadata fields export const kQuartoInternal = "quarto-internal"; diff --git a/src/config/types.ts b/src/config/types.ts index 97006005c5d..fef150450f1 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -154,6 +154,7 @@ import { kManuscriptMecaBundle, kMarkdownHeadings, kMathjax, + kMathMethod, kMathml, kMergeIncludes, kMermaidFormat, @@ -645,6 +646,7 @@ export interface PandocFlags { [kMathml]?: boolean; [kGladtex]?: boolean; [kWebtex]?: boolean; + [kMathMethod]?: { method: string; url?: string }; } // the requested pdf engine, it's options, and the bib engine diff --git a/src/format/html/format-html-math.ts b/src/format/html/format-html-math.ts index da40b0406b9..5c18d77a1f3 100644 --- a/src/format/html/format-html-math.ts +++ b/src/format/html/format-html-math.ts @@ -7,14 +7,14 @@ import { kHtmlEmptyPostProcessResult } from "../../command/render/constants.ts"; import { Document } from "../../core/deno-dom.ts"; -import { kHtmlMathMethod } from "../../config/constants.ts"; +import { kHtmlMathMethod, kMathMethod } from "../../config/constants.ts"; import { Format, PandocFlags } from "../../config/types.ts"; import { MathMethods } from "../../resources/types/schema-types.ts"; export interface HtmlMathMethod { method: MathMethods; url?: string; - // true when a command line flag (--katex, --mathjax, ...) chose the method + // true when a command line flag (--math-method, --katex, ...) chose the method fromFlag: boolean; } @@ -29,6 +29,14 @@ export function resolveHtmlMathMethod( format: Format, flags?: PandocFlags, ): HtmlMathMethod | undefined { + const mathMethod = flags?.[kMathMethod]; + if (mathMethod) { + return { + method: mathMethod.method as MathMethods, + url: mathMethod.url, + fromFlag: true, + }; + } const flagMethod = kMathFlags.find((method) => flags?.[method]); if (flagMethod) { return { method: flagMethod, fromFlag: true }; diff --git a/tests/docs/render/math-method-flag.qmd b/tests/docs/render/math-method-flag.qmd new file mode 100644 index 00000000000..5c08cddab0b --- /dev/null +++ b/tests/docs/render/math-method-flag.qmd @@ -0,0 +1,12 @@ +--- +title: "Math method chosen with the --math-method command line option" +format: html +--- + +Inline math $x^2$. + +$$ +E = mc^2 +$$ {#eq-energy} + +See @eq-energy. diff --git a/tests/smoke/render/render-math-method-flag.test.ts b/tests/smoke/render/render-math-method-flag.test.ts new file mode 100644 index 00000000000..0aa2f56ea50 --- /dev/null +++ b/tests/smoke/render/render-math-method-flag.test.ts @@ -0,0 +1,32 @@ +/* + * render-math-method-flag.test.ts + * + * Pandoc 3.11 replaced --katex, --mathjax, ... with --math-method=METHOD[:URL]. + * Quarto must see the method chosen that way, as it does for the older flags. + * + * Copyright (C) 2026 Posit Software, PBC + */ + +import { docs, outputForInput } from "../../utils.ts"; +import { ensureFileRegexMatches, noErrorsOrWarnings } from "../../verify.ts"; +import { testRender } from "./render.ts"; + +const input = docs("render/math-method-flag.qmd"); +const output = outputForInput(input, "html"); + +// With embed-resources, Pandoc embeds the KaTeX library itself (its error +// strings are in the page); Quarto must not swap in its MathJax loader. +testRender(input, "html", true, [ + noErrorsOrWarnings, + ensureFileRegexMatches(output.outputPath, [/KaTeX parse error/], [ + /mathjax@3\/es5\/tex-chtml-full\.js/, + ]), +], {}, ["--math-method=katex", "--embed-resources"]); + +// Without embed-resources, Quarto's KaTeX post-processor runs +testRender(input, "html", false, [ + noErrorsOrWarnings, + ensureFileRegexMatches(output.outputPath, [ + /window\.backupDefine = window\.define/, + ]), +], {}, ["--math-method", "katex"]); diff --git a/tests/unit/format-html-math.test.ts b/tests/unit/format-html-math.test.ts index f0a7cce9b8e..1b00b8b7101 100644 --- a/tests/unit/format-html-math.test.ts +++ b/tests/unit/format-html-math.test.ts @@ -61,3 +61,20 @@ async () => { assertEquals(resolveHtmlMathMethod(createMockFormat()), undefined); assertEquals(resolveHtmlMathMethod(createMockFormat(), {}), undefined); }); + +unitTest("resolveHtmlMathMethod - --math-method flag", //deno-lint-ignore require-await +async () => { + const format = createMockFormat({ + pandoc: { "html-math-method": "mathjax" }, + }); + assertEquals( + resolveHtmlMathMethod(format, { + "math-method": { method: "katex", url: "https://example.com/katex/" }, + }), + { method: "katex", url: "https://example.com/katex/", fromFlag: true }, + ); + assertEquals( + resolveHtmlMathMethod(format, { "math-method": { method: "plain" } }), + { method: "plain", url: undefined, fromFlag: true }, + ); +}); diff --git a/tests/unit/render-flags.test.ts b/tests/unit/render-flags.test.ts new file mode 100644 index 00000000000..c689fe03297 --- /dev/null +++ b/tests/unit/render-flags.test.ts @@ -0,0 +1,25 @@ +/* + * render-flags.test.ts + * + * Copyright (C) 2026 Posit Software, PBC + */ + +import { assertEquals } from "../asserts.ts"; +import { parseRenderFlags } from "../../src/command/render/flags.ts"; +import { unitTest } from "../test.ts"; + +unitTest("parseRenderFlags - --math-method=METHOD:URL", async () => { + const flags = await parseRenderFlags([ + "--math-method=katex:https://example.com/katex/", + ]); + assertEquals(flags["math-method"], { + method: "katex", + url: "https://example.com/katex/", + }); +}); + +unitTest("parseRenderFlags - --math-method METHOD", async () => { + const flags = await parseRenderFlags(["--math-method", "katex", "--toc"]); + assertEquals(flags["math-method"], { method: "katex" }); + assertEquals(flags.toc, true); +});