Skip to content

Commit 1d7b76a

Browse files
typst: generic font families / font stack aliases
this is a minimal implementation using Noto Sans as the sans-serif font and the built-in Typst fonts for serif, math, monospace each has a synonym, e.g. ui-sans-serif other generic font families could be added and we could ship fonts to replace the built-in Typst fonts fixes #11683 "big numbers" i can't figure out a way to automate this test but we should have it for visual testing
1 parent fd3aacf commit 1d7b76a

File tree

81 files changed

+356
-25
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+356
-25
lines changed

dev-docs/feature-format-matrix/qmd-files/css-properties/font-family/document.qmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ _quarto:
1919
typst:
2020
ensureTypstFileRegexMatches:
2121
-
22-
- '#set text\(font: \("Georgia", "serif"\)\); #table\('
22+
- '#{set text\(font: \("Georgia", "Libertinus Serif"\)\); table\('
2323
- []
2424
---
2525

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
format:
3+
html:
4+
quality: 1
5+
pdf:
6+
quality: na
7+
typst:
8+
quality: 2
9+
comment: "table only"
10+
include-in-header:
11+
text: |
12+
#set text(fallback: false)
13+
dashboard:
14+
quality: 1
15+
docx:
16+
quality: na
17+
pptx:
18+
quality: na
19+
keep-typ: true
20+
_quarto:
21+
tests:
22+
typst:
23+
ensureTypstFileRegexMatches:
24+
-
25+
- '#{set text\(font: \("Libertinus Serif"\)\); table\('
26+
- '#show heading: set text\(font: "Noto Sans", \)'
27+
- '#show raw.where\(block: true\): set text\(font: "DejaVu Sans Mono", \)'
28+
- []
29+
ensurePdfRegexMatches:
30+
-
31+
- 'heading is noto sans'
32+
- 'base is libertinus serif'
33+
- 'code should appear in a monospace font'
34+
- []
35+
brand:
36+
typography:
37+
base: serif
38+
headings: sans-serif
39+
monospace: monospace
40+
---
41+
# heading is `#context text.font`{=typst}
42+
43+
base is `#context text.font`{=typst}
44+
45+
```{=html}
46+
<table style="font-family: serif;">
47+
<tr><td>A</td><td>B</td></tr>
48+
</table>
49+
```
50+
51+
```
52+
// This code should appear in a monospace font
53+
```
54+

src/command/render/pandoc.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { Document } from "../../core/deno-dom.ts";
2121
import { execProcess } from "../../core/process.ts";
2222
import { dirAndStem, normalizePath } from "../../core/path.ts";
2323
import { mergeConfigs } from "../../core/config.ts";
24+
import { quartoConfig } from "../../core/quarto.ts";
2425

2526
import {
2627
Format,
@@ -1601,6 +1602,9 @@ async function resolveExtras(
16011602
}
16021603
fontdirs.add(font_cache);
16031604
}
1605+
const srcDir = Deno.env.get("QUARTO_SRC_PATH") ||
1606+
join(quartoConfig.sharePath(), "../../src");
1607+
fontdirs.add(join(srcDir,'resources/fonts'));
16041608
let fontPaths = format.metadata[kFontPaths] as Array<string> || [];
16051609
if (typeof fontPaths === "string") {
16061610
fontPaths = [fontPaths];

src/resources/filters/modules/typst_css.lua

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ local function output_length(length, warnings)
551551
if not csf then
552552
output_warning(warnings, 'unit ' .. length.unit .. ' is not supported in ' .. length.csslen )
553553
return nil
554-
end
554+
end
555555
return csf(length.value, length.unit, length.csslen, warnings)
556556
end
557557

@@ -595,6 +595,10 @@ local function quote(s)
595595
return '"' .. s .. '"'
596596
end
597597

598+
local function dequote(s)
599+
return s:gsub('^["\']', ''):gsub('["\']$', '')
600+
end
601+
598602
local same_weights = {
599603
'thin',
600604
'light',
@@ -636,6 +640,36 @@ local function translate_font_weight(w, warnings)
636640
end
637641
end
638642

643+
local generic_font_families = {
644+
['sans-serif'] = 'Noto Sans',
645+
serif = 'Libertinus Serif',
646+
math = 'New Computer Modern Math',
647+
monospace = 'DejaVu Sans Mono',
648+
}
649+
650+
local gff_synonyms = {
651+
['ui-sans-serif'] = 'sans-serif',
652+
['system-ui'] = 'sans-serif',
653+
['ui-serif'] = 'serif',
654+
['ui-monospace'] = 'monospace'
655+
}
656+
657+
local function translate_font_family(ff)
658+
ff = gff_synonyms[ff] or ff
659+
return generic_font_families[ff] or ff
660+
end
661+
662+
local function translate_font_family_list(sl)
663+
local strings = {}
664+
for s in sl:gmatch('([^,]+)') do
665+
s = dequote(trim(s))
666+
s = translate_font_family(s)
667+
table.insert(strings, quote(s))
668+
end
669+
return '(' .. table.concat(strings, ', ') ..')'
670+
end
671+
672+
639673
local function translate_border_style(v, _warnings)
640674
local dash
641675
if v == 'none' then
@@ -762,6 +796,8 @@ return {
762796
translate_border_style = translate_border_style,
763797
translate_border_color = translate_border_color,
764798
translate_font_weight = translate_font_weight,
799+
translate_font_family = translate_font_family,
800+
translate_font_family_list = translate_font_family_list,
765801
consume_width = consume_width,
766802
consume_style = consume_style,
767803
consume_color = consume_color

src/resources/filters/quarto-post/typst-brand-yaml.lua

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ function render_typst_brand_yaml()
117117
if headings and next(headings) then
118118
quarto.doc.include_text('in-header', table.concat({
119119
'#show heading: set text(',
120-
conditional_entry('font', headings.family),
120+
conditional_entry('font', _quarto.modules.typst.css.translate_font_family(headings.family)),
121121
conditional_entry('weight', _quarto.modules.typst.css.translate_font_weight(headings.weight)),
122122
conditional_entry('style', headings.style),
123123
conditional_entry('fill', headings.color, false),
@@ -138,7 +138,7 @@ function render_typst_brand_yaml()
138138
if monospaceInline and next(monospaceInline) then
139139
quarto.doc.include_text('in-header', table.concat({
140140
'#show raw.where(block: false): set text(',
141-
conditional_entry('font', monospaceInline.family),
141+
conditional_entry('font', _quarto.modules.typst.css.translate_font_family(monospaceInline.family)),
142142
conditional_entry('weight', _quarto.modules.typst.css.translate_font_weight(monospaceInline.weight)),
143143
conditional_entry('size', monospaceInline.size, false),
144144
conditional_entry('fill', monospaceInline.color, false),
@@ -157,7 +157,7 @@ function render_typst_brand_yaml()
157157
if monospaceBlock and next(monospaceBlock) then
158158
quarto.doc.include_text('in-header', table.concat({
159159
'#show raw.where(block: true): set text(',
160-
conditional_entry('font', monospaceBlock.family),
160+
conditional_entry('font', _quarto.modules.typst.css.translate_font_family(monospaceBlock.family)),
161161
conditional_entry('weight', _quarto.modules.typst.css.translate_font_weight(monospaceBlock.weight)),
162162
conditional_entry('size', monospaceBlock.size, false),
163163
conditional_entry('fill', monospaceBlock.color, false),
@@ -309,7 +309,7 @@ function render_typst_brand_yaml()
309309
local base = _quarto.modules.brand.get_typography(brandMode, 'base')
310310
if base and next(base) then
311311
meta.brand.typography.base = {
312-
family = base.family,
312+
family = _quarto.modules.typst.css.translate_font_family(base.family),
313313
size = base.size,
314314
}
315315
end
@@ -324,7 +324,7 @@ function render_typst_brand_yaml()
324324
local weight = _quarto.modules.typst.css.translate_font_weight(headings.weight or base.weight)
325325
weight = weight and pandoc.RawInline('typst', tostring(quote_string(weight)))
326326
meta.brand.typography.headings = {
327-
family = headings.family or base.family,
327+
family = _quarto.modules.typst.css.translate_font_family(headings.family or base.family),
328328
weight = weight,
329329
style = headings.style or base.style,
330330
decoration = headings.decoration or base.decoration,

src/resources/filters/quarto-post/typst-css-property-processing.lua

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,6 @@ function render_typst_css_property_processing()
3232
end
3333
end
3434

35-
local function dequote(s)
36-
return s:gsub('^["\']', ''):gsub('["\']$', '')
37-
end
38-
39-
local function quote(s)
40-
return '"' .. s .. '"'
41-
end
42-
4335
local function translate_vertical_align(va)
4436
if va == 'top' then
4537
return 'top'
@@ -270,15 +262,6 @@ function render_typst_css_property_processing()
270262
end
271263
return span
272264
end
273-
274-
local function translate_string_list(sl)
275-
local strings = {}
276-
for s in sl:gmatch('([^,]+)') do
277-
s = s:gsub('^%s+', '')
278-
table.insert(strings, quote(dequote(s)))
279-
end
280-
return '(' .. table.concat(strings, ', ') ..')'
281-
end
282265

283266
return {
284267
Table = function(tab)
@@ -289,7 +272,7 @@ function render_typst_css_property_processing()
289272
for clause in tabstyle:gmatch('([^;]+)') do
290273
local k, v = to_kv(clause)
291274
if k == 'font-family' then
292-
tab.attributes['typst:text:font'] = translate_string_list(v)
275+
tab.attributes['typst:text:font'] = _quarto.format.typst.css.translate_font_family_list(v)
293276
has_typst_text = true
294277
end
295278
if k == 'font-size' then
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)