Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/changelog-1.9.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ All changes included in 1.9:
- ([#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.
- ([#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)
- ([#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.
- ([#14126](https://github.com/quarto-dev/quarto-cli/issues/14126)): Fix Skylighting code blocks in Typst lacking full-width background, padding, and border radius. Temporarily overrides the Pandoc-generated `Skylighting` Typst function to add `width: 100%`, `inset: 8pt`, and `radius: 2pt` to the block call, matching the styling of native code blocks. Brand `monospace-block.background-color` also now correctly applies to Skylighting output. This override will be removed once the fix is upstreamed to Skylighting.

### `pdf`

Expand Down
64 changes: 64 additions & 0 deletions src/resources/filters/quarto-post/typst-brand-yaml.lua
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,31 @@ function render_typst_brand_yaml()
return '"' .. value .. '"'
end

-- Generate a replacement #let Skylighting() function with proper block styling.
-- The default Pandoc-generated version only uses block(fill: bgcolor, blocks)
-- which lacks width, inset, and radius (issue #14126).
local function emit_skylighting_override(bgcolor, lineNumberColor)
local lineNumberFill = ''
if lineNumberColor and type(lineNumberColor) == 'string' then
lineNumberFill = 'fill: rgb("' .. lineNumberColor .. '"), '
end
quarto.doc.include_text('in-header', table.concat({
'#let Skylighting(fill: none, number: false, start: 1, sourcelines) = {\n',
' let blocks = []\n',
' let lnum = start - 1\n',
' let bgcolor = ', bgcolor, '\n',
' for ln in sourcelines {\n',
' if number {\n',
' lnum = lnum + 1\n',
' blocks = blocks + box(width: if start + sourcelines.len() > 999 { 30pt } else { 24pt }, text(', lineNumberFill, '[ #lnum ]))\n',
' }\n',
' blocks = blocks + ln + EndLine()\n',
' }\n',
' block(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, blocks)\n',
'}\n',
}))
end

return {
Pandoc = function(pandoc0)
local brand = param('brand')
Expand Down Expand Up @@ -228,6 +253,27 @@ function render_typst_brand_yaml()
end
end

-- When Skylighting is active, Pandoc emits #Skylighting() calls instead
-- of raw code blocks, so #show raw.where(block: true) rules above don't
-- apply. Override the Skylighting function to include proper block styling.
-- Use brand background-color if set, otherwise fall back to theme bgcolor.
local highlightMethod = PANDOC_WRITER_OPTIONS.highlight_method
if monospaceBlock and next(monospaceBlock)
and type(highlightMethod) == 'table' then
local bgcolor = monospaceBlock['background-color']
if not bgcolor then
local themeBg = highlightMethod['background-color']
if type(themeBg) == 'string' then
bgcolor = 'rgb("' .. themeBg .. '")'
end
end
if bgcolor then
local lineNumberColor = type(highlightMethod['line-number-color']) == 'string'
and highlightMethod['line-number-color'] or nil
emit_skylighting_override(bgcolor, lineNumberColor)
end
end

local link = _quarto.modules.brand.get_typography(brandMode, 'link')
local primaryColor = _quarto.modules.brand.get_color(brandMode, 'primary')
if link and next(link) or primaryColor then
Expand All @@ -250,6 +296,24 @@ function render_typst_brand_yaml()
}))
end
end

-- Non-brand Skylighting override: even without a brand, the Pandoc-generated
-- Skylighting function lacks width/inset/radius. Override it using the
-- theme's own background color from PANDOC_WRITER_OPTIONS.highlight_method.
-- Skip if brand already emitted an override above.
local highlightMethod = PANDOC_WRITER_OPTIONS.highlight_method
local monospaceBlock = brand and brand.processedData
and _quarto.modules.brand.get_typography(brandMode, 'monospace-block')
local brandAlreadyOverrode = monospaceBlock and next(monospaceBlock)
and type(highlightMethod) == 'table'
if not brandAlreadyOverrode and type(highlightMethod) == 'table' then
local themeBg = highlightMethod['background-color']
if type(themeBg) == 'string' then
local lineNumberColor = type(highlightMethod['line-number-color']) == 'string'
and highlightMethod['line-number-color'] or nil
emit_skylighting_override('rgb("' .. themeBg .. '")', lineNumberColor)
end
end
end,
Meta = function(meta)
local brand = param('brand')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
color:
palette:
code-fg: "#2d3748"

typography:
monospace-block:
color: code-fg
weight: 500
size: 10pt
line-height: 1.5
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
title: Brand Monospace Block without Background Color
format:
typst:
keep-typ: true
_quarto:
tests:
typst:
ensureTypstFileRegexMatches:
-
# Skylighting is active (default)
- "#Skylighting"
- "#KeywordTok"
# Brand monospace-block text properties emitted as show rules
- '^#show raw\.where\(block: true\): set text\(weight: 500, size: 10pt, fill: rgb\("#2d3748"\), \)$'
- '^#show raw\.where\(block: true\): set par\(leading: 0\.75em\)$'
# Even without brand bg, Skylighting override uses theme bgcolor
# so that width/inset/radius are applied
- 'let bgcolor = rgb\("#f1f3f5"\)'
- 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, blocks\)'
# No brand background-color show rule (not configured)
- ['^#show raw\.where\(block: true\): set block\(fill:']
---

Brand sets monospace-block color, weight, size, and line-height but NOT
background-color. The Skylighting override should still be emitted using
the theme's background color so that code blocks get proper width/inset/radius.

```python
def hello():
x = 1 + 2
print(f"result: {x}")
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
color:
palette:
code-bg: "#1e1e2e"
code-fg: "#cdd6f4"

typography:
monospace-block:
color: code-fg
background-color: code-bg
size: 10pt
weight: 400
line-height: 1.6
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
title: Brand Monospace Block with Skylighting
format:
typst:
keep-typ: true
_quarto:
tests:
typst:
ensureTypstFileRegexMatches:
-
# Skylighting is active (default)
- "#Skylighting"
- "#KeywordTok"
# Brand monospace-block properties are emitted as show rules
# (still useful for idiomatic mode fallback)
- '^#show raw\.where\(block: true\): set text\(weight: 400, size: 10pt, fill: rgb\("#cdd6f4"\), \)$'
- '^#show raw\.where\(block: true\): set block\(fill: rgb\("#1e1e2e"\)\)$'
- '^#show raw\.where\(block: true\): set par\(leading: 0\.85em\)$'
# Quarto-generated Skylighting override with brand bg and proper block styling
- 'let bgcolor = rgb\("#1e1e2e"\)'
- 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, blocks\)'
# Should NOT have raw fenced blocks
- ["```python"]
---

Brand monospace-block options should apply to Skylighting code blocks.

```python
def hello():
x = 1 + 2
print(f"result: {x}")
```

Inline code like `hello()` should NOT get monospace-block styling.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
color:
palette:
block-bg: "#f0f4f8"
block-fg: "#1a365d"
inline-bg: "#fed7d7"
inline-fg: "#9b2c2c"

typography:
monospace-block:
color: block-fg
background-color: block-bg
size: 11pt
weight: 400
line-height: 1.5
monospace-inline:
color: inline-fg
background-color: inline-bg
weight: 600
size: 0.9rem
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
title: Brand Monospace with Idiomatic Highlighting
format:
typst:
keep-typ: true
syntax-highlighting: idiomatic
_quarto:
tests:
typst:
ensureTypstFileRegexMatches:
-
# Idiomatic = native typst highlighting = raw fenced code blocks
- "```python"
# Brand monospace-block properties (these target raw.where(block: true)
# which DOES match native/idiomatic code blocks)
- '^#show raw\.where\(block: true\): set text\(weight: 400, size: 11pt, fill: rgb\("#1a365d"\), \)$'
- '^#show raw\.where\(block: true\): set block\(fill: rgb\("#f0f4f8"\)\)$'
- '^#show raw\.where\(block: true\): set par\(leading: 0\.75em\)$'
# Brand monospace-inline properties
- '^#show raw\.where\(block: false\): set text\(weight: 600, size: 0\.9em, fill: rgb\("#9b2c2c"\), \)$'
- '^#show raw\.where\(block: false\): content => highlight\(fill: rgb\("#fed7d7"\), content\)$'
# Should NOT have Skylighting tokens
- ["#Skylighting", "#KeywordTok"]
---

With idiomatic highlighting, brand monospace-block properties apply directly
to `raw.where(block: true)` which matches native Typst code blocks.
This is the baseline that "just works."

Here's `inline code` with brand styling.

```python
def hello():
x = 1 + 2
print(f"result: {x}")
```

Both inline and block code should reflect brand styling.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
color:
palette:
mono-base-fg: "#2d3748"
block-bg: "#edf2f7"
inline-bg: "#fefcbf"

typography:
fonts:
- source: google
family: Fira Code
weight: [300, 400, 700]
# Base monospace: family and weight inherited by both inline and block
monospace:
family: Fira Code
weight: 400
size: 0.85rem
color: mono-base-fg
# Block overrides only background-color; inherits family, weight, size, color
monospace-block:
background-color: block-bg
line-height: 1.5
# Inline overrides only background-color and weight; inherits family, size, color
monospace-inline:
background-color: inline-bg
weight: 700
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
title: Brand Monospace Inheritance with Skylighting
format:
typst:
keep-typ: true
_quarto:
tests:
typst:
ensureTypstFileRegexMatches:
-
# Skylighting is active (default)
- "#Skylighting"
# Base monospace family applied via codefont
- 'codefont: \("Fira Code",\),$'
# monospace-block inherits color from base monospace, gets its own bg
- '^#show raw\.where\(block: true\): set text\(weight: 400, size: 0\.85em, fill: rgb\("#2d3748"\), \)$'
- '^#show raw\.where\(block: true\): set block\(fill: rgb\("#edf2f7"\)\)$'
- '^#show raw\.where\(block: true\): set par\(leading: 0\.75em\)$'
# Quarto Skylighting override with inherited brand bg
- 'let bgcolor = rgb\("#edf2f7"\)'
- 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, blocks\)'
# monospace-inline overrides weight to 700, inherits color, gets its own bg
- '^#show raw\.where\(block: false\): set text\(weight: 700, size: 0\.85em, fill: rgb\("#2d3748"\), \)$'
- '^#show raw\.where\(block: false\): content => highlight\(fill: rgb\("#fefcbf"\), content\)$'
- ["```python"]
---

This tests that `monospace` base properties are properly inherited by
`monospace-block` and `monospace-inline`, with specific overrides taking
precedence.

Inline code: `hello()` and `x + y` should use bold weight (700) from
monospace-inline override, with yellow background.

```python
# Block code inherits base weight (400) with blue-gray background
def greet(name):
return f"Hello, {name}!"
```

More `inline()` code references.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
color:
palette:
inline-bg: "#fff3cd"
inline-fg: "#664d03"

typography:
monospace-inline:
color: inline-fg
background-color: inline-bg
weight: 600
size: 0.85rem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: Brand Monospace Inline with Skylighting
format:
typst:
keep-typ: true
_quarto:
tests:
typst:
ensureTypstFileRegexMatches:
-
# Skylighting is active for code blocks
- "#Skylighting"
# Brand monospace-inline properties are emitted
- '^#show raw\.where\(block: false\): set text\(weight: 600, size: 0\.85em, fill: rgb\("#664d03"\), \)$'
- '^#show raw\.where\(block: false\): content => highlight\(fill: rgb\("#fff3cd"\), content\)$'
# No monospace-block show rules (not configured)
- ['^#show raw\.where\(block: true\): set block\(fill:']
---

Inline code like `hello()` and `x + y` should get brand monospace-inline styling
(background highlight, custom color, weight, size).

```python
def hello():
print("world")
```

Code blocks use Skylighting and should not be affected by monospace-inline settings.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
color:
palette:
block-bg: "#282a36"
block-fg: "#f8f8f2"
inline-bg: "#e8e0f0"
inline-fg: "#6c3483"

typography:
monospace-block:
color: block-fg
background-color: block-bg
weight: 400
size: 9pt
line-height: 1.4
monospace-inline:
color: inline-fg
background-color: inline-bg
weight: 500
Loading
Loading