From ddc41c499e3ee2089fa6cd9b9fda75babbe4c035 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 6 Oct 2026 18:05:48 +0200 Subject: [PATCH 1/2] Support lof and lot in Typst documents The schema has advertised lof and lot for Typst since book support landed, but the default Typst template never acted on them: only the TOC was mapped into article(), and Pandoc's own Typst template has no lists of figures or tables either. Setting them silently did nothing. The lists are rendered inside article(), right after the TOC, so a format that overrides typst-show.typ (orange-book draws its own lists inside book()) keeps control and does not get a second set. The outlines target Quarto's float kinds, since Quarto emits floats as figure(kind: "quarto-float-fig") and figure(kind: "quarto-float-tbl"), not Typst's native image/table kinds. Titles use the lookup LaTeX already uses: crossref lof-title / lot-title, else the language's crossref-lof-title / crossref-lot-title. An extension that ships its own typst-template.typ with Quarto's typst-show.typ gets "unexpected argument: lof" only when lof is set, the same contract toc-indent already has. Refs #14081 --- llm-docs/pandoc-quarto-typst-templates.md | 8 ++++- news/changelog-1.11.md | 1 + .../typst/pandoc/quarto/typst-show.typ | 8 +++++ .../typst/pandoc/quarto/typst-template.typ | 16 +++++++++ tests/docs/smoke-all/typst/lof-lot-false.qmd | 30 ++++++++++++++++ tests/docs/smoke-all/typst/lof-lot-lang.qmd | 35 +++++++++++++++++++ tests/docs/smoke-all/typst/lof-lot.qmd | 30 ++++++++++++++++ 7 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 tests/docs/smoke-all/typst/lof-lot-false.qmd create mode 100644 tests/docs/smoke-all/typst/lof-lot-lang.qmd create mode 100644 tests/docs/smoke-all/typst/lof-lot.qmd diff --git a/llm-docs/pandoc-quarto-typst-templates.md b/llm-docs/pandoc-quarto-typst-templates.md index f3358c9697d..13a81a93dc7 100644 --- a/llm-docs/pandoc-quarto-typst-templates.md +++ b/llm-docs/pandoc-quarto-typst-templates.md @@ -106,6 +106,7 @@ Corresponds to `conf()` in Pandoc's `template.typst`. Defines the `article()` fu - `title-size`, `subtitle-size` for customizable title sizing - `heading-family`, `heading-weight`, `heading-style`, `heading-color`, `heading-line-height` for brand typography - `toc`, `toc_title`, `toc_depth`, `toc_indent` for integrated table of contents +- `lof`, `lof-title`, `lot`, `lot-title` for lists of figures and tables (outlines of `quarto-float-fig` / `quarto-float-tbl` figures) **Functionality**: - Sets `document()` metadata (title, keywords, author string) for PDF accessibility @@ -113,7 +114,7 @@ Corresponds to `conf()` in Pandoc's `template.typst`. Defines the `article()` fu - Applies conditional font settings using `set ... if` pattern (Typst 0.14+) - Applies link colors using `content-to-string` helper - Renders the title block with thanks footnote, author grid, date, and abstract -- Optionally renders table of contents +- Optionally renders table of contents, then lists of figures and tables - Handles single or multi-column layout ### page.typ - Page Configuration @@ -143,6 +144,7 @@ Applies the `article()` function via a show rule, mapping Pandoc metadata and br - `linkcolor`, `citecolor`, `filecolor` → link color parameters - `keywords` → `keywords` - `toc`, `toc-title`, `toc-depth`, `toc-indent` → TOC parameters +- `lof`, `lot` → `lof`, `lot`; titles from `crossref.lof-title` / `crossref.lot-title`, else `quarto.language.crossref-lof-title` / `crossref-lot-title` (localized) - `columns` → `cols` **Brand.yaml Fallbacks** (used when Pandoc metadata not set): @@ -210,3 +212,7 @@ This is the copy of Pandoc's `default.typst`, kept for reference. It is used whe | `toc-title` | `toc_title` | - | | | `toc-depth` | `toc_depth` | - | | | `toc-indent` | `toc_indent` | - | Quarto extension | +| `lof` | `lof` | - | Quarto extension (Pandoc's Typst writer ignores it) | +| - | `lof-title` | - | `crossref.lof-title`, else `quarto.language.crossref-lof-title` | +| `lot` | `lot` | - | Quarto extension (Pandoc's Typst writer ignores it) | +| - | `lot-title` | - | `crossref.lot-title`, else `quarto.language.crossref-lot-title` | diff --git a/news/changelog-1.11.md b/news/changelog-1.11.md index eab91d51c80..744d72d9ce8 100644 --- a/news/changelog-1.11.md +++ b/news/changelog-1.11.md @@ -43,6 +43,7 @@ All changes included in 1.11: ### `typst` +- ([#14081](https://github.com/quarto-dev/quarto-cli/issues/14081)): Support `lof` and `lot` in Typst documents, which previously had no effect. The list titles follow `lang` and can be set with `crossref: lof-title` and `lot-title`. - ([#14847](https://github.com/quarto-dev/quarto-cli/pull/14847)): Fix `toc_title` auto-fallback in typst outline template that was ignoring the computed fallback value when `toc_title` is `none`. - ([#14947](https://github.com/quarto-dev/quarto-cli/issues/14947)): Fix Typst compilation failing with `invalid number suffix: px` when an image with alt text (`fig-alt`, `alt`, or an inline image caption) has its `width` or `height` in pixels. These images are now written by Pandoc's Typst writer like other images, which also fixes URL-encoded image paths and unsupported size units for them. diff --git a/src/resources/formats/typst/pandoc/quarto/typst-show.typ b/src/resources/formats/typst/pandoc/quarto/typst-show.typ index e929d2777e1..72fa761f832 100644 --- a/src/resources/formats/typst/pandoc/quarto/typst-show.typ +++ b/src/resources/formats/typst/pandoc/quarto/typst-show.typ @@ -97,5 +97,13 @@ $if(toc-indent)$ toc_indent: $toc-indent$, $endif$ toc_depth: $toc-depth$, +$if(lof)$ + lof: true, + lof-title: [$if(crossref.lof-title)$$crossref.lof-title$$else$$quarto.language.crossref-lof-title$$endif$], +$endif$ +$if(lot)$ + lot: true, + lot-title: [$if(crossref.lot-title)$$crossref.lot-title$$else$$quarto.language.crossref-lot-title$$endif$], +$endif$ doc, ) diff --git a/src/resources/formats/typst/pandoc/quarto/typst-template.typ b/src/resources/formats/typst/pandoc/quarto/typst-template.typ index cf1f8dd669c..e5ccc37f146 100644 --- a/src/resources/formats/typst/pandoc/quarto/typst-template.typ +++ b/src/resources/formats/typst/pandoc/quarto/typst-template.typ @@ -31,6 +31,10 @@ toc_title: none, toc_depth: none, toc_indent: 1.5em, + lof: false, + lof-title: none, + lot: false, + lot-title: none, doc, ) = { // Set document metadata for PDF accessibility @@ -135,6 +139,18 @@ ] } + if lof { + block(above: 0em, below: 2em)[ + #outline(title: lof-title, target: figure.where(kind: "quarto-float-fig")); + ] + } + + if lot { + block(above: 0em, below: 2em)[ + #outline(title: lot-title, target: figure.where(kind: "quarto-float-tbl")); + ] + } + doc } diff --git a/tests/docs/smoke-all/typst/lof-lot-false.qmd b/tests/docs/smoke-all/typst/lof-lot-false.qmd new file mode 100644 index 00000000000..05436c1a126 --- /dev/null +++ b/tests/docs/smoke-all/typst/lof-lot-false.qmd @@ -0,0 +1,30 @@ +--- +title: "No lists without lof and lot" +toc: true +format: typst +_quarto: + tests: + typst: + ensurePdfRegexMatches: + - - 'Table of contents' + - - 'List of Figures' + - 'List of Tables' +--- + +# Introduction + +Without `lof` or `lot`, no list of figures or tables is printed, even though the document has a figure, a table and a table of contents. + +::: {#fig-one} + +CONTENT + +A figure caption + +::: + +| a | b | +|---|---| +| 1 | 2 | + +: A table caption {#tbl-one} diff --git a/tests/docs/smoke-all/typst/lof-lot-lang.qmd b/tests/docs/smoke-all/typst/lof-lot-lang.qmd new file mode 100644 index 00000000000..6a7636146c2 --- /dev/null +++ b/tests/docs/smoke-all/typst/lof-lot-lang.qmd @@ -0,0 +1,35 @@ +--- +title: "Localised list titles" +lang: fr +lof: true +lot: true +crossref: + lot-title: "Mes tableaux" +format: typst +_quarto: + tests: + typst: + ensurePdfRegexMatches: + - # French default title for figures, crossref override for tables + - 'Liste des Figures[\s\S]*Une figure[\s\S]*Mes tableaux[\s\S]*Un tableau' + - - 'List of Figures' # English default must not leak through + - 'Liste des Tables' # crossref lot-title must win over the language title +--- + +# Introduction + +With `lang: fr`, the figure list takes its title from the French language file, while `crossref: lot-title` replaces the language title of the table list. + +::: {#fig-one} + +CONTENU + +Une figure + +::: + +| a | b | +|---|---| +| 1 | 2 | + +: Un tableau {#tbl-one} diff --git a/tests/docs/smoke-all/typst/lof-lot.qmd b/tests/docs/smoke-all/typst/lof-lot.qmd new file mode 100644 index 00000000000..282c16dfa14 --- /dev/null +++ b/tests/docs/smoke-all/typst/lof-lot.qmd @@ -0,0 +1,30 @@ +--- +title: "List of figures and tables" +lof: true +lot: true +format: typst +_quarto: + tests: + typst: + ensurePdfRegexMatches: + - # Both lists are rendered with their entries, before the body + - 'List of Figures[\s\S]*A figure caption[\s\S]*List of Tables[\s\S]*A table caption[\s\S]*Introduction' +--- + +# Introduction + +With `lof: true` and `lot: true`, a list of figures and a list of tables are printed after the title block and before this heading, as in LaTeX output (#14081). + +::: {#fig-one} + +CONTENT + +A figure caption + +::: + +| a | b | +|---|---| +| 1 | 2 | + +: A table caption {#tbl-one} From 6d3e0b1fe06179f1c4a3f09fdc7272c176d4c44b Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 6 Oct 2026 18:08:58 +0200 Subject: [PATCH 2/2] Leave Typst subfigures out of the list of figures Subfloats are figures of the same kind as their parent, so the new list of figures listed "Figure 2a" and "Figure 2b" as separate entries after "Figure 2". LaTeX lists only the parent, and subpar, which quarto_super is adapted from, defaults to outlined-sub: false. The rule is scoped to the parent's body, so the parent stays listed, and it only affects outlines: references to a subfigure still render its sub-number. This also applies to formats that reuse definitions.typ for their own lists, such as orange-book. Refs #14081 --- llm-docs/pandoc-quarto-typst-templates.md | 2 +- .../typst/pandoc/quarto/definitions.typ | 1 + tests/docs/smoke-all/typst/lof-lot.qmd | 32 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/llm-docs/pandoc-quarto-typst-templates.md b/llm-docs/pandoc-quarto-typst-templates.md index 13a81a93dc7..c0182dd640c 100644 --- a/llm-docs/pandoc-quarto-typst-templates.md +++ b/llm-docs/pandoc-quarto-typst-templates.md @@ -83,7 +83,7 @@ Combines Pandoc definitions with Quarto-specific functionality: - Code block styling (gray background, padding, rounded corners) - `block_with_new_content` helper for reconstructing blocks with modified content - `empty` function to check if content is empty (handles strings and content nodes) -- Subfloat support via `quartosubfloatcounter` and `quarto_super` function for nested figures with sub-numbering +- Subfloat support via `quartosubfloatcounter` and `quarto_super` function for nested figures with sub-numbering; subfloats are `outlined: false`, so only the parent appears in a list of figures - Callout figure show rule that transforms callout figures with proper titles and cross-reference numbering - `callout` function for rendering callout boxes with customizable colors, icons, and styling diff --git a/src/resources/formats/typst/pandoc/quarto/definitions.typ b/src/resources/formats/typst/pandoc/quarto/definitions.typ index 40dc1a164b5..f372f20529c 100644 --- a/src/resources/formats/typst/pandoc/quarto/definitions.typ +++ b/src/resources/formats/typst/pandoc/quarto/definitions.typ @@ -88,6 +88,7 @@ subfloat-numbering(n-super, subfloat-idx) }) show figure.where(kind: kind): set figure.caption(position: position) + show figure.where(kind: kind): set figure(outlined: false) show figure: it => { let num = numbering(subcapnumbering, n-super, quartosubfloatcounter.get().first() + 1) diff --git a/tests/docs/smoke-all/typst/lof-lot.qmd b/tests/docs/smoke-all/typst/lof-lot.qmd index 282c16dfa14..e2644467b54 100644 --- a/tests/docs/smoke-all/typst/lof-lot.qmd +++ b/tests/docs/smoke-all/typst/lof-lot.qmd @@ -9,12 +9,22 @@ _quarto: ensurePdfRegexMatches: - # Both lists are rendered with their entries, before the body - 'List of Figures[\s\S]*A figure caption[\s\S]*List of Tables[\s\S]*A table caption[\s\S]*Introduction' + # The subfigure parent stays in the list + - 'List of Figures[\s\S]*Parent with subfigures[\s\S]*List of Tables' + # Cross-references to a subfigure keep their sub-numbering + - 'See Figure 2a' + - # Subfigure captions are not listed between the list title and the body + - 'List of Figures[\s\S]*Subcaption A[\s\S]*Introduction' --- # Introduction With `lof: true` and `lot: true`, a list of figures and a list of tables are printed after the title block and before this heading, as in LaTeX output (#14081). +Subfigures are left out of the list of figures, as in LaTeX: only their parent is listed. A cross-reference to a subfigure still shows its sub-numbering. + +See @fig-sub-a. + ::: {#fig-one} CONTENT @@ -23,6 +33,28 @@ A figure caption ::: +:::: {#fig-sub layout-ncol=2} + +::: {#fig-sub-a} + +CONTENT A + +Subcaption A + +::: + +::: {#fig-sub-b} + +CONTENT B + +Subcaption B + +::: + +Parent with subfigures + +:::: + | a | b | |---|---| | 1 | 2 |