Skip to content

Conversation

@gordonwoodhull
Copy link
Contributor

@gordonwoodhull gordonwoodhull commented Jan 25, 2026

Summary

  • Add comprehensive Typst book support using orange-book template by default
  • Replace ctheorems with theorion package for improved control over numbering (and themes)
  • Add theorem-appearance option for configurable theorem styling in Typst output
  • Bundle required Typst packages (theorion, fontawesome, showybox, octique) for offline builds

theorem-appearance Option

theorion has various themes, which can be selected with theorem-appearance:

format:
  typst:
    theorem-appearance: simple  # default
    # or: fancy, clouds, rainbow

Themes:

  • simple (default): Bold title with period, italic body - matches classic LaTeX style
  • fancy: Colored boxes using brand colors (primary/secondary/tertiary)
  • clouds: Rounded colored background boxes per theorem type
  • rainbow: Colored left border with colored title per theorem type

Rough draft, but getting there. PR for CI (and a link to put in the changelog).

gordonwoodhull and others added 30 commits January 24, 2026 04:15
This implements Typst as a single-file book format in Quarto, using the
external @preview/orange-book:0.6.2 Typst package for styling.

## New Files

- src/resources/formats/typst/pandoc/quarto/book-template.typ
  Main book template that imports orange-book and composes partials

- src/resources/formats/typst/pandoc/quarto/book-typst-show.typ
  Show rule partial that wraps content with orange-book's book() function,
  mapping Quarto metadata (title, subtitle, author, date, lang) to template params

- tests/docs/books/typst/
  Test book with three chapters for smoke testing

## Modified Files

- src/format/typst/format-typst.ts
  - Added BookExtension to enable Typst in book projects
  - Added project parameter to formatExtras
  - Detects book context and returns book-specific templateContext

- src/project/types/book/book.ts
  - Added Typst format extras: top-level-division=chapter, toc=false
  - TOC disabled because orange-book generates its own TOC

- src/resources/filters/quarto-pre/book-numbering.lua
  - Added Typst handling for parts: emits #part[Title] raw blocks
  - Added Typst handling for appendices: emits #show: appendices.with()

- src/resources/filters/quarto-finalize/book-cleanup.lua
  - Updated to preserve book parts for Typst output (was LaTeX-only)

- tests/smoke/book/render-book.test.ts
  - Added Typst book smoke test
  - Verifies PDF output exists
  - Verifies content from all chapters appears in generated .typ file

## Architecture

The implementation minimizes changes to existing templates by:
1. Creating separate book-specific template files
2. Importing orange-book externally (not copying code)
3. Using Quarto's existing definitions.typ for callouts, subfloats, etc.

When project type is "book" and format is "typst", the format returns a
different templateContext pointing to book-template.typ instead of template.typ.

## Known Limitations

1. Unnumbered headings ({.unnumbered}) cause errors with orange-book
   - Pandoc wraps unnumbered headings in #block[], which conflicts with
     orange-book's pagebreak() inside heading show rules
   - Workaround: Don't use {.unnumbered} class for now

2. Limited metadata mapping
   - Only title, subtitle, author, date, lang are mapped
   - orange-book supports many more options (cover, main-color, copyright, etc.)
   - These could be exposed via YAML passthrough in future

3. TOC is generated by orange-book, not Quarto
   - Quarto's TOC is disabled for Typst books
   - TOC customization options differ from other formats

4. Requires Typst 0.14.1+
   - orange-book 0.6.2 requires Typst compiler version 0.14.1 or newer

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… support

Remove custom Typst heading generation code that wrapped unnumbered/unlisted
headings in #block[], causing compatibility issues with Typst templates that
use pagebreak() in heading show rules (like orange-book).

## Timeline

- **July 2023**: Pandoc 3.1.12.3 adds .unlisted support for Typst (outlined: false)
- **December 2023**: Quarto adds workaround in commit 770c47f to support
  .unnumbered class for Typst, since Pandoc didn't handle it yet. This
  workaround used typst_function_call() which returns a pandoc.Div, causing
  headings to be wrapped in #block[] in the final output.
- **April 2024**: Pandoc 3.1.13 adds native .unnumbered support for Typst
  (commit 21d99703), emitting #heading(numbering: none) without any wrapper.
- **Now**: Quarto uses Pandoc 3.8.3, so the workaround is no longer needed
  and was causing issues with orange-book's pagebreak() in heading show rules.

## The Problem

The old code path:
  Header element → typst_function_call() → pandoc.Div → #block[#heading(...)]

This caused errors with orange-book because its show rule for level-1 headings
calls pagebreak(to: "odd"), which cannot be executed inside a #block[].

## The Fix

Keep only the number-depth logic (adding .unnumbered class when needed) and
let Pandoc handle all heading output natively:
  Header element → Pandoc Typst writer → #heading(numbering: none)[...]

The test verifies that unnumbered headings are emitted with the correct
Pandoc native syntax.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add figures, tables, and section cross-references to the Typst book test
to verify that Quarto correctly generates Typst anchor and link syntax.

Tests verify:
- Typst label anchors: <fig-simple>, <tbl-data>, <sec-intro>, <sec-methods>
- Typst reference links: #ref(<label>, supplement: [Type])
- Figure and table captions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use R code execution to generate the test figure instead of a static PNG.
This tests that code execution works correctly in Typst books, matching
the pattern used in the simple book test.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ignore R code execution output directories.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Embed a figure from a Jupyter notebook (computations.ipynb) alongside
the R code execution, testing that notebook embedding works in Typst books.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add test coverage for Quarto's bibliography and citation support in
Typst book output:

- Add references.bib with a test bibliography entry (knuth84)
- Add references.qmd chapter with unnumbered References heading
- Add citation @knuth84 in index.qmd preface
- Update _quarto.yml with bibliography config and references chapter
- Add test patterns verifying Typst syntax:
  - #cite(<knuth84>, form: "prose") for citations
  - #heading(level: 1, numbering: none)[References] for unnumbered heading
  - #bibliography(("references.bib")) for bibliography inclusion

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two fixes for Typst book rendering:

1. Fix appendices to use localized "Appendices" title
   - Changed book-numbering.lua to use language["section-title-appendices"]
     instead of the first appendix chapter's title
   - This matches orange-book's expected usage where the title is a
     grouping header in the TOC, not an individual chapter title

2. Fix parts by unwrapping .quarto-book-part div for Typst
   - Changed book-cleanup.lua to return el.content instead of el
   - The div was being converted to #block[] by Pandoc's Typst writer
   - Orange-book's part() function calls pagebreak(to: "odd") which
     cannot be used inside containers like #block[]
   - LaTeX keeps the div (harmless there), Typst unwraps it

Added test coverage:
- Book with two parts: "Part I: Getting Started", "Part II: Advanced Topics"
- Appendix chapter with cross-references back to main content
- Test patterns verify #part[], #show: appendices.with("Appendices")

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… books

This commit adds proper sub-figure support for Typst books, including
chapter-based numbering that matches the parent figure numbering scheme.

## Problem

Sub-figures in Typst books were displaying without chapter prefixes.
For example, a sub-figure in chapter 2 would show as "Figure 3a" instead
of the expected "Figure 2.3a".

## Solution

### Typst-side fix (definitions.typ)

Modified `quarto_super()` to detect chapter-based numbering by checking
if `subrefnumbering` contains a "." character. When detected, it includes
the chapter number from `counter(heading).get().first()`:

- Format "1.1a" → chapter-based: uses `numbering(pattern, chapter, n-super, idx)`
- Format "1a" → simple: uses `numbering(pattern, n-super, idx)`

### Lua filter fix (floatreftarget.lua, layout/typst.lua)

Updated both files to pass "1.1a" instead of "1a" when in book context,
detected via `crossrefOption("chapters", false)`.

## Test additions

- Added chapter 3 (`chapter3.qmd`) with cross-chapter sub-figure references
- Added sub-figure panel to chapter 2 using layout divs
- Updated `render-book.test.ts` with comprehensive PDF text verification:
  - Chapter-based sub-figure numbering (Figure 2.3a, Figure 2.3b)
  - Cross-chapter references maintain correct chapter prefix
  - Parent figure references (Figure 2.3)
- Used `\s+` in regex to handle PDF line wrapping

## Cross-references

The test also verifies that section cross-references work correctly:
- `@sec-methods` renders as "Chapter 2."
- `@sec-intro` renders as "Chapter 1."

Note: The trailing dot in chapter references (e.g., "Chapter 1.") is a
known limitation of the orange-book template's numbering pattern choice.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements callouts for Typst book output with proper chapter-based
cross-reference numbering (e.g., "Note 2.1" instead of "Note 1").

## Changes

### Lua filters
- callout.lua: Pass chapter-aware numbering pattern ("1.1" vs "1")
  based on crossrefOption("chapters", false)
- layout/typst.lua: Detect "." in numbering pattern and emit a Typst
  function that includes heading counter for proper #ref() display

### Typst definitions
- definitions.typ: Simplify callout show rule to use counter.display()
  with the figure's numbering function

### Test content
- Added all 5 callout types across chapters (note, warning, tip,
  caution, important)
- Added cross-referenceable callout (#nte-vogon) in chapter 2
- Added cross-chapter callout reference from chapter 3
- Douglas Adams-style humor in callout content

### Test verification
- Typst syntax: #callout(, kind: "quarto-callout-Note", <nte-vogon>,
  #ref(<nte-vogon>, supplement: [Note])
- PDF content: "Note 2.1: A Note About Vogon Poetry",
  cross-chapter reference with chapter prefix

## Technical notes

The numbering pattern convention (patterns with "." = chapter-based)
matches quarto_super()'s subfigure handling. This is documented in
layout/typst.lua. Currently only callout.lua passes non-nil numbering.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Work around orange-book bug where unnumbered headings trigger duplicate
"Appendices" entries in the table of contents. The bug occurs because
my-outline.typ adds "Appendices" whenever counter.first() == 1 in
appendix mode, but unnumbered headings don't advance the counter.

Fix:
- Use `hide-parent: true` in `appendices.with()` to disable orange-book's
  automatic "Appendices" TOC detection
- Emit our own controlled "Appendices" heading when processing the
  synthetic appendices divider

Also:
- Remove references.qmd from Typst book test (Typst's native #bibliography()
  handles the references section)
- Minor whitespace cleanup in biblio.typ

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ooks

Callouts and subfigures in appendices now use letter-based chapter
prefixes (e.g., "Warning A.2", "Figure A.4a") instead of numeric
prefixes (e.g., "Warning 1.2", "Figure 1.4a").

The fix checks orange-book's appendix-state and dynamically switches
from "1.1" to "A.1" numbering patterns when in appendix mode.

Note: The counter values may still be incorrect (A.4 instead of A.1)
due to a separate bug where custom figure kind counters are not reset
per chapter.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Orange-book only resets kind:image and kind:table at chapter boundaries,
but Quarto uses custom figure kinds (quarto-float-fig, quarto-float-tbl,
quarto-float-lst, quarto-callout-Warning, etc.). This caused incorrect
chapter-based numbering (e.g., Figure 2.3 instead of Figure 2.1).

This fix dynamically generates a Typst show rule from crossref.categories
that resets all Quarto custom figure counters at each level-1 heading.
The rule is injected via include-before and handles:
- Float categories (fig, tbl, lst)
- Callout categories (Note, Warning, Caution, Tip, Important)
- Custom crossref categories (if any are defined)

Also updates tests to expect correct A.1 numbering in appendices now that
both bugs are fixed (Bug 1: counter reset, Bug 2: appendix state detection).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a user-defined "Dinosaur" (key: dino) custom crossref type to the
Typst book test to verify the dynamic counter reset works for custom
categories, not just built-in ones.

The test verifies:
- Custom crossref kind "quarto-float-dino" is correctly generated
- Counter resets at chapter boundaries (Dinosaur 2.1, not 1.3)
- Appendix uses letter prefix (Dinosaur A.1)
- Cross-chapter references work correctly
- Dynamic counter reset includes custom type in show rule

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a second appendix (appendix-b.qmd) to verify that:
- Multiple appendices get correct letter prefixes (A, B, C, ...)
- Counters reset at each appendix boundary (B.1, not A.2)
- Forward references from main chapters to Appendix B work
- Cross-references between appendices work

Tests verify Figure B.1, Warning B.1, Tip B.1, and Dinosaur B.1 all
render with the correct "B" prefix, confirming the alphabetic appendix
numbering continues correctly beyond the first appendix.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…r Typst books

Implements chapter-based equation numbering for Typst book output. Equations
now display as "(1.1)", "(2.1)", etc. in regular chapters and "(A.1)", "(B.1)"
in appendices, matching the pattern established for figures, tables, callouts,
and custom crossref types.

- equations.lua: Replace hardcoded `numbering: "(1)"` with chapter-aware
  numbering function that checks `crossrefOption("chapters", false)` and
  orange-book's `appendix-state` for proper appendix letter prefixes
- book-numbering.lua: Add `counter(math.equation).update(0)` to reset
  equation counter at chapter boundaries (level-1 headings)

- chapter1.qmd: Add eq-einstein (1.1) and eq-newton (1.2) with self-refs
- chapter2.qmd: Add eq-quadratic (2.1) with cross-chapter refs to chapter 1
- appendix.qmd: Add eq-pythagorean (A.1) with cross-chapter refs

- render-book.test.ts: Add .typ file assertions for equation anchors,
  references, numbering function with appendix-state check, and counter reset
- render-book.test.ts: Add PDF assertions for equation numbering (1.1, 1.2,
  2.1, A.1) and cross-references across chapters

The numbering function emitted for chapter-based equations:
```typst
numbering: it => {
  let pattern = if state("appendix-state", none).get() != none { "(A.1)" } else { "(1.1)" }
  numbering(pattern, counter(heading).get().first(), it)
}
```

This follows the same pattern used for callouts in typst.lua, ensuring
consistent chapter-based numbering across all crossref types in Typst books.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… Typst books

Implements chapter-based theorem numbering for Typst book output using the
ctheorems package. Theorems now display as "Theorem 1.1", "Theorem 2.1", etc.
with counters resetting at chapter boundaries.

## Changes

### Lua filters
- theorem.lua: Add `base: "heading", base_level: 1` to ctheorems thmbox()
  when in book mode with chapter numbering. This ties theorem counters to
  the heading counter and limits numbering to chapter level only.

### Test content
- chapter1.qmd: Add thm-pythagorean (Theorem 1.1) and lem-triangle (Lemma 1.1)
- chapter2.qmd: Add thm-calculus (Theorem 2.1) and def-continuous (Definition 2.1)
  with cross-chapter references to Chapter 1 theorems
- appendix.qmd: Add thm-appendix to test appendix numbering

### Test assertions
- render-book.test.ts: Add .typ file assertions for ctheorems import,
  thmbox with base:heading, and theorem labels/references
- render-book.test.ts: Add PDF assertions for theorem numbering and
  cross-references

### Documentation
- plans/typst-ctheorems-appendix-prefix.md: Document known limitation where
  appendix theorems show "Theorem 1.1" instead of "Theorem A.1"

## Known Limitation

Theorems in appendices display numeric prefixes (1.1) instead of letter
prefixes (A.1). This is because ctheorems reads the raw heading counter
(which orange-book resets for appendices) without applying the letter
transformation. See plans/typst-ctheorems-appendix-prefix.md for investigation
notes. The appendix test assertions are commented out pending a fix.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds test content and assertions for code listing cross-references in Typst
books. Listings already have chapter-based numbering (1.1, 2.1, A.1) thanks
to orange-book's global figure numbering rule - no code changes needed.

## Test content
- chapter1.qmd: Add lst-hello (Listing 1.1) and lst-fibonacci (Listing 1.2)
- chapter2.qmd: Add lst-quicksort (Listing 2.1) with cross-chapter references
- appendix.qmd: Add lst-appendix-example (Listing A.1) with cross-chapter refs

## Test assertions
- render-book.test.ts: Add .typ file assertions for listing labels, references,
  and kind ("quarto-float-lst")
- render-book.test.ts: Add PDF assertions for listing numbering (1.1, 1.2, 2.1,
  A.1) and cross-references across chapters

## Technical note

Orange-book applies chapter-based numbering globally to ALL figures via:
  set figure(numbering: num => numbering("1.1", counter(heading).get().first(), num))

This includes listings (kind: "quarto-float-lst"), so they automatically get
chapter-based numbering without any Quarto code changes. Counter resets at
chapter boundaries are handled by book-numbering.lua which already includes
quarto-float-lst in the reset list.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…k/non-book

Move cross-reference numbering configuration out of Lua filters into
dedicated Typst template partials. This provides cleaner separation
between book and non-book rendering modes and reduces conditional
logic in the Lua codebase.

New files:
- numbering.typ: Simple sequential numbering for articles ("1", "1a")
- book-numbering.typ: Chapter-based numbering with appendix support
  ("1.1", "A.1", etc.)

Each file defines:
- quarto-equation-numbering: Pattern or function for equation numbers
- quarto-callout-numbering: Pattern or function for callout numbers
- quarto-subfloat-numbering: Function for subfigure numbers
- quarto-thmbox-args: Arguments for theorem box (empty for articles,
  base:"heading" for books)

The Lua filters now emit references to these template-defined variables
instead of computing numbering inline:
- equations.lua uses quarto-equation-numbering
- callout.lua triggers quarto-callout-numbering via make_typst_figure
- theorem.lua uses ..quarto-thmbox-args spread
- floatreftarget.lua and layout/typst.lua use quarto-subfloat-numbering
  via quarto_super default

Benefits:
- Zero impact on non-book users (simple defaults, no runtime complexity)
- Simpler Lua code without book/non-book conditionals
- Typst-specific logic stays in Typst files
- Template authors can customize numbering schemes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Always emit brand-color and brand-color-background in typst-brand-yaml.lua
  (empty dict if no brand defined, allowing safe .at() access in templates)
- Use brand-color.at("primary", default: blue) for orange-book main-color
- Add _brand.yml to test book with primary (#F36619) and secondary colors
- Add tests verifying brand colors are picked up in generated Typst

Uses standard Quarto brand.color.primary - no custom pass-through variable needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Always emit brand-logo in typst-brand-yaml.lua (empty dict if no logo)
- Use brand-logo.at("medium") for orange-book's logo parameter on title page
- Add test logo.svg and update _brand.yml with medium logo
- Add tests verifying brand-logo is picked up in generated Typst

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Map Quarto's toc-depth to orange-book's outline-depth parameter
- Switch from @preview/orange-book:0.6.2 to @local/orange-book:0.7.0
  (local version has outline-depth support)
- Add toc-depth: 17 to test book for distinctive verification
- Add test for outline-depth: 17 in generated Typst

Note: Requires orange-book 0.7.0 installed in local Typst packages:
~/Library/Application Support/typst/packages/local/orange-book/0.7.0/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ok fix)

- Enable lof/lot options for typst format in schema
- Pass list-of-figure-title/list-of-table-title to orange-book
- Support crossref.lof-title/lot-title with language fallback
- Add multi-paragraph content to test first-line indent

Note: Lists will be empty until orange-book is modified to accept
custom figure kinds (quarto-float-fig/tbl) instead of hardcoded
image/table kinds. See plans/orange-hardcodes-list-figure-kinds.md.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move #let brand-color and #let brand-color-background declarations
before the #set page/text statements that use them. Typst requires
variables to be defined before use.

Also update nobrand test to expect empty brand-color dicts, since
we now always emit them to allow safe .at() access in templates.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add cross-references (@fig-test, @eq-einstein) to demonstrate citecolor
and internal links (#sec-intro, #sec-math) to demonstrate filecolor.
Remove conclusion section and reorder for better flow.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove built-in book-*.typ files and simplify format-typst.ts to always
use the standard templates and partials for all Typst output. For Typst
books, a book extension (e.g., orange-book) overrides the default
partials to provide:

- numbering.typ: Chapter-based numbering with appendix support
- typst-show.typ: Book package import and configuration
- page.typ: Book-specific page setup

This enables users to bring their own book extensions while quarto
provides the Lua filter logic (book-numbering.lua) that works with
any compatible extension.

Changes:
- Remove book-template.typ, book-numbering.typ, book-typst-show.typ
- Simplify format-typst.ts to remove book special-casing
- Update test to use orange-book-typst format
- Update test comment to reference "book extension"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new quarto.utils API for extension filters that need book metadata:
- quarto.utils.file_metadata_filter() - returns filter that parses markers
- quarto.utils.combineFilters() - merges multiple filters into one traversal
- quarto.doc.file_metadata() - returns current file metadata state

This allows book extensions (e.g., orange-book) to combine their filters
with file_metadata_filter so book metadata (bookItemType, appendix, etc.)
is available during the filter's document traversal.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add quarto.doc.language to the Lua API, providing extensions with access
to localized strings (e.g., section-title-appendices) without needing to
use the internal _G.param function.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add quarto.doc.crossref.categories to the Lua API, providing extensions
with access to all crossref category definitions (figures, tables,
callouts, custom types). This enables book extensions like min-book to
dynamically build counter reset commands for all figure kinds.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
gordonwoodhull and others added 10 commits January 24, 2026 08:12
- Add filter-entry-point enum to definitions.yml with all entry points
  (pre-ast, post-ast, pre-quarto, post-quarto, pre-render, post-render,
  pre-finalize, post-finalize)
- Update pandoc-format-filters to use the ref instead of inline enum
- Update extension.yml filters to use the ref
- Adds pre-finalize and post-finalize to pandoc-format-filters

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of failing on the first regex mismatch, collect all failures
and report them together. This makes large-scale PDF testing much
easier by showing all problems at once.

Example output:
  5 regex mismatch(es) in file.pdf:
    - Required match /pattern1/ is missing
    - Required match /pattern2/ is missing
    - Illegal match /pattern3/ was found

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add smoke-all infrastructure support for testing Typst books:

- outputForInput() uses bookOutputStem() to get correct PDF filename
  (e.g., Test-Typst-Book.pdf from book title, not index.pdf)
- Add intermediateTypstPath for book projects where the merged .typ
  file is at project root, not derived from PDF path in _book/
- resolveTestSpecs() uses intermediateTypstPath for ensureTypstFileRegexMatches

Move orange-book test from custom TypeScript to smoke-all YAML annotations
as proof of concept, with 120+ regex patterns testing cross-references,
chapter numbering, appendices, callouts, equations, theorems, and brand support.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…oss-refs

Use @sec-xxx cross-references instead of hardcoded "Section X.Y" text.
Add section labels to all sections for cross-referencing.
Replace "Chapter N" text with @sec-intro/@sec-methods/@sec-results refs.
Add PDF regex tests for section self-references.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ackground

Orange-book handles the logo on its cover page, so the default page.typ
behavior of adding the logo as a page background should be omitted.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document the Lua APIs exposed for Typst book extensions:

quarto.utils:
- file_metadata_filter(): Returns filter for parsing book metadata
- combineFilters(): Merges multiple filters into one traversal

quarto.doc:
- file_metadata(): Returns current file metadata state
- language: Language settings for localization
- crossref.categories: Cross-reference category definitions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This migration solves the cross-reference bug where ctheorems resolved
numbering at reference time, causing Chapter 1 theorems to appear as
"Theorem A.1" when referenced from appendices.

Changes:
- theorem.lua: Use theorion's make-frame() instead of ctheorems' thmbox()
- numbering.typ: Add quarto-theorem-inherited-levels, quarto-theorem-numbering,
  and quarto-theorem-render configuration variables
- Update test assertions for new Typst patterns (title: named parameter)
- orange-book tests: Add appendix theorem cross-reference verification

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…styles

Add a new `theorem-appearance` YAML option to control theorem styling in
Typst output. Supports four themes:

- `simple` (default): Bold title with period, italic body, no box
- `fancy`: Colored boxes using brand colors (primary/secondary/tertiary)
- `clouds`: Rounded colored background boxes per theorem type
- `rainbow`: Colored left border with colored title per theorem type

The fancy theme integrates with brand.yaml colors, while clouds and rainbow
use hardcoded per-theorem-type colors (red for theorems, teal for lemmas,
olive for definitions, etc.).

Book extensions updated:
- orange-book: fancy theme
- Test files added for all four themes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Include theorion 0.4.1 (theorem environments) and fontawesome 0.5.0
for offline/hermetic Typst builds.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Downloaded via typst-gather:
- fontawesome 0.5.0: Icon support
- theorion 0.4.1: Theorem environments
- showybox 2.0.4: Box styling (theorion dependency)
- octique 0.1.1: Octicons (theorion dependency)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@posit-snyk-bot
Copy link
Collaborator

posit-snyk-bot commented Jan 25, 2026

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

Status Scanner 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.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@gordonwoodhull gordonwoodhull changed the title Typst book support with theorem-appearance option Typst Books Jan 25, 2026
gordonwoodhull and others added 17 commits January 25, 2026 02:50
Add 21 seminal CS and data science references distributed across all
chapters to test that citations are properly aggregated into a single
global bibliography. References include:

- Turing (1950), Dijkstra (1968), Shannon (1948), McCarthy (1960)
- Codd (1970), Backus (1978), Hoare (1978), Lamport (1978)
- Tukey (1977), Cooley & Tukey (1965), Breiman (2001), Cleveland (1988)
- Efron (1979), Tibshirani (1996), Pearl (2009), Wickham (2014)
- Floyd (1967), Cortes & Vapnik (1995), Box & Jenkins (1976)

Add PDF regex tests to verify bibliography entries [4], [8], [17]
appear in expected order, confirming cross-chapter aggregation works.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Enable citeproc: true for author-date citation style
- Remove Typst file tests for #cite and #bibliography (not used with citeproc)
- Update bibliography PDF tests for author-date format
- Add inline citation tests verifying "Author (Year)" format:
  - Turing (1950), McCarthy (1960), Codd (1970), Lamport (1978)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add references: references.qmd to place citeproc bibliography
in a dedicated References section.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add _quarto: tests: {} to chapter files to prevent the test
framework from running standalone renders on them. These files
have cross-chapter references that only resolve when the full
book is rendered.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…formats

The outputForInput() function was incorrectly using book stem for all
files in book projects, causing tests to look for wrong output paths
when rendering chapter files standalone.

Now correctly distinguishes:
- Multi-file formats (HTML): always use input filename, each chapter
  produces its own output file
- Single-file formats (PDF, Typst, EPUB): only use book stem when
  rendering the index file, which triggers merged book output

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The .quarto directories are cache directories that should be populated
at render time from src/resources/formats/typst/packages, not tracked
in git. Partial package files were accidentally committed, causing CI
failures when Typst couldn't find complete packages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add typst-gather.toml and update import to orange-book 0.7.1.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Package includes fix that changes figure centering from transformational
show rule to show-set rule, making it overridable by users/Quarto.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add show rule injection to left-align listing figures in Typst output.
This overrides template centering for listing-kind figures by injecting
a show-set rule after the template is applied.

- Add injected_listing_align_rule tracking variable
- Inject #show figure.where(kind: "quarto-float-lst"): set align(start)
- Remove old workaround that only worked inside figure content
- Add ensurePdfTextPositions test for listing alignment

Fixes #9724

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add code-listing-alignment.qmd test that documents proper usage of
ensurePdfTextPositions for code blocks. Key finding: the subject text
must be the FIRST token in the code block because pdftotext extracts
words separately and reports their individual positions.

Also update orange-book test to use ALIGNTEST_MARKER as first token.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a Deno script to extract and display the PDF structure tree (tag
hierarchy) with MCIDs. Useful for debugging ensurePdfTextPositions
issues and understanding how PDF tagged structure maps to text content.

Also update code-listing-alignment test with notes explaining that
subjects must be at the start of a line since ensurePdfTextPositions
uses word positions, not semantic container bounds.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove invalid subrefnumbering parameter from quarto_super calls
  in margin layout code (quarto_super doesn't accept this param)
- Update equations-alt.qmd test to expect quarto-equation-numbering
  function instead of literal "(1)" string

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rename Typst variables to follow convention of not using quarto- prefix
in generated output:
- quarto-equation-numbering → equation-numbering
- quarto-callout-numbering → callout-numbering
- quarto-subfloat-numbering → subfloat-numbering
- quarto-theorem-inherited-levels → theorem-inherited-levels
- quarto-theorem-numbering → theorem-numbering
- quarto-theorem-render → theorem-render
- quarto-simple-theorem-render → simple-theorem-render

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… commit 831c2f28f

git-subtree-dir: src/resources/extension-subtrees/orange-book
git-subtree-split: 831c2f28faf00fde53277f1b895e8bbf5c32716b
When a book project uses `format: typst` without specifying an extension,
automatically load the bundled orange-book extension as the default typst
book template. This provides a polished book appearance out-of-the-box.

Changes:
- render-contexts.ts: Auto-load orange-book in readExtensionFormat when
  project type is book, format is typst, and no extension is specified
- extension.ts: Add subtree extension search to discoverExtensionPath,
  export readSubtreeExtensions and builtinSubtreeExtensions
- output-typst.ts: Handle subtree extensions in stageTypstPackages for
  proper Typst package staging
- Test now uses plain `typst` format instead of `orange-book-typst`,
  relying on auto-loading; removed local _extensions (uses bundled)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.

3 participants