diff --git a/configuration b/configuration index 63c8647e469..fa8bac417cb 100644 --- a/configuration +++ b/configuration @@ -14,10 +14,10 @@ export DENO=v2.4.5 # TODO figure out where 0.1.41 apple silicon libs are available export DENO_DOM=v0.1.41-alpha-artifacts -export PANDOC=3.6.3 +export PANDOC=3.8.3 export DARTSASS=1.87.0 export ESBUILD=0.25.10 -export TYPST=0.13.0 +export TYPST=0.14.2 # NB: we can't put comments in the same line as export statements because it diff --git a/dev-docs/update-pandoc-checklist.md b/dev-docs/update-pandoc-checklist.md index ac3115da0ad..e59a80321d1 100644 --- a/dev-docs/update-pandoc-checklist.md +++ b/dev-docs/update-pandoc-checklist.md @@ -2,10 +2,30 @@ Carlos needs to run this: -- [ ] Ensure archives are upgraded -- [ ] Run `AWS_PROFILE=... ./package/src/quarto-bld update-pandoc PANDOC_VERSION` +- [x] Ensure archives are upgraded +- [x] Run `AWS_PROFILE=... ./package/src/quarto-bld update-pandoc PANDOC_VERSION` - [ ] look at `git diff`, specifically for changes in Pandoc templates, and adjust as needed. +As a reminder, our templates are kept in the same directories as Pandoc's templates, but with different names. `git diff` will show the diff in Pandoc's template; we have to manually patch +ours. (We can't just use `patch` because the templates have diverged too much) + +### Pandoc templates + +The general rule for the naming is that "format.template" indicates Pandoc naming, and "template.format" indicates ours. Examples below: + +#### beamer + +- Pandoc's: src/resources/formats/beamer/pandoc/beamer.template +- Ours: src/resources/formats/beamer/pandoc/template.tex + +Partials: + +- Pandoc's: + - src/resources/formats/beamer/pandoc/latex.common +- Ours: + - src/resources/formats/beamer/pandoc/common.latex + + ## Manual steps - [ ] Update schemas by inspecting [their changelog](https://github.com/jgm/pandoc/blob/main/changelog.md) for new commands, deprecation removals, etc diff --git a/llm-docs/pandoc-quarto-typst-templates.md b/llm-docs/pandoc-quarto-typst-templates.md new file mode 100644 index 00000000000..7739ea44f3c --- /dev/null +++ b/llm-docs/pandoc-quarto-typst-templates.md @@ -0,0 +1,210 @@ +# Pandoc and Quarto Typst Templates + +This document describes how Quarto integrates Pandoc's typst templates and transforms them into a more modular structure suitable for Quarto's extended functionality. + +## 1. How Pandoc Templates Are Copied into Quarto + +The `writePandocTemplates` function in `package/src/common/update-pandoc.ts` handles copying Pandoc's templates into Quarto's resources during the Pandoc update process. + +### Source and Destination + +- **Source**: Pandoc templates are downloaded from the Pandoc GitHub repository's `data/templates/` directory +- **Destination**: `src/resources/formats/typst/pandoc/` + +### Files Copied + +Two files are copied from Pandoc for typst support: + +| Pandoc Source | Quarto Destination | +|---------------|-------------------| +| `default.typst` | `typst.template` | +| `template.typst` | `template.typst` (unchanged name) | + +### Purpose of Each Pandoc File + +**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 +- Configures table styling with no strokes +- Sets figure caption positions for tables (top) and images (bottom) +- Optionally includes syntax highlighting definitions +- Either imports a user-provided template or inlines the `template.typst` content via `$template.typst()$` +- Disables smart quotes if not enabled +- Processes header-includes +- Invokes the `conf()` function with all document metadata +- Renders include-before content, TOC, body, bibliography, and include-after content + +**template.typst**: Defines the `conf()` document function and helpers. It: +- Provides a `content-to-string` helper to extract text from content nodes +- Defines `conf()` which accepts all document metadata parameters +- Sets document metadata (title, keywords, author) for PDF accessibility +- Configures page, paragraph, text, and heading settings +- Applies link, reference, and file colors +- Renders the title block with optional thanks footnote +- Returns the document content + +## 2. Quarto's Modular Template Structure + +Quarto breaks the Pandoc templates into a modular structure in `src/resources/formats/typst/pandoc/quarto/`. This allows for: +- Better separation of concerns +- Easier customization and extension +- Support for Quarto-specific features (brand typography, callouts, subfloats) + +### Template Files + +The `typstFormat` function in `src/format/typst/format-typst.ts` configures the template context, specifying `template.typ` as the main template with these partials: `definitions.typ`, `typst-template.typ`, `page.typ`, `typst-show.typ`, `notes.typ`, and `biblio.typ`. + +### template.typ - The Orchestrator + +Assembles the document by including all partials in order: +1. `definitions.typ()` - utility definitions +2. `typst-template.typ()` - the article function +3. Header-includes loop +4. `page.typ()` - page configuration +5. `typst-show.typ()` - applies the article function +6. Include-before loop +7. Body +8. `notes.typ()` - endnotes handling +9. `biblio.typ()` - bibliography +10. Include-after loop + +### definitions.typ - Utility Definitions + +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 +- Code highlighting definitions (conditionally included) + +**Quarto additions**: +- `endnote` helper for endnote rendering +- 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 +- 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 + +### typst-template.typ - The Article Function + +Corresponds to `conf()` in Pandoc's `template.typst`. Defines the `article()` function with these parameters: + +**Document Metadata** (from Pandoc): +- `title`, `subtitle`, `authors`, `keywords`, `date` +- `abstract-title`, `abstract`, `thanks` + +**Layout** (from Pandoc): +- `cols`, `lang`, `region` + +**Typography** (from Pandoc): +- `font`, `fontsize`, `mathfont`, `codefont`, `linestretch`, `sectionnumbering` +- `linkcolor`, `citecolor`, `filecolor` + +**Quarto Extensions**: +- `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 + +**Functionality**: +- Sets `document()` metadata (title, keywords, author string) for PDF accessibility +- Configures paragraph justification and leading from `linestretch` +- 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 +- Handles single or multi-column layout + +### page.typ - Page Configuration + +Extracted from Pandoc's `conf()` function to allow independent page setup: +- Sets paper size (defaults to "us-letter") +- Sets margins (defaults to x: 1.25in, y: 1.25in) +- Sets page numbering +- Sets column count +- Optionally sets a background logo image with configurable location, inset, width, and alt text (Quarto extension) + +### typst-show.typ - Parameter Mapping + +Applies the `article()` function via a show rule, mapping Pandoc metadata and brand.yaml values to parameters. Follows precedence rules where Pandoc metadata takes priority and brand.yaml provides fallbacks. + +**Pandoc Metadata Mappings**: +- `title`, `subtitle`, `date`, `abstract` → direct pass-through +- `by-author` → `authors` (uses Quarto's author normalization with `it.name.literal` and `it.affiliations`) +- `labels.abstract` → `abstract-title` (localized) +- `mainfont` → `font` +- `fontsize` → `fontsize` +- `mathfont` → `mathfont` +- `codefont` → `codefont` +- `linestretch` → `linestretch` +- `section-numbering` → `sectionnumbering` +- `thanks` → `thanks` +- `linkcolor`, `citecolor`, `filecolor` → link color parameters +- `keywords` → `keywords` +- `toc`, `toc-title`, `toc-depth`, `toc-indent` → TOC parameters +- `columns` → `cols` + +**Brand.yaml Fallbacks** (used when Pandoc metadata not set): +- `brand.typography.base.family` → `font` +- `brand.typography.base.size` → `fontsize` +- `brand.typography.monospace.family` → `codefont` +- `brand.typography.headings.family` → `heading-family` +- `brand.typography.headings.weight` → `heading-weight` +- `brand.typography.headings.style` → `heading-style` +- `brand.typography.headings.color` → `heading-color` +- `brand.typography.headings.line-height` → `heading-line-height` + +### notes.typ - Endnotes Section + +Renders endnotes when present: +- Adds vertical space and a horizontal rule +- Sets smaller text size (0.88em) +- Renders the notes content + +### biblio.typ - Bibliography + +Handles bibliography rendering: +- Sets bibliography style from CSL file or bibliography style option +- Renders bibliography from specified files + +### typst.template - Reference Copy + +This is the copy of Pandoc's `default.typst`, kept for reference. It is used when rendering without Quarto's template context (e.g., when a user provides a custom template). + +## 3. Parameter Summary Table + +| Pandoc Parameter | Quarto Parameter | Brand.yaml Fallback | Notes | +|-----------------|------------------|---------------------|-------| +| `title` | `title` | - | | +| `subtitle` | `subtitle` | - | | +| `author` | `authors` | - | Normalized via `by-author` | +| `keywords` | `keywords` | - | Array of quoted strings | +| `date` | `date` | - | | +| `abstract` | `abstract` | - | | +| `abstract-title` | `abstract-title` | `labels.abstract` | Localized | +| `thanks` | `thanks` | - | Title footnote | +| `mainfont` | `font` | `brand.typography.base.family` | | +| `fontsize` | `fontsize` | `brand.typography.base.size` | | +| `mathfont` | `mathfont` | - | | +| `codefont` | `codefont` | `brand.typography.monospace.family` | | +| `linestretch` | `linestretch` | - | Multiplied by 0.65em for leading | +| `section-numbering` | `sectionnumbering` | - | | +| `linkcolor` | `linkcolor` | - | Hex color string | +| `citecolor` | `citecolor` | - | Hex color string | +| `filecolor` | `filecolor` | - | Hex color string | +| `columns` | `cols` | - | | +| `papersize` | (in page.typ) | - | | +| `margin` | (in page.typ) | - | | +| `page-numbering` | (in page.typ) | - | | +| - | `title-size` | - | Quarto extension | +| - | `subtitle-size` | - | Quarto extension | +| - | `heading-family` | `brand.typography.headings.family` | Quarto extension | +| - | `heading-weight` | `brand.typography.headings.weight` | Quarto extension | +| - | `heading-style` | `brand.typography.headings.style` | Quarto extension | +| - | `heading-color` | `brand.typography.headings.color` | Quarto extension | +| - | `heading-line-height` | `brand.typography.headings.line-height` | Quarto extension | +| `toc` | `toc` | - | | +| `toc-title` | `toc_title` | - | | +| `toc-depth` | `toc_depth` | - | | +| `toc-indent` | `toc_indent` | - | Quarto extension | diff --git a/src/command/check/check.ts b/src/command/check/check.ts index 97c349dc820..c74afe9592d 100644 --- a/src/command/check/check.ts +++ b/src/command/check/check.ts @@ -245,16 +245,16 @@ async function checkVersions(conf: CheckConfiguration) { // with our installers const checkData: [string | undefined, string, string][] = strict ? [ - [pandocVersion, "3.6.3", "Pandoc"], + [pandocVersion, "3.8.3", "Pandoc"], [sassVersion, "1.87.0", "Dart Sass"], [denoVersion, "2.4.5", "Deno"], - [typstVersion, "0.13.0", "Typst"], + [typstVersion, "0.14.0", "Typst"], ] : [ - [pandocVersion, ">=3.6.3", "Pandoc"], + [pandocVersion, ">=3.8.3", "Pandoc"], [sassVersion, ">=1.87.0", "Dart Sass"], [denoVersion, ">=2.3.1", "Deno"], - [typstVersion, ">=0.13.0", "Typst"], + [typstVersion, ">=0.14.0", "Typst"], ]; const fun = strict ? strictCheckVersion : checkVersion; for (const [version, constraint, name] of checkData) { diff --git a/src/execute/engine-shared.ts b/src/execute/engine-shared.ts deleted file mode 100644 index e0b9e14a52d..00000000000 --- a/src/execute/engine-shared.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * engine-shared.ts - * - * Copyright (C) 2021-2022 Posit Software, PBC - */ - -import { dirname, isAbsolute, join } from "../deno_ral/path.ts"; - -import { restorePreservedHtml } from "../core/jupyter/preserve.ts"; -import { PostProcessOptions } from "./types.ts"; - -export function postProcessRestorePreservedHtml(options: PostProcessOptions) { - // read the output file - - const outputPath = isAbsolute(options.output) - ? options.output - : join(dirname(options.target.input), options.output); - let output = Deno.readTextFileSync(outputPath); - - // substitute - output = restorePreservedHtml( - output, - options.preserve, - ); - - // re-write the output - Deno.writeTextFileSync(outputPath, output); -} - -export function languagesInMarkdownFile(file: string) { - return languagesInMarkdown(Deno.readTextFileSync(file)); -} - -export function languagesInMarkdown(markdown: string) { - // see if there are any code chunks in the file - const languages = new Set(); - const kChunkRegex = /^[\t >]*```+\s*\{([a-zA-Z0-9_]+)( *[ ,].*)?\}\s*$/gm; - kChunkRegex.lastIndex = 0; - let match = kChunkRegex.exec(markdown); - while (match) { - const language = match[1].toLowerCase(); - if (!languages.has(language)) { - languages.add(language); - } - match = kChunkRegex.exec(markdown); - } - kChunkRegex.lastIndex = 0; - return languages; -} diff --git a/src/execute/engine.ts b/src/execute/engine.ts index 497b8262aa0..44b4b1fa7b6 100644 --- a/src/execute/engine.ts +++ b/src/execute/engine.ts @@ -27,7 +27,7 @@ import { ExecutionTarget, kQmdExtensions, } from "./types.ts"; -import { languagesInMarkdown } from "./engine-shared.ts"; +import { languagesInMarkdown } from "../core/pandoc/pandoc-partition.ts"; import { languages as handlerLanguages } from "../core/handlers/base.ts"; import { RenderContext, RenderFlags } from "../command/render/types.ts"; import { mergeConfigs } from "../core/config.ts"; diff --git a/src/execute/ojs/compile.ts b/src/execute/ojs/compile.ts index cc33bc02b39..e87cbeb6dde 100644 --- a/src/execute/ojs/compile.ts +++ b/src/execute/ojs/compile.ts @@ -65,7 +65,7 @@ import { logError } from "../../core/log.ts"; import { breakQuartoMd, QuartoMdCell } from "../../core/lib/break-quarto-md.ts"; import { MappedString } from "../../core/mapped-text.ts"; -import { languagesInMarkdown } from "../engine-shared.ts"; +import { languagesInMarkdown } from "../../core/pandoc/pandoc-partition.ts"; import { pandocBlock, diff --git a/src/resources/filters/quarto-post/typst-brand-yaml.lua b/src/resources/filters/quarto-post/typst-brand-yaml.lua index 3ca5be17bb7..f23190d727c 100644 --- a/src/resources/filters/quarto-post/typst-brand-yaml.lua +++ b/src/resources/filters/quarto-post/typst-brand-yaml.lua @@ -170,11 +170,12 @@ function render_typst_brand_yaml() end end + -- monospace font family is handled by codefont in typst-template.typ via typst-show.typ + -- here we only handle properties that Pandoc doesn't support: weight, size, color local monospaceInline = _quarto.modules.brand.get_typography(brandMode, 'monospace-inline') if monospaceInline and next(monospaceInline) then quarto.doc.include_text('in-header', table.concat({ '#show raw.where(block: false): set text(', - conditional_entry('font', monospaceInline.family and _quarto.modules.typst.css.translate_font_family_list(monospaceInline.family), false), conditional_entry('weight', _quarto.modules.typst.css.translate_font_weight(monospaceInline.weight)), conditional_entry('size', monospaceInline.size, false), conditional_entry('fill', monospaceInline.color, false), @@ -189,11 +190,12 @@ function render_typst_brand_yaml() })) end + -- monospace font family is handled by codefont in typst-template.typ via typst-show.typ + -- here we only handle properties that Pandoc doesn't support: weight, size, color local monospaceBlock = _quarto.modules.brand.get_typography(brandMode, 'monospace-block') if monospaceBlock and next(monospaceBlock) then quarto.doc.include_text('in-header', table.concat({ '#show raw.where(block: true): set text(', - conditional_entry('font', monospaceBlock.family and _quarto.modules.typst.css.translate_font_family_list(monospaceBlock.family), false), conditional_entry('weight', _quarto.modules.typst.css.translate_font_weight(monospaceBlock.weight)), conditional_entry('size', monospaceBlock.size, false), conditional_entry('fill', monospaceBlock.color, false), @@ -307,7 +309,7 @@ function render_typst_brand_yaml() inset = '0.75in' end logoOptions.width = _quarto.modules.typst.css.translate_length(logoOptions.width or '1.5in') - logoOptions.inset = inset + logoOptions.inset = pandoc.RawInline('typst', inset) logoOptions.location = logoOptions.location and location_to_typst_align(logoOptions.location) or 'left+top' quarto.log.debug('logo options', logoOptions) @@ -356,6 +358,13 @@ function render_typst_brand_yaml() ['line-height'] = line_height_to_leading(headings['line-height'] or base['line-height']), } end + + local monospace = _quarto.modules.brand.get_typography(brandMode, 'monospace') + if monospace and monospace.family then + meta.brand.typography.monospace = { + family = pandoc.RawInline('typst', _quarto.modules.typst.css.translate_font_family_list(monospace.family)), + } + end return meta end, } diff --git a/src/resources/formats/beamer/pandoc/babel-lang.tex b/src/resources/formats/beamer/pandoc/babel-lang.tex index f29c833cb1e..ad1cc90c499 100644 --- a/src/resources/formats/beamer/pandoc/babel-lang.tex +++ b/src/resources/formats/beamer/pandoc/babel-lang.tex @@ -3,9 +3,9 @@ $-- $if(lang)$ \ifLuaTeX -\usepackage[bidi=basic$for(babeloptions)$,$babeloptions$$endfor$]{babel} +\usepackage[bidi=basic,shorthands=off,$for(babeloptions)$,$babeloptions$$endfor$]{babel} \else -\usepackage[bidi=default$for(babeloptions)$,$babeloptions$$endfor$]{babel} +\usepackage[bidi=default,shorthands=off,$for(babeloptions)$,$babeloptions$$endfor$]{babel} \fi $if(babel-lang)$ $if(mainfont)$ @@ -18,12 +18,7 @@ $for(babelfonts/pairs)$ \babelfont[$babelfonts.key$]{rm}{$babelfonts.value$} $endfor$ -% get rid of language-specific shorthands (see #6817): -\let\LanguageShortHands\languageshorthands -\def\languageshorthands#1{} -$if(selnolig-langs)$ \ifLuaTeX - \usepackage[$for(selnolig-langs)$$it$$sep$,$endfor$]{selnolig} % disable illegal ligatures + \usepackage{selnolig} % disable illegal ligatures \fi -$endif$ $endif$ \ No newline at end of file diff --git a/src/resources/formats/beamer/pandoc/latex.common b/src/resources/formats/beamer/pandoc/latex.common index 3f93b1b883a..cb745941de6 100644 --- a/src/resources/formats/beamer/pandoc/latex.common +++ b/src/resources/formats/beamer/pandoc/latex.common @@ -183,9 +183,9 @@ $-- Babel language support $-- $if(lang)$ \ifLuaTeX -\usepackage[bidi=basic$for(babeloptions)$,$babeloptions$$endfor$]{babel} +\usepackage[bidi=basic,shorthands=off,$for(babeloptions)$,$babeloptions$$endfor$]{babel} \else -\usepackage[bidi=default$for(babeloptions)$,$babeloptions$$endfor$]{babel} +\usepackage[bidi=default,shorthands=off,$for(babeloptions)$,$babeloptions$$endfor$]{babel} \fi $if(babel-lang)$ $if(mainfont)$ @@ -198,15 +198,10 @@ $endif$ $for(babelfonts/pairs)$ \babelfont[$babelfonts.key$]{rm}{$babelfonts.value$} $endfor$ -% get rid of language-specific shorthands (see #6817): -\let\LanguageShortHands\languageshorthands -\def\languageshorthands#1{} -$if(selnolig-langs)$ \ifLuaTeX - \usepackage[$for(selnolig-langs)$$it$$sep$,$endfor$]{selnolig} % disable illegal ligatures + \usepackage{selnolig} % disable illegal ligatures \fi $endif$ -$endif$ $-- $-- pagestyle $-- diff --git a/src/resources/formats/beamer/pandoc/tables.tex b/src/resources/formats/beamer/pandoc/tables.tex index c539bd640f9..443a14ab2f3 100644 --- a/src/resources/formats/beamer/pandoc/tables.tex +++ b/src/resources/formats/beamer/pandoc/tables.tex @@ -3,6 +3,7 @@ $-- $if(tables)$ \usepackage{longtable,booktabs,array} +\newcounter{none} % for unnumbered tables $if(multirow)$ \usepackage{multirow} $endif$ diff --git a/src/resources/formats/jats/pandoc/default-templates/article.jats_publishing b/src/resources/formats/jats/pandoc/default-templates/article.jats_publishing index d402b8bbd39..b33263cfd33 100644 --- a/src/resources/formats/jats/pandoc/default-templates/article.jats_publishing +++ b/src/resources/formats/jats/pandoc/default-templates/article.jats_publishing @@ -98,7 +98,7 @@ $if(author.surname)$ $if(author.non-dropping-particle)$${author.non-dropping-particle} $endif$$author.surname$ $author.given-names$$if(author.dropping-particle)$ ${author.dropping-particle}$endif$ $if(author.prefix)$ -${author.suffix} +${author.prefix} $endif$ $if(author.suffix)$ ${author.suffix} diff --git a/src/resources/formats/jats/pandoc/default-templates/default.jats_articleauthoring b/src/resources/formats/jats/pandoc/default-templates/default.jats_articleauthoring index 627911ae516..5a4fa212872 100644 --- a/src/resources/formats/jats/pandoc/default-templates/default.jats_articleauthoring +++ b/src/resources/formats/jats/pandoc/default-templates/default.jats_articleauthoring @@ -31,7 +31,7 @@ $if(author.surname)$ $if(author.non-dropping-particle)$${author.non-dropping-particle} $endif$${author.surname} ${author.given-names}$if(author.dropping-particle)$ ${author.dropping-particle}$endif$ $if(author.prefix)$ -${author.suffix} +${author.prefix} $endif$ $if(author.suffix)$ ${author.suffix} diff --git a/src/resources/formats/pdf/pandoc/babel-lang.tex b/src/resources/formats/pdf/pandoc/babel-lang.tex index f29c833cb1e..ad1cc90c499 100644 --- a/src/resources/formats/pdf/pandoc/babel-lang.tex +++ b/src/resources/formats/pdf/pandoc/babel-lang.tex @@ -3,9 +3,9 @@ $-- $if(lang)$ \ifLuaTeX -\usepackage[bidi=basic$for(babeloptions)$,$babeloptions$$endfor$]{babel} +\usepackage[bidi=basic,shorthands=off,$for(babeloptions)$,$babeloptions$$endfor$]{babel} \else -\usepackage[bidi=default$for(babeloptions)$,$babeloptions$$endfor$]{babel} +\usepackage[bidi=default,shorthands=off,$for(babeloptions)$,$babeloptions$$endfor$]{babel} \fi $if(babel-lang)$ $if(mainfont)$ @@ -18,12 +18,7 @@ $for(babelfonts/pairs)$ \babelfont[$babelfonts.key$]{rm}{$babelfonts.value$} $endfor$ -% get rid of language-specific shorthands (see #6817): -\let\LanguageShortHands\languageshorthands -\def\languageshorthands#1{} -$if(selnolig-langs)$ \ifLuaTeX - \usepackage[$for(selnolig-langs)$$it$$sep$,$endfor$]{selnolig} % disable illegal ligatures + \usepackage{selnolig} % disable illegal ligatures \fi -$endif$ $endif$ \ No newline at end of file diff --git a/src/resources/formats/pdf/pandoc/latex.common b/src/resources/formats/pdf/pandoc/latex.common index 3f93b1b883a..cb745941de6 100644 --- a/src/resources/formats/pdf/pandoc/latex.common +++ b/src/resources/formats/pdf/pandoc/latex.common @@ -183,9 +183,9 @@ $-- Babel language support $-- $if(lang)$ \ifLuaTeX -\usepackage[bidi=basic$for(babeloptions)$,$babeloptions$$endfor$]{babel} +\usepackage[bidi=basic,shorthands=off,$for(babeloptions)$,$babeloptions$$endfor$]{babel} \else -\usepackage[bidi=default$for(babeloptions)$,$babeloptions$$endfor$]{babel} +\usepackage[bidi=default,shorthands=off,$for(babeloptions)$,$babeloptions$$endfor$]{babel} \fi $if(babel-lang)$ $if(mainfont)$ @@ -198,15 +198,10 @@ $endif$ $for(babelfonts/pairs)$ \babelfont[$babelfonts.key$]{rm}{$babelfonts.value$} $endfor$ -% get rid of language-specific shorthands (see #6817): -\let\LanguageShortHands\languageshorthands -\def\languageshorthands#1{} -$if(selnolig-langs)$ \ifLuaTeX - \usepackage[$for(selnolig-langs)$$it$$sep$,$endfor$]{selnolig} % disable illegal ligatures + \usepackage{selnolig} % disable illegal ligatures \fi $endif$ -$endif$ $-- $-- pagestyle $-- diff --git a/src/resources/formats/pdf/pandoc/tables.tex b/src/resources/formats/pdf/pandoc/tables.tex index c539bd640f9..443a14ab2f3 100644 --- a/src/resources/formats/pdf/pandoc/tables.tex +++ b/src/resources/formats/pdf/pandoc/tables.tex @@ -3,6 +3,7 @@ $-- $if(tables)$ \usepackage{longtable,booktabs,array} +\newcounter{none} % for unnumbered tables $if(multirow)$ \usepackage{multirow} $endif$ diff --git a/src/resources/formats/typst/pandoc/quarto/definitions.typ b/src/resources/formats/typst/pandoc/quarto/definitions.typ index fff6dcdc4c1..c5b2f55e645 100644 --- a/src/resources/formats/typst/pandoc/quarto/definitions.typ +++ b/src/resources/formats/typst/pandoc/quarto/definitions.typ @@ -1,4 +1,16 @@ // Some definitions presupposed by pandoc's typst output. +#let content-to-string(content) = { + if content.has("text") { + content.text + } else if content.has("children") { + content.children.map(content-to-string).join("") + } else if content.has("body") { + content-to-string(content.body) + } else if content == [ ] { + " " + } +} + #let horizontalrule = line(start: (25%,0%), end: (75%,0%)) #let endnote(num, contents) = [ @@ -171,3 +183,8 @@ ) } +$if(highlighting-definitions)$ +// syntax highlighting functions from skylighting: +$highlighting-definitions$ + +$endif$ diff --git a/src/resources/formats/typst/pandoc/quarto/page.typ b/src/resources/formats/typst/pandoc/quarto/page.typ index f5af676afdf..a0289428606 100644 --- a/src/resources/formats/typst/pandoc/quarto/page.typ +++ b/src/resources/formats/typst/pandoc/quarto/page.typ @@ -2,6 +2,7 @@ paper: $if(papersize)$"$papersize$"$else$"us-letter"$endif$, margin: $if(margin)$($for(margin/pairs)$$margin.key$: $margin.value$,$endfor$)$else$(x: 1.25in, y: 1.25in)$endif$, numbering: $if(page-numbering)$"$page-numbering$"$else$none$endif$, + columns: $if(columns)$$columns$$else$1$endif$, ) $if(logo)$ #set page(background: align($logo.location$, box(inset: $logo.inset$, image("$logo.path$", width: $logo.width$$if(logo.alt)$, alt: "$logo.alt$"$endif$)))) diff --git a/src/resources/formats/typst/pandoc/quarto/typst-show.typ b/src/resources/formats/typst/pandoc/quarto/typst-show.typ index 472e71c0c43..5c2d5fe86d5 100644 --- a/src/resources/formats/typst/pandoc/quarto/typst-show.typ +++ b/src/resources/formats/typst/pandoc/quarto/typst-show.typ @@ -61,6 +61,32 @@ $endif$ $if(section-numbering)$ sectionnumbering: "$section-numbering$", $endif$ +$if(mathfont)$ + mathfont: ($for(mathfont)$"$mathfont$",$endfor$), +$endif$ +$if(codefont)$ + codefont: ($for(codefont)$"$codefont$",$endfor$), +$elseif(brand.typography.monospace.family)$ + codefont: $brand.typography.monospace.family$, +$endif$ +$if(linestretch)$ + linestretch: $linestretch$, +$endif$ +$if(thanks)$ + thanks: [$thanks$], +$endif$ +$if(linkcolor)$ + linkcolor: [$linkcolor$], +$endif$ +$if(citecolor)$ + citecolor: [$citecolor$], +$endif$ +$if(filecolor)$ + filecolor: [$filecolor$], +$endif$ +$if(keywords)$ + keywords: ($for(keywords)$"$keywords$",$endfor$), +$endif$ $if(toc)$ toc: $toc$, $endif$ diff --git a/src/resources/formats/typst/pandoc/quarto/typst-template.typ b/src/resources/formats/typst/pandoc/quarto/typst-template.typ index 02c0dc041e1..34becf2872f 100644 --- a/src/resources/formats/typst/pandoc/quarto/typst-template.typ +++ b/src/resources/formats/typst/pandoc/quarto/typst-template.typ @@ -1,85 +1,114 @@ - #let article( title: none, subtitle: none, authors: none, + keywords: (), date: none, - abstract: none, abstract-title: none, + abstract: none, + thanks: none, cols: 1, lang: "en", region: "US", - font: "libertinus serif", + font: none, fontsize: 11pt, title-size: 1.5em, subtitle-size: 1.25em, - heading-family: "libertinus serif", + heading-family: none, heading-weight: "bold", heading-style: "normal", heading-color: black, heading-line-height: 0.65em, + mathfont: none, + codefont: none, + linestretch: 1, sectionnumbering: none, + linkcolor: none, + citecolor: none, + filecolor: none, toc: false, toc_title: none, toc_depth: none, toc_indent: 1.5em, doc, ) = { - set par(justify: true) + // Set document metadata for PDF accessibility + set document(title: title, keywords: keywords) + set document( + author: authors.map(author => content-to-string(author.name)).join(", ", last: " & "), + ) if authors != none and authors != () + set par( + justify: true, + leading: linestretch * 0.65em + ) set text(lang: lang, region: region, - font: font, size: fontsize) + set text(font: font) if font != none + show math.equation: set text(font: mathfont) if mathfont != none + show raw: set text(font: codefont) if codefont != none + set heading(numbering: sectionnumbering) - if title != none { - align(center)[#block(inset: 2em)[ - #set par(leading: heading-line-height) - #if (heading-family != none or heading-weight != "bold" or heading-style != "normal" - or heading-color != black) { - set text(font: heading-family, weight: heading-weight, style: heading-style, fill: heading-color) - text(size: title-size)[#title] - if subtitle != none { + + show link: set text(fill: rgb(content-to-string(linkcolor))) if linkcolor != none + show ref: set text(fill: rgb(content-to-string(citecolor))) if citecolor != none + show link: this => { + if filecolor != none and type(this.dest) == label { + text(this, fill: rgb(content-to-string(filecolor))) + } else { + text(this) + } + } + + block(below: 1em, width: 100%)[ + #if title != none { + align(center, block(inset: 2em)[ + #set par(leading: heading-line-height) if heading-line-height != none + #set text(font: heading-family) if heading-family != none + #set text(weight: heading-weight) + #set text(style: heading-style) if heading-style != "normal" + #set text(fill: heading-color) if heading-color != black + + #text(size: title-size)[#title #if thanks != none { + footnote(thanks, numbering: "*") + counter(footnote).update(n => n - 1) + }] + #(if subtitle != none { parbreak() text(size: subtitle-size)[#subtitle] - } - } else { - text(weight: "bold", size: title-size)[#title] - if subtitle != none { - parbreak() - text(weight: "bold", size: subtitle-size)[#subtitle] - } - } - ]] - } + }) + ]) + } - if authors != none { - let count = authors.len() - let ncols = calc.min(count, 3) - grid( - columns: (1fr,) * ncols, - row-gutter: 1.5em, - ..authors.map(author => - align(center)[ - #author.name \ - #author.affiliation \ - #author.email - ] + #if authors != none and authors != () { + let count = authors.len() + let ncols = calc.min(count, 3) + grid( + columns: (1fr,) * ncols, + row-gutter: 1.5em, + ..authors.map(author => + align(center)[ + #author.name \ + #author.affiliation \ + #author.email + ] + ) ) - ) - } + } - if date != none { - align(center)[#block(inset: 1em)[ - #date - ]] - } + #if date != none { + align(center)[#block(inset: 1em)[ + #date + ]] + } - if abstract != none { - block(inset: 2em)[ - #text(weight: "semibold")[#abstract-title] #h(1em) #abstract - ] - } + #if abstract != none { + block(inset: 2em)[ + #text(weight: "semibold")[#abstract-title] #h(1em) #abstract + ] + } + ] if toc { let title = if toc_title == none { diff --git a/src/resources/formats/typst/pandoc/template.typst b/src/resources/formats/typst/pandoc/template.typst index 1889bef6fa5..648476620f5 100644 --- a/src/resources/formats/typst/pandoc/template.typst +++ b/src/resources/formats/typst/pandoc/template.typst @@ -15,74 +15,104 @@ authors: (), keywords: (), date: none, + abstract-title: none, abstract: none, + thanks: none, cols: 1, margin: (x: 1.25in, y: 1.25in), paper: "us-letter", lang: "en", region: "US", - font: (), + font: none, fontsize: 11pt, + mathfont: none, + codefont: none, + linestretch: 1, sectionnumbering: none, + linkcolor: none, + citecolor: none, + filecolor: none, pagenumbering: "1", doc, ) = { set document( title: title, - author: authors.map(author => content-to-string(author.name)), keywords: keywords, ) + set document( + author: authors.map(author => content-to-string(author.name)).join(", ", last: " & "), + ) if authors != none and authors != () set page( paper: paper, margin: margin, numbering: pagenumbering, - columns: cols, - ) - set par(justify: true) + columns: cols + ) + + set par( + justify: true, + leading: linestretch * 0.65em + ) set text(lang: lang, region: region, - font: font, size: fontsize) + + set text(font: font) if font != none + show math.equation: set text(font: mathfont) if mathfont != none + show raw: set text(font: codefont) if codefont != none + set heading(numbering: sectionnumbering) - place(top, float: true, scope: "parent", clearance: 4mm)[ - #if title != none { - align(center)[#block(inset: 2em)[ - #text(weight: "bold", size: 1.5em)[#title] - #(if subtitle != none { - parbreak() - text(weight: "bold", size: 1.25em)[#subtitle] - }) - ]] + show link: set text(fill: rgb(content-to-string(linkcolor))) if linkcolor != none + show ref: set text(fill: rgb(content-to-string(citecolor))) if citecolor != none + show link: this => { + if filecolor != none and type(this.dest) == label { + text(this, fill: rgb(content-to-string(filecolor))) + } else { + text(this) + } } - #if authors != none and authors != [] { - let count = authors.len() - let ncols = calc.min(count, 3) - grid( - columns: (1fr,) * ncols, - row-gutter: 1.5em, - ..authors.map(author => - align(center)[ - #author.name \ - #author.affiliation \ - #author.email - ] + block(below: 1em, width: 100%)[ + #if title != none { + align(center, block[ + #text(weight: "bold", size: 1.5em)[#title #if thanks != none { + footnote(thanks, numbering: "*") + counter(footnote).update(n => n - 1) + }] + #( + if subtitle != none { + parbreak() + text(weight: "bold", size: 1.25em)[#subtitle] + } + )]) + } + + #if authors != none and authors != [] { + let count = authors.len() + let ncols = calc.min(count, 3) + grid( + columns: (1fr,) * ncols, + row-gutter: 1.5em, + ..authors.map(author => align(center)[ + #author.name \ + #author.affiliation \ + #author.email + ]) ) - ) - } + } - #if date != none { - align(center)[#block(inset: 1em)[ - #date - ]] - } + #if date != none { + align(center)[#block(inset: 1em)[ + #date + ]] + } - #if abstract != none { - block(inset: 2em)[ - #text(weight: "semibold")[Abstract] #h(1em) #abstract - ] - } + #if abstract != none { + block(inset: 2em)[ + #text(weight: "semibold")[#abstract-title] #h(1em) #abstract + ] + } ] doc diff --git a/src/resources/formats/typst/pandoc/typst.template b/src/resources/formats/typst/pandoc/typst.template index 79b2c33f583..a499cd8db9f 100644 --- a/src/resources/formats/typst/pandoc/typst.template +++ b/src/resources/formats/typst/pandoc/typst.template @@ -22,6 +22,11 @@ kind: image ): set figure.caption(position: $if(figure-caption-position)$$figure-caption-position$$else$bottom$endif$) +$if(highlighting-definitions)$ +// syntax highlighting functions from skylighting: +$highlighting-definitions$ + +$endif$ $if(template)$ #import "$template$": conf $else$ @@ -60,7 +65,7 @@ $endfor$ ), $endif$ $if(keywords)$ - keywords: ($for(keywords)$$keyword$$sep$,$endfor$), + keywords: ($for(keywords)$$keywords$$sep$,$endfor$), $endif$ $if(date)$ date: [$date$], @@ -71,9 +76,15 @@ $endif$ $if(region)$ region: "$region$", $endif$ +$if(abstract-title)$ + abstract-title: [$abstract-title$], +$endif$ $if(abstract)$ abstract: [$abstract$], $endif$ +$if(thanks)$ + thanks: [$thanks$], +$endif$ $if(margin)$ margin: ($for(margin/pairs)$$margin.key$: $margin.value$,$endfor$), $endif$ @@ -86,10 +97,28 @@ $endif$ $if(fontsize)$ fontsize: $fontsize$, $endif$ +$if(mathfont)$ + mathfont: ($for(mathfont)$"$mathfont$",$endfor$), +$endif$ +$if(codefont)$ + codefont: ($for(codefont)$"$codefont$",$endfor$), +$endif$ +$if(linestretch)$ + linestretch: $linestretch$, +$endif$ $if(section-numbering)$ sectionnumbering: "$section-numbering$", $endif$ pagenumbering: $if(page-numbering)$"$page-numbering$"$else$none$endif$, +$if(linkcolor)$ + linkcolor: [$linkcolor$], +$endif$ +$if(citecolor)$ + citecolor: [$citecolor$], +$endif$ +$if(filecolor)$ + filecolor: [$filecolor$], +$endif$ cols: $if(columns)$$columns$$else$1$endif$, doc, ) @@ -108,6 +137,9 @@ $endif$ $body$ $if(citations)$ +$for(nocite-ids)$ +#cite(label("${it}"), form: none) +$endfor$ $if(csl)$ #set bibliography(style: "$csl$") @@ -117,7 +149,7 @@ $elseif(bibliographystyle)$ $endif$ $if(bibliography)$ -#bibliography($for(bibliography)$"$bibliography$"$sep$,$endfor$) +#bibliography(($for(bibliography)$"$bibliography$"$sep$,$endfor$)$if(full-bibliography)$, full: true$endif$) $endif$ $endif$ $for(include-after)$ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/font-list.qmd b/tests/docs/smoke-all/typst/brand-yaml/typography/font-list.qmd index 4b76245b8ac..968ea05845e 100644 --- a/tests/docs/smoke-all/typst/brand-yaml/typography/font-list.qmd +++ b/tests/docs/smoke-all/typst/brand-yaml/typography/font-list.qmd @@ -20,8 +20,8 @@ _quarto: ensureTypstFileRegexMatches: - - 'font: \("InvalidFont", "Roboto"\),' - - '#show raw.where\(block: false\): set text\(font: \("InvalidFont", "Inconsolata"\), \)' - - '#show raw.where\(block: true\): set text\(font: \("InvalidFont", "Inconsolata"\), \)' + # monospace font now goes through codefont parameter instead of header injection + - 'codefont: \("InvalidFont", "Inconsolata"\),' - [] ensurePdfRegexMatches: - diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/aguafinascript/v24/If2QXTv_ZzSxGIO30LemWEOmt1b3rcQt.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/aguafinascript/v24/If2QXTv_ZzSxGIO30LemWEOmt1b3rcQt.ttf new file mode 100644 index 00000000000..7f546f35ccd Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/aguafinascript/v24/If2QXTv_ZzSxGIO30LemWEOmt1b3rcQt.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/inconsolata/v37/QldgNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLYxYWI2qfdm7Lpp1s7WR32kg.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/inconsolata/v37/QldgNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLYxYWI2qfdm7Lpp1s7WR32kg.ttf new file mode 100644 index 00000000000..16c32c75b10 Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/inconsolata/v37/QldgNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLYxYWI2qfdm7Lpp1s7WR32kg.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/inconsolata/v37/QldgNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLYxYWI2qfdm7Lpp4U8WR32kg.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/inconsolata/v37/QldgNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLYxYWI2qfdm7Lpp4U8WR32kg.ttf new file mode 100644 index 00000000000..f81dccc97d9 Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/inconsolata/v37/QldgNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLYxYWI2qfdm7Lpp4U8WR32kg.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUFjIg1_i6t8kCHKm459Wx7xQYXK0vOoz6jq6R9WXh0ow.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUFjIg1_i6t8kCHKm459Wx7xQYXK0vOoz6jq6R9WXh0ow.ttf new file mode 100644 index 00000000000..1aee202a63a Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUFjIg1_i6t8kCHKm459Wx7xQYXK0vOoz6jq6R9WXh0ow.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw5aX8.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw5aX8.ttf new file mode 100644 index 00000000000..4b100deda20 Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw5aX8.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCuM73w5aX8.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCuM73w5aX8.ttf new file mode 100644 index 00000000000..263f954fe7e Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCuM73w5aX8.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCvC73w5aX8.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCvC73w5aX8.ttf new file mode 100644 index 00000000000..753cb446dd2 Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/montserrat/v31/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCvC73w5aX8.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/robotoslab/v36/BngbUXZYTXPIvIBgJJSb6s3BzlRRfKOFbvjojISmb2Rm.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/robotoslab/v36/BngbUXZYTXPIvIBgJJSb6s3BzlRRfKOFbvjojISmb2Rm.ttf new file mode 100644 index 00000000000..9fc573f0c35 Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/.quarto/typst-font-cache/fonts.gstatic.com/s/robotoslab/v36/BngbUXZYTXPIvIBgJJSb6s3BzlRRfKOFbvjojISmb2Rm.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/brand-typography.qmd b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/brand-typography.qmd index 23ce2483fed..6912828f2d4 100644 --- a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/brand-typography.qmd +++ b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-1/brand-typography.qmd @@ -35,10 +35,12 @@ _quarto: - '^#show heading: set text\(font: \("Montserrat",\), weight: 800, style: "normal", fill: rgb\("#0b8005"\), \)$' - '^#show heading: set par\(leading: 0.25em\)$' - - '^#show raw.where\(block: false\): set text\(font: \("Inconsolata",\), weight: 600, size: 0.57\*14pt, fill: rgb\(8, 111, 15\), \)$' + - 'codefont: \("Inconsolata",\),$' + - 'show raw: set text\(font: codefont\) if codefont != none' + - '^#show raw.where\(block: false\): set text\(weight: 600, size: 0.57\*14pt, fill: rgb\(8, 111, 15\), \)$' - '^#show raw.where\(block: false\): content => highlight\(fill: rgb\(255, 250, 224\), content\)$' - - '^#show raw.where\(block: true\): set text\(font: \("Inconsolata",\), size: 18pt, fill: rgb\(245, 255, 250\), \)$' + - '^#show raw.where\(block: true\): set text\(size: 18pt, fill: rgb\(245, 255, 250\), \)$' - '^#show raw.where\(block: true\): set block\(fill: rgb\("#77aae1"\)\)$' - '^#show raw.where\(block: true\): set par\(leading: 1\.25em\)$' diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/ebgaramond/v32/SlGDmQSNjdsmc35JDF1K5E55YMjF_7DPuGi-6_RkBI96.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/ebgaramond/v32/SlGDmQSNjdsmc35JDF1K5E55YMjF_7DPuGi-6_RkBI96.ttf new file mode 100644 index 00000000000..ff4d43175b8 Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/ebgaramond/v32/SlGDmQSNjdsmc35JDF1K5E55YMjF_7DPuGi-6_RkBI96.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/ebgaramond/v32/SlGFmQSNjdsmc35JDF1K5GRwUjcdlttVFm-rI7e8QL99U60.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/ebgaramond/v32/SlGFmQSNjdsmc35JDF1K5GRwUjcdlttVFm-rI7e8QL99U60.ttf new file mode 100644 index 00000000000..9cda96bb8fd Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/ebgaramond/v32/SlGFmQSNjdsmc35JDF1K5GRwUjcdlttVFm-rI7e8QL99U60.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/gentiumplus/v2/IurD6Ytw-oSPaZ00r2bNe8VZjqFPwGw.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/gentiumplus/v2/IurD6Ytw-oSPaZ00r2bNe8VZjqFPwGw.ttf new file mode 100644 index 00000000000..08d7ebe045c Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/gentiumplus/v2/IurD6Ytw-oSPaZ00r2bNe8VZjqFPwGw.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/gentiumplus/v2/Iurd6Ytw-oSPaZ00r2bNe8VZi5FI.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/gentiumplus/v2/Iurd6Ytw-oSPaZ00r2bNe8VZi5FI.ttf new file mode 100644 index 00000000000..d374e6370dc Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/gentiumplus/v2/Iurd6Ytw-oSPaZ00r2bNe8VZi5FI.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/raleway/v37/1Pt_g8zYS_SKggPNyCgSQamb1W0lwk4S4WjMDrMfJQ.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/raleway/v37/1Pt_g8zYS_SKggPNyCgSQamb1W0lwk4S4WjMDrMfJQ.ttf new file mode 100644 index 00000000000..c7cc9679a47 Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/raleway/v37/1Pt_g8zYS_SKggPNyCgSQamb1W0lwk4S4WjMDrMfJQ.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/raleway/v37/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCIPrQ.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/raleway/v37/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCIPrQ.ttf new file mode 100644 index 00000000000..009c1606b8c Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/raleway/v37/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCIPrQ.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/spacemono/v17/i7dNIFZifjKcF5UAWdDRYERMR3K6.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/spacemono/v17/i7dNIFZifjKcF5UAWdDRYERMR3K6.ttf new file mode 100644 index 00000000000..4db489b01fa Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/spacemono/v17/i7dNIFZifjKcF5UAWdDRYERMR3K6.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/spacemono/v17/i7dPIFZifjKcF5UAWdDRYEF8QA.ttf b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/spacemono/v17/i7dPIFZifjKcF5UAWdDRYEF8QA.ttf new file mode 100644 index 00000000000..6ccee6c1963 Binary files /dev/null and b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/.quarto/typst-font-cache/fonts.gstatic.com/s/spacemono/v17/i7dPIFZifjKcF5UAWdDRYEF8QA.ttf differ diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/brand-typography.qmd b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/brand-typography.qmd index bbac8f51ce5..3f59bd8747e 100644 --- a/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/brand-typography.qmd +++ b/tests/docs/smoke-all/typst/brand-yaml/typography/kitchen-sink-2/brand-typography.qmd @@ -33,10 +33,12 @@ _quarto: - '^#show heading: set text\(font: \("Raleway",\), weight: 500, style: "normal", fill: rgb\("#042f02"\), \)$' - '^#show heading: set par\(leading: 0.25em\)$' - - '^#show raw.where\(block: false\): set text\(font: \("Space Mono",\), weight: 400, size: 0.75\*12pt, fill: rgb\(8, 111, 15\), \)$' + - 'codefont: \("Space Mono",\),$' + - 'show raw: set text\(font: codefont\) if codefont != none' + - '^#show raw.where\(block: false\): set text\(weight: 400, size: 0.75\*12pt, fill: rgb\(8, 111, 15\), \)$' - '^#show raw.where\(block: false\): content => highlight\(fill: rgb\(255, 250, 224\), content\)$' - - '^#show raw.where\(block: true\): set text\(font: \("Space Mono",\), weight: 400, size: 0.75\*12pt, fill: rgb\("#eee"\), \)$' + - '^#show raw.where\(block: true\): set text\(weight: 400, size: 0.75\*12pt, fill: rgb\("#eee"\), \)$' - '^#show raw.where\(block: true\): set block\(fill: rgb\("#0a3c07"\)\)$' - '^#show link: set text\(weight: 200, fill: maroon, \)$' diff --git a/tests/docs/smoke-all/typst/pandoc-template-features.qmd b/tests/docs/smoke-all/typst/pandoc-template-features.qmd new file mode 100644 index 00000000000..479bf4a3e4b --- /dev/null +++ b/tests/docs/smoke-all/typst/pandoc-template-features.qmd @@ -0,0 +1,96 @@ +--- +title: "Test Document" +subtitle: "Pandoc Template Features" +author: + - name: Alice Smith + email: alice@example.com + affiliation: University A + - name: Bob Jones + email: bob@example.com + affiliation: University B +date: "2024-01-15" +keywords: + - quarto + - typst + - testing +thanks: "We thank our reviewers for their feedback." +abstract: "This document tests the Pandoc typst template features merged into Quarto." +mainfont: "Libertinus Serif" +mathfont: "STIX Two Math" +linestretch: 1.2 +linkcolor: "#0000ff" +citecolor: "#00ff00" +filecolor: "#ff0000" +brand: + typography: + fonts: + - family: Fira Code + source: google + monospace: + family: Fira Code +format: + typst: + keep-typ: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - # Patterns that MUST be found + # content-to-string function defined (from Pandoc) + - '#let content-to-string\(content\)' + # Document metadata in article() function + - 'set document\(title: title, keywords: keywords\)' + - 'set document\(\s*author: authors\.map' + # Keywords passed to article() call (quoted strings) + - 'keywords: \("quarto","typst","testing",\)' + # Thanks parameter passed to article() + - 'thanks: \[We thank our reviewers' + # Thanks footnote in title block + - 'footnote\(thanks, numbering: "\*"\)' + # Font settings passed to article() + # codefont comes from brand.typography.monospace.family fallback + - 'codefont: \("Fira Code",\)' + - 'mathfont: \("STIX Two Math",\)' + # mainfont (Libertinus Serif is bundled with Typst) + - 'font: \("Libertinus Serif",\)' + # Linestretch + - 'linestretch: 1\.2' + # Link colors passed to article() (# escaped as \#) + - 'linkcolor: \[\\#0000ff\]' + - 'citecolor: \[\\#00ff00\]' + - 'filecolor: \[\\#ff0000\]' + # Link color show rules in article() function + - 'show link: set text\(fill: rgb\(content-to-string\(linkcolor\)\)\)' + - 'show ref: set text\(fill: rgb\(content-to-string\(citecolor\)\)\)' + - # Patterns that must NOT be found + [] +--- + +## Introduction + +This document tests all the Pandoc typst template features that have been merged into Quarto's modular template structure. + +## Code Example + +Here is some code with custom font: + +```python +def hello(): + print("Hello, world!") +``` + +## Math Example + +Here is some math with custom font: + +$$ +E = mc^2 +$$ + +## Links + +Here is a [link to Quarto](https://quarto.org) which should be colored. + +## Conclusion + +All features work correctly. diff --git a/tests/docs/websites/website-sidebar-auto/.gitignore b/tests/docs/websites/website-sidebar-auto/.gitignore new file mode 100644 index 00000000000..b5d6aa19d53 --- /dev/null +++ b/tests/docs/websites/website-sidebar-auto/.gitignore @@ -0,0 +1,4 @@ +/.quarto/ +**/*.quarto_ipynb +*_files/ +_site/ diff --git a/tests/docs/websites/website-sidebar-auto/_quarto.yml b/tests/docs/websites/website-sidebar-auto/_quarto.yml new file mode 100644 index 00000000000..a743825dfdd --- /dev/null +++ b/tests/docs/websites/website-sidebar-auto/_quarto.yml @@ -0,0 +1,11 @@ +project: + type: website + +website: + title: "Sidebar Auto Test" + sidebar: + contents: auto + +format: + html: + theme: default diff --git a/tests/docs/websites/website-sidebar-auto/index.qmd b/tests/docs/websites/website-sidebar-auto/index.qmd new file mode 100644 index 00000000000..50187e5080c --- /dev/null +++ b/tests/docs/websites/website-sidebar-auto/index.qmd @@ -0,0 +1,5 @@ +--- +title: "Home" +--- + +This is the home page. diff --git a/tests/docs/websites/website-sidebar-auto/subdir/index.ipynb b/tests/docs/websites/website-sidebar-auto/subdir/index.ipynb new file mode 100644 index 00000000000..b03257b03b3 --- /dev/null +++ b/tests/docs/websites/website-sidebar-auto/subdir/index.ipynb @@ -0,0 +1,33 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "---\n", + "title: \"Subdir Index\"\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is the index page for the subdir." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.9.0" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/tests/smoke/website/website-sidebar-auto.test.ts b/tests/smoke/website/website-sidebar-auto.test.ts new file mode 100644 index 00000000000..236d0e70776 --- /dev/null +++ b/tests/smoke/website/website-sidebar-auto.test.ts @@ -0,0 +1,37 @@ +/* + * website-sidebar-auto.test.ts + * + * Verifies that sidebar auto-generation properly detects index files with + * non-qmd extensions (like .ipynb) in subdirectories. This tests the + * engineValidExtensions() call in indexFileHrefForDir() which must work + * before resolveEngines() has been called. + * + * Copyright (C) 2020-2025 Posit Software, PBC + */ + +import { docs } from "../../utils.ts"; +import { join } from "../../../src/deno_ral/path.ts"; +import { existsSync } from "../../../src/deno_ral/fs.ts"; +import { testQuartoCmd } from "../../test.ts"; +import { fileExists, noErrorsOrWarnings } from "../../verify.ts"; + +const renderDir = docs("websites/website-sidebar-auto"); +const outDir = join(Deno.cwd(), renderDir, "_site"); + +// Test that sidebar auto-generation detects index.ipynb in subdirectory +testQuartoCmd( + "render", + [renderDir], + [ + noErrorsOrWarnings, + fileExists(join(outDir, "index.html")), // Main index page + fileExists(join(outDir, "subdir", "index.html")), // Subdir index from .ipynb should be rendered + ], + { + teardown: async () => { + if (existsSync(outDir)) { + await Deno.remove(outDir, { recursive: true }); + } + }, + }, +);