Skip to content

Commit

Permalink
Merge pull request #11841 from quarto-dev/bugfix/issue-11835
Browse files Browse the repository at this point in the history
Detect `#` headings with AST
  • Loading branch information
cscheid authored Jan 10, 2025
2 parents fc6cd8d + e4cfc51 commit 06dd45a
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 6 deletions.
5 changes: 5 additions & 0 deletions news/changelog-1.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ All changes included in 1.7:
## `typst` Format

- ([#11578](https://github.com/quarto-dev/quarto-cli/issues/11578)): Typst column layout widths use fractional `fr` units instead of percent `%` units for unitless and default widths in order to fill the enclosing block and not spill outside it.
- ([#11835](https://github.com/quarto-dev/quarto-cli/issues/11835)): Take markdown structure into account when detecting minimum heading level.

## `pdf` Format

- ([#11835](https://github.com/quarto-dev/quarto-cli/issues/11835)): Take markdown structure into account when detecting minimum heading level.

## Lua Filters and extensions

Expand Down
2 changes: 1 addition & 1 deletion src/core/lib/break-quarto-md.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* Copyright (C) 2021-2022 Posit Software, PBC
*/

import { lineOffsets, lines } from "./text.ts";
import { lineOffsets } from "./text.ts";
import { Range, rangedLines, RangedSubstring } from "./ranged-text.ts";
import {
asMappedString,
Expand Down
24 changes: 24 additions & 0 deletions src/core/lib/markdown-analysis/level-one-headings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* level-one-headings.ts
*
* Copyright (C) 2025 Posit Software, PBC
*/

import { join } from "../../../deno_ral/path.ts";
import { execProcess } from "../../process.ts";
import { pandocBinaryPath, resourcePath } from "../../resources.ts";

export async function hasLevelOneHeadings(markdown: string): Promise<boolean> {
// this is O(n * m) where n is the number of blocks and m is the number of matches
// we could do better but won't until we profile and show it's a problem

const path = pandocBinaryPath();
const filterPath = resourcePath(
join("filters", "quarto-internals", "leveloneanalysis.lua"),
);
const result = await execProcess({
cmd: [path, "-f", "markdown", "-t", "markdown", "-L", filterPath],
stdout: "piped",
}, markdown);
return result.stdout?.trim() === "true";
}
5 changes: 3 additions & 2 deletions src/format/pdf/format-pdf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { kTemplatePartials } from "../../command/render/template.ts";
import { copyTo } from "../../core/copy.ts";
import { kCodeAnnotations } from "../html/format-html-shared.ts";
import { safeModeFromFile } from "../../deno_ral/fs.ts";
import { hasLevelOneHeadings as hasL1Headings } from "../../core/lib/markdown-analysis/level-one-headings.ts";

export function pdfFormat(): Format {
return mergeConfigs(
Expand Down Expand Up @@ -138,7 +139,7 @@ function createPdfFormat(
metadata: {
["block-headings"]: true,
},
formatExtras: (
formatExtras: async (
_input: string,
markdown: string,
flags: PandocFlags,
Expand Down Expand Up @@ -254,7 +255,7 @@ function createPdfFormat(
};

// Don't shift the headings if we see any H1s (we can't shift up any longer)
const hasLevelOneHeadings = !!markdown.match(/\n^#\s.*$/gm);
const hasLevelOneHeadings = await hasL1Headings(markdown);

// pdfs with no other heading level oriented options get their heading level shifted by -1
if (
Expand Down
7 changes: 4 additions & 3 deletions src/format/typst/format-typst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
} from "../../config/types.ts";
import { formatResourcePath } from "../../core/resources.ts";
import { createFormat } from "../formats-shared.ts";
import { hasLevelOneHeadings as hasL1Headings } from "../../core/lib/markdown-analysis/level-one-headings.ts";

export function typstFormat(): Format {
return createFormat("Typst", "pdf", {
Expand All @@ -44,14 +45,14 @@ export function typstFormat(): Format {
[kCiteproc]: false,
},
resolveFormat: typstResolveFormat,
formatExtras: (
formatExtras: async (
_input: string,
markdown: string,
flags: PandocFlags,
format: Format,
_libDir: string,
_services: RenderServices,
): FormatExtras => {
): Promise<FormatExtras> => {
const pandoc: FormatPandoc = {};
const metadata: Metadata = {};

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

// unless otherwise specified, pdfs with only level 2 or greater headings get their
// heading level shifted by -1.
const hasLevelOneHeadings = !!markdown.match(/\n^#\s.*$/gm);
const hasLevelOneHeadings = await hasL1Headings(markdown);
if (
!hasLevelOneHeadings &&
flags?.[kShiftHeadingLevelBy] === undefined &&
Expand Down
18 changes: 18 additions & 0 deletions src/resources/filters/quarto-internals/leveloneanalysis.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
local found = false
function Header(el)
found = found or el.level == 1
return nil
end

function Pandoc(doc)
if found then
doc.blocks = pandoc.Blocks({
pandoc.Str("true")
})
else
doc.blocks = pandoc.Blocks({
pandoc.Str("false")
})
end
return doc
end
17 changes: 17 additions & 0 deletions tests/docs/smoke-all/2025/01/10/issue-11835-b.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
format: latex
number-sections: true
_quarto:
tests:
latex:
ensureFileRegexMatches:
- []
- ["subsection{Section}"]
---

## Section

```r
# this is a comment that shouldn't break quarto
print("Hello, world")
```
17 changes: 17 additions & 0 deletions tests/docs/smoke-all/2025/01/10/issue-11835.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
format: typst
number-sections: true
_quarto:
tests:
typst:
ensurePdfRegexMatches:
- ["1 Section"]
- ["0.1 Section"]
---

## Section

```r
# this is a comment that shouldn't break quarto
print("Hello, world")
```

0 comments on commit 06dd45a

Please sign in to comment.