Skip to content

Commit 5de85d1

Browse files
committed
typst - use pandoc ast to search for level one headings
1 parent 2bab015 commit 5de85d1

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* level-one-headings.ts
3+
*
4+
* Copyright (C) 2025 Posit Software, PBC
5+
*/
6+
7+
import { join } from "../../../deno_ral/path.ts";
8+
import { execProcess } from "../../process.ts";
9+
import { pandocBinaryPath, resourcePath } from "../../resources.ts";
10+
11+
export async function hasLevelOneHeadings(markdown: string): Promise<boolean> {
12+
// this is O(n * m) where n is the number of blocks and m is the number of matches
13+
// we could do better but won't until we profile and show it's a problem
14+
15+
const path = pandocBinaryPath();
16+
const filterPath = resourcePath(
17+
join("filters", "quarto-internals", "leveloneanalysis.lua"),
18+
);
19+
const result = await execProcess({
20+
cmd: [path, "-f", "markdown", "-t", "markdown", "-L", filterPath],
21+
stdout: "piped",
22+
}, markdown);
23+
return result.stdout === "true";
24+
}

src/format/typst/format-typst.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
} from "../../config/types.ts";
3030
import { formatResourcePath } from "../../core/resources.ts";
3131
import { createFormat } from "../formats-shared.ts";
32+
import { hasLevelOneHeadings as hasL1Headings } from "../../core/lib/markdown-analysis/level-one-headings.ts";
3233

3334
export function typstFormat(): Format {
3435
return createFormat("Typst", "pdf", {
@@ -44,14 +45,14 @@ export function typstFormat(): Format {
4445
[kCiteproc]: false,
4546
},
4647
resolveFormat: typstResolveFormat,
47-
formatExtras: (
48+
formatExtras: async (
4849
_input: string,
4950
markdown: string,
5051
flags: PandocFlags,
5152
format: Format,
5253
_libDir: string,
5354
_services: RenderServices,
54-
): FormatExtras => {
55+
): Promise<FormatExtras> => {
5556
const pandoc: FormatPandoc = {};
5657
const metadata: Metadata = {};
5758

@@ -68,7 +69,7 @@ export function typstFormat(): Format {
6869

6970
// unless otherwise specified, pdfs with only level 2 or greater headings get their
7071
// heading level shifted by -1.
71-
const hasLevelOneHeadings = !!markdown.match(/\n^#\s.*$/gm);
72+
const hasLevelOneHeadings = await hasL1Headings(markdown);
7273
if (
7374
!hasLevelOneHeadings &&
7475
flags?.[kShiftHeadingLevelBy] === undefined &&
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
local found = false
2+
function Header(el)
3+
found = found or el.level == 1
4+
return nil
5+
end
6+
7+
function Pandoc(doc)
8+
if found then
9+
doc.blocks = pandoc.Blocks({
10+
pandoc.Str("true")
11+
})
12+
else
13+
doc.blocks = pandoc.Blocks({
14+
pandoc.Str("false")
15+
})
16+
end
17+
return doc
18+
end

0 commit comments

Comments
 (0)