Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3b6fbda
Update Pandoc to 3.13
cscheid Nov 3, 2026
b3c9e58
Remove stray src/deno.lock committed in the Pandoc 3.13 bump
cderv Nov 4, 2026
cc8eb87
Sync beamer toc partial with Pandoc 3.11 duplicate-TOC fix
cderv Nov 4, 2026
fe73595
Bump Pandoc version constraint in quarto check to 3.13
cderv Nov 5, 2026
78f3873
Port Pandoc 3.13 typst terms hanging indent and keyword nowrap
cderv Nov 5, 2026
b64e5b6
typst: port Pandoc 3.13 csl-settings template block for citeproc bibl…
cderv Nov 5, 2026
5047caf
typst: alias divider() to Quarto's horizontalrule for Pandoc 3.13
cderv Nov 5, 2026
ddb043b
typst: use Typst 0.15 native std.divider for horizontal rules
cderv Nov 5, 2026
98ebdd1
changelog: typst horizontal rule change from Pandoc 3.13
cderv Nov 5, 2026
f04fbec
changelog: move typst hr entry under Dependencies pandoc line
cderv Nov 5, 2026
948decf
latex/beamer: port Pandoc 3.13 caption setup, drop footnotehyper long…
cderv Nov 6, 2026
df8b342
html: port Pandoc 3.13 styles.html print, link and border updates
cderv Nov 6, 2026
a2a56b4
html: move theme: pandoc print styles after the base rules
cderv Nov 6, 2026
13a079a
new .gitignore from testing
cderv Nov 6, 2026
0e3d656
typst: require Typst 0.15 for a custom QUARTO_TYPST binary
cderv Nov 6, 2026
aaf4fd7
html: place theme: pandoc print block at the end, as Pandoc does
cderv Nov 6, 2026
fa71e31
typst: cite the right upstream issue for the leading-dot workaround
cderv Nov 9, 2026
c7291f3
revealjs: remove the stale template patch script
cderv Nov 9, 2026
eb9f438
tests: check docx crossref ids map to their bookmarks and links
cderv Nov 9, 2026
291a030
tests: pin pptx layout for bullets, table, bullets on one slide
cderv Nov 9, 2026
290dfc1
docs: add llm-docs guide for pptx smoke tests
cderv Nov 9, 2026
72da3c9
tests: import assert from tests/asserts.ts in docx crossref test
cderv Nov 10, 2026
85c7785
tests: match Pandoc 3.13 tight Typst terms in nested definition list
cderv Nov 10, 2026
700e6ea
tests: update docusaurus-md title snapshot for Pandoc 3.13 code fences
cderv Nov 10, 2026
52cf689
tests: drop duplicate key from delimited YAML bibliography fixture
cderv Nov 10, 2026
ec5ca41
tests: check a duplicate key in a YAML bibliography fails the render
cderv Nov 10, 2026
01cdb23
news: note Typst tight definition list layout from Pandoc 3.13
cderv Nov 10, 2026
1ba22f3
news: note hidden, hashed docx bookmark names from Pandoc 3.12
cderv Nov 10, 2026
b3aa64f
news: use backticks for package names in docx bookmark note
cderv Nov 10, 2026
0203480
tests: expand {{bookmark:<id>}} in docx XPath and regex checks
cderv Nov 10, 2026
bb45b57
tests: point docx-float-options-1 negative check at its real crossref…
cderv Nov 10, 2026
3b8aa04
tests: regenerate 8507 docx snapshot for Pandoc 3.13
cderv Nov 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .claude/rules/testing/pptx-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
paths:
- tests/docs/smoke-all/pptx/**
---

# pptx Tests

How the `ensurePptx*` verifiers address slides, their argument shapes, and why layout assertions depend on the bundled Pandoc: `llm-docs/pptx-testing.md`.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ package/dist/**
/tests/test-out.json
*~
.env
# deno lock file generated by test runs (the root deno.lock is committed)
# deno lock files generated outside the pinned root lockfile (the root deno.lock is committed)
tests/deno.lock
src/deno.lock

# deno_std library
src/resources/deno_std/cache
Expand Down
2 changes: 1 addition & 1 deletion configuration
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
export DENO=v2.9.8
# TODO figure out where 0.1.41 apple silicon libs are available
export DENO_DOM=v0.1.41-alpha-artifacts
export PANDOC=3.10
export PANDOC=3.13
export DARTSASS=1.107.1
export ESBUILD=0.28.2
export TYPST=0.15.1
Expand Down
2 changes: 1 addition & 1 deletion llm-docs/pandoc-quarto-latex-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ Pandoc's `common.latex` is copied as `latex.common`; Quarto maintains its own `c

| File | Purpose |
| ---------------- | --------------------------------------------------------------------------- |
| `tables.tex` | Table packages (longtable, booktabs, array, multirow) and footnote handling |
| `tables.tex` | Table packages (longtable, booktabs, array, multirow) and caption setup |
| `graphics.tex` | graphicx package and `\pandocbounded` command for auto-scaling images |
| `citations.tex` | CSL citation definitions (`\citeproc`, `CSLReferences` environment) |
| `babel-lang.tex` | Babel language configuration and font setup |
Expand Down
7 changes: 4 additions & 3 deletions llm-docs/pandoc-quarto-typst-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Two files are copied from Pandoc for typst support:

**default.typst** (becomes `typst.template`): The main Pandoc template that orchestrates the document structure. It:
- Defines a horizontal rule helper
- Sets up term list rendering with indented descriptions
- Sets up term list rendering with a hanging indent
- Configures table styling with no strokes
- Sets figure caption positions for tables (top) and images (bottom)
- Optionally includes syntax highlighting definitions
Expand Down Expand Up @@ -86,8 +86,9 @@ Combines Pandoc definitions with Quarto-specific functionality:

**From Pandoc**:
- `content-to-string` helper to extract text from content nodes (used for PDF metadata and link colors)
- `horizontalrule` definition for horizontal rules
- Term list show rule with indented descriptions
- `horizontalrule` definition (a centered 25-75% line, kept for `notes.typ` and external templates that call `#horizontalrule`). Pandoc 3.13's typst writer emits `#divider()` for HorizontalRule; Quarto deliberately does not define `divider`, so it resolves to Typst 0.15's native `std.divider` (full-width, restyleable via `#show divider:` rules), matching pandoc's default template behavior with typst >= 0.15
- Term list hanging indent (`#set terms(hanging-indent: 1.5em)`; Pandoc 3.13 dropped its custom `terms.item` show rule)
- CSL citeproc formatting (`#show <refs>: set par(...)` with `csl-hanging-indent` / `csl-entry-spacing` under `$if(csl-settings)$`, from Pandoc 3.12.1's `default.typst`; applies CSL hanging indent and entry spacing to Pandoc-citeproc bibliographies)
- Code highlighting definitions (conditionally included)

**Quarto additions**:
Expand Down
50 changes: 50 additions & 0 deletions llm-docs/pptx-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
main_commit: 38e34ec50
analyzed_date: 2026-11-09
key_files:
- tests/verify.ts
- tests/smoke/smoke-all.test.ts
- tests/docs/smoke-all/pptx/bullets-table-bullets-one-slide.qmd
---

# Testing PowerPoint (pptx) output

pptx is tested through smoke-all documents (`tests/docs/smoke-all/`), with the verifiers `ensurePptxXpath`, `ensurePptxLayout`, `ensurePptxMaxSlides` and `ensurePptxRegexMatches` in `tests/verify.ts`. Few tests exist; for one worth copying see `tests/docs/smoke-all/pptx/bullets-table-bullets-one-slide.qmd`.

## How a verifier reads the deck

`withPptxContent` (`tests/verify.ts`) copies the `.pptx`, unzips it, and reads `ppt/slides/slide<N>.xml` (or its `_rels/slide<N>.xml.rels` for layouts). Everything is per slide number.

- **Slide 1 is the generated title slide** whenever the document has a `title` (and `author`/`date`). The first slide made from a `##` heading is slide 2.
- **Text before the first heading becomes its own slide.** Put the scenario explanation of a test in an HTML comment, not in body prose, or the slide count changes.

## Verifier arguments in `_quarto: tests: pptx:`

| Key | Value | Notes |
|---|---|---|
| `ensurePptxMaxSlides` | `- N` | Fails if slide N+1 exists. A ceiling, not an exact count. Also fails if slide N is missing. |
| `ensurePptxLayout` | `- [N, "Layout name"]`, one entry per slide | Layout name is the `p:cSld/@name` of the slide's layout. |
| `ensurePptxXpath` | `- [N, [must-match xpaths], [must-not-match xpaths]]` | Namespaces such as `a:` and `p:` are available, e.g. `//a:tbl`. |
| `ensurePptxRegexMatches` | `- [regexes]` then `- N` | Regexes run on the raw slide XML. Slide number is the second item, after the regex list. |

Pass a list of lists to check several slides with `ensurePptxLayout` or `ensurePptxXpath`; a single `[N, ...]` entry also works.

## Layouts come from Pandoc

Pandoc's pptx writer chooses the layout (Title Slide, Section Header, Two Content, Comparison, Content with Caption, Blank, Title and Content) from the slide content, using the layouts of its default `reference-doc`. A Pandoc upgrade can change both the choice and the slide splitting, so layout and slide-count assertions are characterization tests of the bundled Pandoc, not of Quarto code. Say so in the test comment, and re-check them on each Pandoc bump.

Pandoc 3.13 example: text followed by a table gets "Title and Content" where Pandoc 3.10 chose "Content with Caption", and a bullet list, a table and another bullet list stay on one slide.

## Comparing against another Pandoc version

To show that a pptx test depends on the Pandoc version, run it with `QUARTO_PANDOC` set to the `bin/tools/pandoc` of an installed Quarto release (see the `qvm` skill), then run it again without. `QUARTO_<BINARY>` overrides any bundled tool path.

## Inspecting a deck by hand

```bash
quarto render doc.qmd --to pptx
mkdir x && cd x && unzip -q ../doc.pptx
ls ppt/slides/*.xml # slide count
cat ppt/slides/_rels/slide2.xml.rels # which slideLayout<N>.xml
grep -o '<p:cSld name="[^"]*"' ppt/slideLayouts/slideLayout2.xml
```
6 changes: 6 additions & 0 deletions news/changelog-1.12.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ All changes included in 1.12:
- Update `esbuild` to 0.28.2 (fixes a CSS minification bug involving `&` and a TypeScript import-alias tree-shaking bug).
- Update `typst-gather` to 0.2.4.
- Update `verapdf` to 1.30.3 (used by `quarto install verapdf` for PDF/A validation).
- Update `pandoc` to 3.13
- ([jgm/pandoc#11540](https://github.com/jgm/pandoc/issues/11540)): Horizontal rules (`---`) in Typst output are now full-width, following Pandoc 3.13's use of Typst 0.15's native `divider` element, instead of the previous centered half-width line. Restyle them with `#show divider: set line(stroke: 2pt)` in a raw Typst block or a custom template. A Typst binary set through `QUARTO_TYPST` must now be version 0.15 or later.
- ([jgm/pandoc#11748](https://github.com/jgm/pandoc/pull/11748)): In Typst output, a single-paragraph definition in a tight definition list now sits on the same line as its term instead of below it. Definitions in loose lists, or made of several blocks, still start below the term.
- ([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.

## Accessibility

Expand Down
2 changes: 1 addition & 1 deletion src/command/check/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ async function checkVersions(conf: CheckConfiguration) {
// file is in an awkward format and it is not packaged
// with our installers
const versionConstraints: [string | undefined, string, string][] = [
[pandocVersion, "3.10.0", "Pandoc"],
[pandocVersion, "3.13.0", "Pandoc"],
[sassVersion, "1.107.1", "Dart Sass"],
[denoVersion, "2.9.8", "Deno"],
[typstVersion, "0.15.1", "Typst"],
Expand Down
3 changes: 2 additions & 1 deletion src/core/bibliography.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ export async function renderToCSLJSON(
// Pandoc has no reader for a YAML bibliography: read as markdown, it
// only works when wrapped in --- delimiters. Like --bibliography, use
// the first YAML document, either a references: map or a bare array.
// json: true lets a duplicate key win last, as pandoc does.
// json: true lets a duplicate key win last instead of throwing here;
// pandoc itself rejects duplicate keys when it reads the bibliography.
const firstDoc = loadAll(Deno.readTextFileSync(absBiblioPath), null, {
schema: kBibliographyYamlSchema,
json: true,
Expand Down
2 changes: 1 addition & 1 deletion src/core/typst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ export async function validateRequiredTypstVersion() {
if (Deno.env.get("QUARTO_TYPST")) {
const version = await typstVersion();
if (version) {
const required = ">=0.8";
const required = ">=0.15";
if (!satisfies(version, required)) {
error(
"An updated version of the Typst CLI is required for rendering typst documents.\n",
Expand Down
2 changes: 1 addition & 1 deletion src/resources/filters/quarto-pre/bibliography-formats.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function bibliography_formats()
elseif _quarto.format.isTypstOutput() and doc.meta.bibliography ~= nil
and quarto.doc.cite_method() ~= "citeproc" then
-- pandoc's Typst writer backslash-escapes any metadata string starting
-- with a literal dot (jgm/pandoc#11511). Rewriting each bibliography
-- with a literal dot (jgm/pandoc#11761). Rewriting each bibliography
-- path as a raw typst inline bypasses that escaping entirely.
--
-- Skip this when citeproc is handling citations natively (cite-method
Expand Down
3 changes: 0 additions & 3 deletions src/resources/formats/beamer/pandoc/beamer.template
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,6 @@ $endif$
\setcounter{tocdepth}{$toc-depth$}
\tableofcontents
\end{frame}
\setcounter{tocdepth}{$toc-depth$}
\tableofcontents
}
$endif$
$if(lof)$
\listoffigures
Expand Down
5 changes: 2 additions & 3 deletions src/resources/formats/beamer/pandoc/latex.common
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ $-- tables
$--
$if(tables)$
\usepackage{longtable,booktabs,array}
\usepackage{caption}
\captionsetup[table]{skip=6pt}
\newcounter{none} % for unnumbered tables
$if(multirow)$
\usepackage{multirow}
Expand All @@ -86,9 +88,6 @@ $else$
\makeatletter
\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
\makeatother
% Allow footnotes in longtable head/foot
\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
\makesavenoteenv{longtable}
$endif$
$endif$
$--
Expand Down
5 changes: 2 additions & 3 deletions src/resources/formats/beamer/pandoc/tables.tex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
$--
$if(tables)$
\usepackage{longtable,booktabs,array}
\usepackage{caption}
\captionsetup[table]{skip=6pt}
\newcounter{none} % for unnumbered tables
$if(multirow)$
\usepackage{multirow}
Expand All @@ -20,8 +22,5 @@
\makeatletter
\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
\makeatother
% Allow footnotes in longtable head/foot
\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
\makesavenoteenv{longtable}
$endif$
$endif$
3 changes: 0 additions & 3 deletions src/resources/formats/beamer/pandoc/toc.tex
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
\setcounter{tocdepth}{$toc-depth$}
\tableofcontents
\end{frame}
\setcounter{tocdepth}{$toc-depth$}
\tableofcontents
}
$endif$
$if(lof)$
\listoffigures
Expand Down
50 changes: 36 additions & 14 deletions src/resources/formats/html/pandoc/html.styles
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ $if(linestretch)$
line-height: $linestretch$;
$endif$
color: $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;
color: light-dark($if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$, $if(fontcolordark)$$fontcolordark$$else$#fdfdfd$endif$);
background-color: $if(backgroundcolor)$$backgroundcolor$$else$#fdfdfd$endif$;
background-color: light-dark($if(backgroundcolor)$$backgroundcolor$$else$#fdfdfd$endif$, $if(backgroundcolordark)$$backgroundcolordark$$else$#1a1a1a$endif$);
color-scheme:$if(fontcolor)$ light$elseif(backgroundcolor)$ light$elseif(fontcolordark)$$elseif(backgroundcolordark)$$else$ light$endif$$if(fontcolordark)$ dark$elseif(backgroundcolordark)$ dark$elseif(fontcolor)$$elseif(backgroundcolor)$$else$ dark$endif$;
}
body {
margin: 0 auto;
Expand All @@ -38,12 +41,16 @@ body {
}
@media print {
html {
background-color: $if(backgroundcolor)$$backgroundcolor$$else$white$endif$;
color-scheme: light only;
}
body {
html, body, pre, code {
background-color: transparent;
}
body, a, a:visited, blockquote {
color: black;
font-size: 12pt;
}
pre, code {
padding: 0;
}
p, h2, h3 {
orphans: 3;
Expand All @@ -56,11 +63,13 @@ body {
p {
margin: 1em 0;
}
a {
color: $if(linkcolor)$$linkcolor$$else$#1a1a1a$endif$;
}
a:visited {
color: $if(linkcolor)$$linkcolor$$else$#1a1a1a$endif$;
a, a:visited {
color: $if(linkcolor)$$linkcolor$$else$inherit$endif$;
$if(linkcolor)$
color: light-dark($linkcolor$, $if(linkcolordark)$$linkcolordark$$else$inherit$endif$);
$elseif(linkcolordark)$
color: light-dark(inherit, $linkcolordark$);
$endif$
}
img {
max-width: 100%;
Expand Down Expand Up @@ -89,8 +98,11 @@ li > ol, li > ul {
blockquote {
margin: 1em 0 1em 1.7em;
padding-left: 1em;
border-left: 2px solid #e6e6e6;
color: #606060;
border-left: 2px solid;
border-color: $if(quotebordercolor)$$quotebordercolor$$else$#e6e6e6$endif$;
border-color: light-dark($if(quotebordercolor)$$quotebordercolor$$else$#e6e6e6$endif$, $if(quotebordercolordark)$$quotebordercolordark$$else$#4c4c4c$endif$);
color: $if(quotecolor)$$quotecolor$$else$#606060$endif$;
color: light-dark($if(quotecolor)$$quotecolor$$else$#606060$endif$, $if(quotecolordark)$$quotecolordark$$else$#b6b6b6$endif$);
}
$if(abstract)$
div.abstract {
Expand All @@ -110,6 +122,11 @@ code {
font-family: $if(monofont)$$monofont$$else$Menlo, Monaco, Consolas, 'Lucida Console', monospace$endif$;
$if(monobackgroundcolor)$
background-color: $monobackgroundcolor$;
background-color: light-dark($monobackgroundcolor$, $if(monobackgroundcolordark)$$monobackgroundcolordark$$else$inherit$endif$);
padding: .2em .4em;
$elseif(monobackgroundcolordark)$
background-color: inherit;
background-color: light-dark(inherit, $monobackgroundcolordark$);
padding: .2em .4em;
$endif$
font-size: 85%;
Expand All @@ -120,6 +137,11 @@ pre {
margin: 1em 0;
$if(monobackgroundcolor)$
background-color: $monobackgroundcolor$;
background-color: light-dark($monobackgroundcolor$, $if(monobackgroundcolordark)$$monobackgroundcolordark$$else$inherit$endif$);
padding: 1em;
$elseif(monobackgroundcolordark)$
background-color: inherit;
background-color: light-dark(inherit, $monobackgroundcolordark$);
padding: 1em;
$endif$
overflow: auto;
Expand All @@ -135,7 +157,7 @@ pre code {
}
hr {
border: none;
border-top: 1px solid #1a1a1a;
border-top: 1px solid currentColor;
height: 1px;
margin: 1em 0;
}
Expand All @@ -157,11 +179,11 @@ $endif$
}
tbody {
margin-top: 0.5em;
border-top: 1px solid $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;
border-bottom: 1px solid $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;
border-top: 1px solid currentColor;
border-bottom: 1px solid currentColor;
}
th {
border-top: 1px solid $if(fontcolor)$$fontcolor$$else$#1a1a1a$endif$;
border-top: 1px solid currentColor;
padding: 0.25em 0.5em 0.25em 0.5em;
}
td {
Expand Down
Loading
Loading