Skip to content

Commit f6addc2

Browse files
cdervclaude
andcommitted
Add syntax-highlighting option for Pandoc 3.8 alignment
Pandoc 3.8 introduced --syntax-highlighting to replace --highlight-style. This adds the new option to Quarto with support for: - Style names (tango, github, etc.) for Pandoc skylighting - Custom .theme files for KDE syntax themes - "none" to disable highlighting - "idiomatic" for native format highlighting (typst, LaTeX listings, reveal.js) The deprecated highlight-style option remains supported but is hidden from autocomplete. Typst format now supports all syntax highlighting options including syntax-definitions for custom language definitions. Fixes #13878 Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 1b55adc commit f6addc2

6 files changed

Lines changed: 88 additions & 26 deletions

File tree

news/changelog-1.9.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ All changes included in 1.9:
2222

2323
## Formats
2424

25+
### All Formats
26+
27+
- ([#13878](https://github.com/quarto-dev/quarto-cli/issues/13878)): Add `syntax-highlighting` option replacing the deprecated `highlight-style` in Pandoc 3.8. It supports style names (e.g., `tango`, `github`), custom `.theme` files, `none` to disable highlighting, or `idiomatic` for native format highlighting. The `highlight-style` option remains supported but is deprecated.
28+
2529
### `gfm`
2630

2731
- ([#13421](https://github.com/quarto-dev/quarto-cli/issues/13421)): Do not word-wrap titles in header.
@@ -56,7 +60,8 @@ All changes included in 1.9:
5660
- ([#13870](https://github.com/quarto-dev/quarto-cli/issues/13870)): Add support for `alt` attribute on cross-referenced equations for improved accessibility. (author: @mcanouil)
5761
- ([#13950](https://github.com/quarto-dev/quarto-cli/pull/13950)): Replace ctheorems with theorion package for theorem environments. Add `theorem-appearance` option to control styling: `simple` (default, classic LaTeX style), `fancy` (colored boxes with brand colors), `clouds` (rounded backgrounds), or `rainbow` (colored start border and colored title).
5862
- ([#13954](https://github.com/quarto-dev/quarto-cli/issues/13954)): Add support for Typst book projects via format extensions. Quarto now bundles the `orange-book` extension which provides a textbook-style format with chapter numbering, cross-references, and professional styling. Book projects with `format: typst` automatically use this extension.
59-
- ([#13978])(https://github.com/quarto-dev/quarto-cli/pull/13978)): Keep term and description together in definition lists to avoid breaking across pages. (author: @mcanouil)
63+
- ([#13978](https://github.com/quarto-dev/quarto-cli/pull/13978)): Keep term and description together in definition lists to avoid breaking across pages. (author: @mcanouil)
64+
- ([#13878](https://github.com/quarto-dev/quarto-cli/issues/13878)): Typst now uses Pandoc's skylighting for syntax highlighting by default (consistent with other formats). Use `syntax-highlighting: idiomatic` to opt-in to Typst's native syntax highlighting instead.
6065

6166
### `pdf`
6267

src/command/render/pandoc.ts

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ import {
9999
kFormatResources,
100100
kFrom,
101101
kHighlightStyle,
102+
kSyntaxHighlighting,
102103
kHtmlMathMethod,
103104
kIncludeAfterBody,
104105
kIncludeBeforeBody,
@@ -699,15 +700,18 @@ export async function runPandoc(
699700
printAllDefaults = mergeConfigs(extras.pandoc, printAllDefaults);
700701

701702
// Special case - theme is resolved on extras and should override allDefaults
702-
if (extras.pandoc[kHighlightStyle] === null) {
703-
delete printAllDefaults[kHighlightStyle];
704-
allDefaults[kHighlightStyle] = null;
705-
} else if (extras.pandoc[kHighlightStyle]) {
706-
delete printAllDefaults[kHighlightStyle];
707-
allDefaults[kHighlightStyle] = extras.pandoc[kHighlightStyle];
703+
// Clean up deprecated kHighlightStyle if user used old name
704+
delete printAllDefaults[kHighlightStyle];
705+
delete allDefaults[kHighlightStyle];
706+
if (extras.pandoc[kSyntaxHighlighting] === null) {
707+
delete printAllDefaults[kSyntaxHighlighting];
708+
allDefaults[kSyntaxHighlighting] = null;
709+
} else if (extras.pandoc[kSyntaxHighlighting]) {
710+
delete printAllDefaults[kSyntaxHighlighting];
711+
allDefaults[kSyntaxHighlighting] = extras.pandoc[kSyntaxHighlighting];
708712
} else {
709-
delete printAllDefaults[kHighlightStyle];
710-
delete allDefaults[kHighlightStyle];
713+
delete printAllDefaults[kSyntaxHighlighting];
714+
delete allDefaults[kSyntaxHighlighting];
711715
}
712716
}
713717

@@ -1756,13 +1760,24 @@ function resolveTextHighlightStyle(
17561760
} as FormatExtras;
17571761

17581762
// Get the user selected theme or choose a default
1759-
const highlightTheme = pandoc[kHighlightStyle] || kDefaultHighlightStyle;
1763+
// Check both syntax-highlighting (new) and highlight-style (deprecated alias)
1764+
const highlightTheme = pandoc[kSyntaxHighlighting] ||
1765+
pandoc[kHighlightStyle] ||
1766+
kDefaultHighlightStyle;
17601767
const textHighlightingMode = extras.html?.[kTextHighlightingMode];
17611768

17621769
if (highlightTheme === "none") {
17631770
// Disable highlighting - pass "none" string (not null, which Pandoc 3.8+ rejects)
17641771
extras.pandoc = extras.pandoc || {};
1765-
extras.pandoc[kHighlightStyle] = "none";
1772+
extras.pandoc[kSyntaxHighlighting] = "none";
1773+
return extras;
1774+
}
1775+
1776+
if (highlightTheme === "idiomatic") {
1777+
// Use native format highlighting (typst, LaTeX listings, reveal.js highlight.js)
1778+
// Pass through to Pandoc 3.8+ which handles this natively
1779+
extras.pandoc = extras.pandoc || {};
1780+
extras.pandoc[kSyntaxHighlighting] = "idiomatic";
17661781
return extras;
17671782
}
17681783

@@ -1775,7 +1790,7 @@ function resolveTextHighlightStyle(
17751790
case "dark":
17761791
// Set light or dark mode as appropriate
17771792
extras.pandoc = extras.pandoc || {};
1778-
extras.pandoc[kHighlightStyle] = textHighlightThemePath(
1793+
extras.pandoc[kSyntaxHighlighting] = textHighlightThemePath(
17791794
inputDir,
17801795
highlightTheme,
17811796
textHighlightingMode,
@@ -1787,7 +1802,7 @@ function resolveTextHighlightStyle(
17871802
// Clear the highlighting
17881803
if (extras.pandoc) {
17891804
extras.pandoc = extras.pandoc || {};
1790-
extras.pandoc[kHighlightStyle] = textHighlightThemePath(
1805+
extras.pandoc[kSyntaxHighlighting] = textHighlightThemePath(
17911806
inputDir,
17921807
"none",
17931808
);
@@ -1797,7 +1812,7 @@ function resolveTextHighlightStyle(
17971812
default:
17981813
// Set the the light (default) highlighting mode
17991814
extras.pandoc = extras.pandoc || {};
1800-
extras.pandoc[kHighlightStyle] =
1815+
extras.pandoc[kSyntaxHighlighting] =
18011816
textHighlightThemePath(inputDir, highlightTheme, "light") ||
18021817
highlightTheme;
18031818
break;

src/config/constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,10 @@ export const kNumberDepth = "number-depth";
543543
export const kTopLevelDivision = "top-level-division";
544544
export const kPaperSize = "papersize";
545545
export const kLogFile = "log-file";
546+
// TODO: Deprecate kHighlightStyle in favor of kSyntaxHighlighting
547+
// Kept for backward compatibility with older documents using highlight-style
546548
export const kHighlightStyle = "highlight-style";
549+
export const kSyntaxHighlighting = "syntax-highlighting";
547550
export const kDefaultImageExtension = "default-image-extension";
548551
export const kLogo = "logo";
549552
export const kLinkColor = "linkcolor";
@@ -709,6 +712,7 @@ export const kPandocDefaultsKeys = [
709712
"ascii",
710713
kDefaultImageExtension,
711714
kHighlightStyle,
715+
kSyntaxHighlighting,
712716
kSyntaxDefinitions,
713717
kSyntaxDefinition,
714718
kListings,

src/config/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ import {
9393
kFreeze,
9494
kGladtex,
9595
kHighlightStyle,
96+
kSyntaxHighlighting,
9697
kHtmlMathMethod,
9798
kHtmlPreTagProcessing,
9899
kHtmlTableProcessing,
@@ -594,6 +595,7 @@ export interface FormatPandoc {
594595
[kNumberSections]?: boolean;
595596
[kNumberOffset]?: number[];
596597
[kHighlightStyle]?: string | Record<string, string> | null;
598+
[kSyntaxHighlighting]?: string | Record<string, string> | null;
597599
[kSectionDivs]?: boolean;
598600
[kHtmlMathMethod]?: string | { method: string; url: string };
599601
[kTopLevelDivision]?: string;

src/quarto-core/text-highlighting.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { join } from "../deno_ral/path.ts";
77

88
import { kDefaultHighlightStyle } from "../command/render/constants.ts";
9-
import { kHighlightStyle } from "../config/constants.ts";
9+
import { kHighlightStyle, kSyntaxHighlighting } from "../config/constants.ts";
1010
import { FormatPandoc } from "../config/types.ts";
1111

1212
import { existsSync } from "../deno_ral/fs.ts";
@@ -69,7 +69,10 @@ export function readHighlightingTheme(
6969
pandoc: FormatPandoc,
7070
style: "dark" | "light" | "default",
7171
): ThemeDescriptor | undefined {
72-
const theme = pandoc[kHighlightStyle] || kDefaultHighlightStyle;
72+
// Check both syntax-highlighting (new) and highlight-style (deprecated alias)
73+
const theme = pandoc[kSyntaxHighlighting] ||
74+
pandoc[kHighlightStyle] ||
75+
kDefaultHighlightStyle;
7376
if (theme) {
7477
const themeRaw = readTheme(inputDir, theme, style);
7578
if (themeRaw) {
@@ -86,12 +89,16 @@ export function readHighlightingTheme(
8689
}
8790

8891
export function hasAdaptiveTheme(pandoc: FormatPandoc) {
89-
const theme = pandoc[kHighlightStyle] || kDefaultHighlightStyle;
92+
// Check both syntax-highlighting (new) and highlight-style (deprecated alias)
93+
const theme = pandoc[kSyntaxHighlighting] ||
94+
pandoc[kHighlightStyle] ||
95+
kDefaultHighlightStyle;
9096
return theme && isAdaptiveTheme(theme);
9197
}
9298

9399
export function hasTextHighlighting(pandoc: FormatPandoc): boolean {
94-
const theme = pandoc[kHighlightStyle];
100+
// Check both syntax-highlighting (new) and highlight-style (deprecated alias)
101+
const theme = pandoc[kSyntaxHighlighting] ?? pandoc[kHighlightStyle];
95102
return theme !== null;
96103
}
97104

src/resources/schema/document-code.yml

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@
9393
long: |
9494
Specifies to apply a background color on code blocks. Provide a hex color to specify that the background color is
9595
enabled as well as the color of the background.
96-
- name: highlight-style
96+
- name: syntax-highlighting
9797
tags:
98-
formats: [$html-all, docx, ms, $pdf-all]
98+
formats: [$html-all, docx, ms, $pdf-all, typst]
9999
schema:
100100
anyOf:
101101
- object:
@@ -117,6 +117,7 @@
117117
- github
118118
- gruvbox
119119
- haddock
120+
- idiomatic
120121
- kate
121122
- monochrome
122123
- monokai
@@ -135,21 +136,49 @@
135136
long: |
136137
Specifies the coloring style to be used in highlighted source code.
137138
138-
Instead of a *STYLE* name, a JSON file with extension
139-
` .theme` may be supplied. This will be parsed as a KDE
140-
syntax highlighting theme and (if valid) used as the
141-
highlighting style.
139+
Valid values:
140+
141+
- `none`: Disables syntax highlighting for code blocks.
142+
- `idiomatic`: Uses the format's native syntax highlighter
143+
(e.g., Typst's built-in highlighting, LaTeX `listings` package,
144+
or reveal.js highlight.js plugin).
145+
- A style name (e.g., `pygments`, `tango`, `github`): Uses
146+
Pandoc's skylighting with the specified theme.
147+
- A path to a `.theme` file: Uses a custom KDE syntax
148+
highlighting theme.
149+
150+
For adaptive light/dark themes, specify an object with `light`
151+
and `dark` properties pointing to theme files.
152+
153+
- name: highlight-style
154+
hidden: true
155+
tags:
156+
formats: [$html-all, docx, ms, $pdf-all, typst]
157+
schema:
158+
anyOf:
159+
- object:
160+
closed: true
161+
properties:
162+
light: path
163+
dark: path
164+
- string
165+
description:
166+
short: "Deprecated: use `syntax-highlighting` instead."
167+
long: |
168+
Deprecated: use `syntax-highlighting` instead.
169+
170+
Specifies the coloring style to be used in highlighted source code.
142171
143172
- name: syntax-definition
144173
tags:
145-
formats: [$html-all, docx, ms, $pdf-all]
174+
formats: [$html-all, docx, ms, $pdf-all, typst]
146175
schema: path
147176
hidden: true
148177
description: "KDE language syntax definition file (XML)"
149178

150179
- name: syntax-definitions
151180
tags:
152-
formats: [$html-all, docx, ms, $pdf-all]
181+
formats: [$html-all, docx, ms, $pdf-all, typst]
153182
schema:
154183
arrayOf: path
155184
description: "KDE language syntax definition files (XML)"

0 commit comments

Comments
 (0)