Skip to content
Merged
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
3 changes: 2 additions & 1 deletion news/changelog-1.10.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,5 @@ All changes included in 1.10:
- ([#14359](https://github.com/quarto-dev/quarto-cli/issues/14359)): Fix intermediate `.quarto_ipynb` file not being deleted after rendering a `.qmd` with Jupyter engine, causing numbered variants (`_1`, `_2`, ...) to accumulate on disk across renders.
- ([#14461](https://github.com/quarto-dev/quarto-cli/issues/14461)): Fix `quarto render --to pdf` aborting with `ERROR: Problem running 'fmtutil-sys --all' to rebuild format tree.` when an automatically-installed LaTeX package's post-update format rebuild fails. Format-tree rebuild is now treated as best-effort housekeeping (matching upstream `tinytex` R behavior) — the failure is logged as a warning and the package install completes.
- ([#14472](https://github.com/quarto-dev/quarto-cli/issues/14472)): Add support for Kotlin in code annotations and YAML cell options. (author: @barendgehrels)
- ([#14529](https://github.com/quarto-dev/quarto-cli/issues/14529)): Fix bundled Julia engine path leaking into rendered YAML metadata and pandoc log output when running an installed Quarto. The internal subtree-engine filter only matched the source-tree share-path layout (`resources/extension-subtrees/`) and missed installed layouts where the path is `share/extension-subtrees/`.
- ([#14529](https://github.com/quarto-dev/quarto-cli/issues/14529)): Fix bundled Julia engine path leaking into rendered YAML metadata and pandoc log output when running an installed Quarto. The internal subtree-engine filter only matched the source-tree share-path layout (`resources/extension-subtrees/`) and missed installed layouts where the path is `share/extension-subtrees/`.
- ([#14582](https://github.com/quarto-dev/quarto-cli/issues/14582)): Fix format detection for extension formats (e.g. `acm-pdf`) in project preview, manuscript notebooks, MECA bundles, and website format ordering.
29 changes: 23 additions & 6 deletions src/config/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import { kBaseFormat, kPreferHtml } from "../config/constants.ts";
import { Format, FormatPandoc } from "./types.ts";
import { parseFormatString } from "../core/pandoc/pandoc-formats.ts";

export function isPdfOutput(format: string): boolean;
export function isPdfOutput(format: FormatPandoc): boolean;
Expand Down Expand Up @@ -97,14 +98,20 @@ export function isJatsOutput(format?: string | FormatPandoc) {
format = format?.to || "html";
}

return [
const jatsFormats = [
"jats",
"jats_archiving",
"jats_articleauthoring",
"jats_publishing",
].find((formatStr) => {
return (format as string).startsWith(formatStr);
}) !== undefined;
];
const formatStr = format as string;
if (jatsFormats.some((f) => formatStr.startsWith(f))) return true;
try {
const base = parseFormatString(formatStr).baseFormat;
return jatsFormats.some((f) => base.startsWith(f));
} catch {
return false;
}
}

export function isPresentationOutput(format: FormatPandoc) {
Expand All @@ -123,7 +130,12 @@ export function isRevealjsOutput(format?: string | FormatPandoc) {
format = format?.to;
}
format = format || "html";
return format.startsWith("revealjs");
if (format.startsWith("revealjs")) return true;
try {
return parseFormatString(format).baseFormat.startsWith("revealjs");
} catch {
return false;
}
}

export function isNativeOutput(format: FormatPandoc) {
Expand All @@ -146,7 +158,12 @@ function isFormatTo(format: string | FormatPandoc, to: string) {
const formatStr = typeof format === "string"
? format
: (format?.to || "html");
return formatStr.startsWith(to);
if (formatStr.startsWith(to)) return true;
try {
return parseFormatString(formatStr).baseFormat.startsWith(to);
} catch {
return false;
}
}

export function isMarkdownOutput(
Expand Down
16 changes: 16 additions & 0 deletions tests/docs/manual/preview/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,22 @@ format edit is detected on the **first** render request.
- **Expected:** No preview process restart. Render runs in the same process.
- **Catches:** Over-eager invalidation triggering 404 when the format is in fact unchanged

## Extension Format PDF Preview (#14582)

### P1: Core functionality

#### T26: Book preview with extension PDF format
- **Setup**: `extension-pdf-book/` fixture
- **Steps**: `quarto preview . --to dummy-extension-pdf --no-browser --port 4444`
- **Expected**: Browse URL contains `web/viewer.html`. PDF.js viewer loads in browser with live-reload.
- **Catches**: `isFormatTo` startsWith check failing for extension format strings.

#### T27: Book preview with extension HTML format (no regression)
- **Setup**: Same fixture
- **Steps**: `quarto preview . --to dummy-extension-html --no-browser --port 4444`
- **Expected**: Normal HTML preview with live-reload. No PDF.js viewer.
- **Catches**: Fix doesn't accidentally enable PDF mode for non-PDF extension formats.

## Test File Templates

**Minimal Python .qmd:**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: dummy-extension
contributes:
formats:
pdf: default
html: default
12 changes: 12 additions & 0 deletions tests/docs/manual/preview/extension-pdf-book/_quarto.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
project:
type: book

book:
title: "Bug reproduction"
chapters:
- index.qmd
- chapter1.qmd

format:
dummy-extension-pdf: default
dummy-extension-html: default
3 changes: 3 additions & 0 deletions tests/docs/manual/preview/extension-pdf-book/chapter1.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Introduction

This is chapter 1.
5 changes: 5 additions & 0 deletions tests/docs/manual/preview/extension-pdf-book/index.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: "Preface"
---

This is the preface.
103 changes: 103 additions & 0 deletions tests/unit/format-detection.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { unitTest } from "../test.ts";
import { assert } from "testing/asserts";
import {
isHtmlOutput,
isJatsOutput,
isPdfOutput,
isRevealjsOutput,
isTypstOutput,
} from "../../src/config/format.ts";

unitTest(
"isPdfOutput - direct formats",
// deno-lint-ignore require-await
async () => {
assert(isPdfOutput("pdf"));
assert(isPdfOutput("beamer"));
assert(!isPdfOutput("html"));
assert(!isPdfOutput("typst"));
assert(!isPdfOutput("docx"));
},
);

unitTest(
"isPdfOutput - extension formats",
// deno-lint-ignore require-await
async () => {
assert(isPdfOutput("acm-pdf"));
assert(isPdfOutput("dummy-extension-pdf"));
assert(isPdfOutput("acm-2023-pdf"));
assert(isPdfOutput("journal-beamer"));
assert(!isPdfOutput("acm-html"));
assert(!isPdfOutput("my-ext-typst"));
},
);

unitTest(
"isPdfOutput - modifiers and edge cases",
// deno-lint-ignore require-await
async () => {
assert(!isPdfOutput("default"));
assert(!isPdfOutput(""));
assert(isPdfOutput("pdf+draft"));
assert(isPdfOutput("acm-pdf+draft"));
},
);

unitTest(
"isHtmlOutput - extension formats",
// deno-lint-ignore require-await
async () => {
assert(isHtmlOutput("html"));
assert(isHtmlOutput("acm-html"));
assert(isHtmlOutput("nature-html"));
assert(!isHtmlOutput("acm-pdf"));
},
);

unitTest(
"isTypstOutput - extension formats",
// deno-lint-ignore require-await
async () => {
assert(isTypstOutput("typst"));
assert(isTypstOutput("orange-book-typst"));
assert(!isTypstOutput("acm-pdf"));
},
);

unitTest(
"isRevealjsOutput - extension formats",
// deno-lint-ignore require-await
async () => {
assert(isRevealjsOutput("revealjs"));
assert(isRevealjsOutput("clean-revealjs"));
assert(isRevealjsOutput("my-theme-revealjs"));
assert(!isRevealjsOutput("html"));
assert(!isRevealjsOutput("acm-pdf"));
},
);

unitTest(
"isJatsOutput - extension formats",
// deno-lint-ignore require-await
async () => {
assert(isJatsOutput("jats"));
assert(isJatsOutput("jats_archiving"));
assert(isJatsOutput("plos-jats"));
assert(isJatsOutput("my-journal-jats_archiving"));
assert(!isJatsOutput("html"));
assert(!isJatsOutput("acm-pdf"));
},
);

unitTest(
"format detection - malformed inputs",
// deno-lint-ignore require-await
async () => {
assert(!isPdfOutput("---"));
assert(!isPdfOutput("123"));
assert(isHtmlOutput("")); // empty defaults to "html" internally
assert(!isRevealjsOutput(""));
assert(!isJatsOutput(""));
},
);
Loading