Skip to content
Closed
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
5 changes: 5 additions & 0 deletions news/changelog-1.11.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ All changes included in 1.11:
- ([#14376](https://github.com/quarto-dev/quarto-cli/issues/14376)): Translate the new `navigation-*-label` keys in all 33 built-in language files. The values are drawn from existing human-translated interface strings (LibreOffice, GNOME, Wikidata) and each one carries a comment naming its source; values that were adapted rather than used verbatim are marked `needs review`.
- ([#14376](https://github.com/quarto-dev/quarto-cli/issues/14376)): Label the table of contents `<nav>` with its localized title (`aria-labelledby`), in `html` and `revealjs` output, so assistive technology can tell it apart from other navigation landmarks.

## Crossrefs

- ([commit](https://github.com/quarto-dev/quarto-cli/commit/c4d6d3bba92abff4a1171affc3ba3e6a49f2ed91)): Add `crossref: numbering: external`, which skips Quarto's own numbering, index, and `@ref`-resolution passes and renders the numbers already present on the nodes, for front ends that compute their own cross-reference numbers. Currently supported for `docx`, `odt`, and `pptx` output only; `latex`/`pdf`/`beamer` and `typst` output raise an error.

## Formats

### All Formats
Expand Down Expand Up @@ -67,6 +71,7 @@ All changes included in 1.11:
## Lua API

- ([#14894](https://github.com/quarto-dev/quarto-cli/pull/14894)): Fix `quarto.version` and `quarto.config.version()` crashing filters with `table expected, got string` when the version string contains semver build metadata (such as a distro packager's revision suffix) or otherwise does not start with a digit.
- ([commit](https://github.com/quarto-dev/quarto-cli/commit/0c497cd6dc6d12ffaf073cc3cbfedadbd3113cdf)): Add `quarto.doc.crossref.subrefNumber`, `refPrefix`, `refDelim`, `refHyperlink`, `refNumberOption`, `crossrefOption`, `renderEquation`, and `quarto.utils.nbspString`, sanctioning functions that were previously called as undefended bare globals by external front ends that reconstruct Quarto custom nodes outside the filter pipeline.

## Other fixes and improvements

Expand Down
7 changes: 7 additions & 0 deletions src/command/render/crossref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import {
kCrossrefNumbering,
kListings,
kNumberDepth,
kNumberOffset,
Expand Down Expand Up @@ -65,6 +66,12 @@ export function crossrefFilterParams(
// Read the number depth
params[kNumberDepth] = metadata?.[kNumberDepth];

// crossref.numbering: who assigns numbers (see document-crossref.yml)
const crossrefMeta = metadata?.crossref as Metadata | undefined;
if (crossrefMeta?.numbering !== undefined) {
params[kCrossrefNumbering] = crossrefMeta.numbering;
}

// always create crossref index for projects
if (!options.project?.isSingleFile) {
// if its a book then only write for multi-file (as otherwise all of the
Expand Down
24 changes: 14 additions & 10 deletions src/command/render/pandoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,16 +271,20 @@ function captureRenderCommand(
// we need to correct the defaults YML because it contains a reference to a template in a temp directory
const ymlDefaults = Deno.readTextFileSync(arg);
const defaults = parseYml(ymlDefaults);
const templateDirectory = dirname(defaults.template);
const newTemplateDirectory = join(
outputDir,
basename(templateDirectory),
);
copyTo(templateDirectory, newTemplateDirectory);
defaults.template = join(
newTemplateDirectory,
basename(defaults.template),
);
// Not every format's defaults YAML references a template (e.g. docx),
// so only rewrite the template path when one is present.
if (defaults.template) {
const templateDirectory = dirname(defaults.template);
const newTemplateDirectory = join(
outputDir,
basename(templateDirectory),
);
copyTo(templateDirectory, newTemplateDirectory);
defaults.template = join(
newTemplateDirectory,
basename(defaults.template),
);
}
const defaultsOutputFile = join(outputDir, basename(arg));
Deno.writeTextFileSync(defaultsOutputFile, stringify(defaults));
return defaultsOutputFile;
Expand Down
1 change: 1 addition & 0 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ export const kCrossrefCorTitle = "crossref-cor-title";
export const kCrossrefPrfTitle = "crossref-prp-title";
export const kCrossrefCnjTitle = "crossref-cnj-title";
export const kCrossrefDefTitle = "crossref-def-title";
export const kCrossrefNumbering = "crossref-numbering";
export const kCrossrefExmTitle = "crossref-exm-title";
export const kCrossrefExrTitle = "crossref-exr-title";
export const kCrossrefFigPrefix = "crossref-fig-prefix";
Expand Down
15 changes: 12 additions & 3 deletions src/resources/editor/tools/vs-code.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14209,6 +14209,14 @@ var require_yaml_intelligence_resources = __commonJS({
default: false
}
},
numbering: {
enum: [
"quarto",
"external"
],
default: "quarto",
description: 'Who assigns cross-reference numbers. "quarto" (the default) numbers\ncross-references in Quarto\'s own filters. "external" skips Quarto\'s\nnumbering, index, and @ref-resolution passes and renders the numbers\nalready present on the nodes \u2014 for front ends that compute their own.\nCurrently only supported for `docx`, `odt`, and `pptx` output; LaTeX\n(`latex`/`pdf`/`beamer`) and `typst` output raise an error.\n'
},
"title-delim": {
string: {
description: "The delimiter used between the prefix and the caption."
Expand Down Expand Up @@ -23555,6 +23563,7 @@ var require_yaml_intelligence_resources = __commonJS({
"The description of the crossreferenceable object to be used in the\ntitle of the \u201Clist of\u201D command. If omitted, the field\n<code>reference-prefix</code> is used.",
"The location of the caption relative to the crossreferenceable\ncontent.",
"Use top level sections (H1) in this document as chapters.",
'Who assigns cross-reference numbers. \u201Cquarto\u201D (the default) numbers\ncross-references in Quarto\u2019s own filters. \u201Cexternal\u201D skips Quarto\u2019s\nnumbering, index, and <span class="citation" data-cites="ref-resolution">@ref-resolution</span> passes and renders\nthe numbers already present on the nodes \u2014 for front ends that compute\ntheir own. Currently only supported for <code>docx</code>,\n<code>odt</code>, and <code>pptx</code> output; LaTeX\n(<code>latex</code>/<code>pdf</code>/<code>beamer</code>) and\n<code>typst</code> output raise an error.',
"The delimiter used between the prefix and the caption.",
"The title prefix used for figure captions.",
"The title prefix used for table captions.",
Expand Down Expand Up @@ -25589,12 +25598,12 @@ var require_yaml_intelligence_resources = __commonJS({
mermaid: "%%"
},
"handlers/mermaid/schema.yml": {
_internalId: 218300,
_internalId: 218540,
type: "object",
description: "be an object",
properties: {
"mermaid-format": {
_internalId: 218292,
_internalId: 218532,
type: "enum",
enum: [
"png",
Expand All @@ -25610,7 +25619,7 @@ var require_yaml_intelligence_resources = __commonJS({
exhaustiveCompletions: true
},
theme: {
_internalId: 218299,
_internalId: 218539,
type: "anyOf",
anyOf: [
{
Expand Down

Large diffs are not rendered by default.

15 changes: 12 additions & 3 deletions src/resources/editor/tools/yaml/web-worker.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 12 additions & 3 deletions src/resources/editor/tools/yaml/yaml-intelligence-resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -7177,6 +7177,14 @@
"default": false
}
},
"numbering": {
"enum": [
"quarto",
"external"
],
"default": "quarto",
"description": "Who assigns cross-reference numbers. \"quarto\" (the default) numbers\ncross-references in Quarto's own filters. \"external\" skips Quarto's\nnumbering, index, and @ref-resolution passes and renders the numbers\nalready present on the nodes — for front ends that compute their own.\nCurrently only supported for `docx`, `odt`, and `pptx` output; LaTeX\n(`latex`/`pdf`/`beamer`) and `typst` output raise an error.\n"
},
"title-delim": {
"string": {
"description": "The delimiter used between the prefix and the caption."
Expand Down Expand Up @@ -16523,6 +16531,7 @@
"The description of the crossreferenceable object to be used in the\ntitle of the “list of” command. If omitted, the field\n<code>reference-prefix</code> is used.",
"The location of the caption relative to the crossreferenceable\ncontent.",
"Use top level sections (H1) in this document as chapters.",
"Who assigns cross-reference numbers. “quarto” (the default) numbers\ncross-references in Quarto’s own filters. “external” skips Quarto’s\nnumbering, index, and <span class=\"citation\" data-cites=\"ref-resolution\">@ref-resolution</span> passes and renders\nthe numbers already present on the nodes — for front ends that compute\ntheir own. Currently only supported for <code>docx</code>,\n<code>odt</code>, and <code>pptx</code> output; LaTeX\n(<code>latex</code>/<code>pdf</code>/<code>beamer</code>) and\n<code>typst</code> output raise an error.",
"The delimiter used between the prefix and the caption.",
"The title prefix used for figure captions.",
"The title prefix used for table captions.",
Expand Down Expand Up @@ -18557,12 +18566,12 @@
"mermaid": "%%"
},
"handlers/mermaid/schema.yml": {
"_internalId": 218300,
"_internalId": 218540,
"type": "object",
"description": "be an object",
"properties": {
"mermaid-format": {
"_internalId": 218292,
"_internalId": 218532,
"type": "enum",
"enum": [
"png",
Expand All @@ -18578,7 +18587,7 @@
"exhaustiveCompletions": true
},
"theme": {
"_internalId": 218299,
"_internalId": 218539,
"type": "anyOf",
"anyOf": [
{
Expand Down
4 changes: 4 additions & 0 deletions src/resources/filters/common/pandoc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ function nbspString()
return pandoc.Str '\u{a0}'
end

-- exposed for external front ends that reconstruct Quarto custom nodes
-- outside the filter pipeline
quarto.utils.nbspString = nbspString

-- the first heading in a div is sometimes the caption
function resolveHeadingCaption(div)
local capEl = div.content[1]
Expand Down
4 changes: 4 additions & 0 deletions src/resources/filters/crossref/equations.lua
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ function renderEquation(eq, label, alt, order)
return result
end

-- exposed for external front ends that reconstruct Quarto custom nodes
-- outside the filter pipeline
quarto.doc.crossref.renderEquation = renderEquation

function eqTag(eq)
return "\\tag{" .. eq .. "}"
end
Expand Down
22 changes: 21 additions & 1 deletion src/resources/filters/crossref/format.lua
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ function subrefNumber(order)
return numberOption("subref", order, {pandoc.Str("alpha"),pandoc.Space(),pandoc.Str("a")})
end

-- exposed for external front ends that reconstruct Quarto custom nodes
-- outside the filter pipeline
quarto.doc.crossref.subrefNumber = subrefNumber

function prependSubrefNumber(captionContent, order)
if not _quarto.format.isLatexOutput() and not _quarto.format.isAsciiDocOutput() then
if #inlinesToString(captionContent) > 0 then
Expand Down Expand Up @@ -95,20 +99,32 @@ function refPrefix(type, upper)
return prefix
end

-- exposed for external front ends that reconstruct Quarto custom nodes
-- outside the filter pipeline
quarto.doc.crossref.refPrefix = refPrefix

function refDelim()
return crossrefOption("ref-delim", stringToInlines(","))
end

-- exposed for external front ends that reconstruct Quarto custom nodes
-- outside the filter pipeline
quarto.doc.crossref.refDelim = refDelim

function refHyperlink()
return crossrefOption("ref-hyperlink", true)
end

-- exposed for external front ends that reconstruct Quarto custom nodes
-- outside the filter pipeline
quarto.doc.crossref.refHyperlink = refHyperlink

function refNumberOption(type, entry)

-- for sections just return the section levels
if type == "sec" then
local num = nil
if entry.appendix then
if entry.appendix and crossref.startAppendix ~= nil then
num = string.char(64 + entry.order.section[1] - crossref.startAppendix + 1)
elseif crossrefOption("chapters", false) then
num = tostring(entry.order.section[1])
Expand All @@ -120,6 +136,10 @@ function refNumberOption(type, entry)
return formatNumberOption(type, entry.order)
end

-- exposed for external front ends that reconstruct Quarto custom nodes
-- outside the filter pipeline
quarto.doc.crossref.refNumberOption = refNumberOption


function numberOption(type, order, default)

Expand Down
4 changes: 4 additions & 0 deletions src/resources/filters/crossref/options.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@ function crossrefOption(name, default)
return readOption(crossref.options, name, default)
end

-- exposed for external front ends that reconstruct Quarto custom nodes
-- outside the filter pipeline
quarto.doc.crossref.crossrefOption = crossrefOption



8 changes: 4 additions & 4 deletions src/resources/filters/customnodes/floatreftarget.lua
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ function is_unlabeled_float(float)
end

function decorate_caption_with_crossref(float)
if not param("enable-crossref", true) then
if not _quarto.modules.crossref_numbering.crossref_present() then
-- don't decorate captions with crossrefs information if crossrefs are disabled
return float
end
Expand Down Expand Up @@ -239,7 +239,7 @@ end
quarto.doc.crossref.decorate_caption_with_crossref = decorate_caption_with_crossref

function full_caption_prefix(float, subfloat)
if not param("enable-crossref", true) then
if not _quarto.modules.crossref_numbering.crossref_present() then
-- don't decorate captions with crossrefs information if crossrefs are disabled
return {}
end
Expand Down Expand Up @@ -962,7 +962,7 @@ end, function(float)
end)

_quarto.ast.add_renderer("FloatRefTarget", function(_)
return _quarto.format.isIpynbOutput() and param("enable-crossref", true)
return _quarto.format.isIpynbOutput() and _quarto.modules.crossref_numbering.crossref_present()
end, function(float)
decorate_caption_with_crossref(float)
if float.content.t == "Plain" and #float.content.content == 1 and float.content.content[1].t == "Image" then
Expand All @@ -979,7 +979,7 @@ end)

-- this should really be "_quarto.format.isEmbedIpynb()" or something like that..
_quarto.ast.add_renderer("FloatRefTarget", function(_)
return _quarto.format.isIpynbOutput() and not param("enable-crossref", true)
return _quarto.format.isIpynbOutput() and not _quarto.modules.crossref_numbering.crossref_present()
end, function(float)
if float.content.t == "Plain" and #float.content.content == 1 and float.content.content[1].t == "Image" then
local imgEl = float.content.content[1]
Expand Down
5 changes: 5 additions & 0 deletions src/resources/filters/layout/ipynb.lua
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ local function render_ipynb_layout(layout)
return pandoc.Div(panel_content, attr)
end

-- Deliberately left reading the enable-crossref param directly rather than
-- calling _quarto.modules.crossref_numbering.crossref_present(): both predicates
-- below dispatch to the same render_ipynb_layout callback, so this pair is a
-- verified no-op regardless of which flag it reads and is intentionally not
-- converted.
_quarto.ast.add_renderer("PanelLayout", function(_)
return _quarto.format.isIpynbOutput() and param("enable-crossref", true)
end, render_ipynb_layout)
Expand Down
20 changes: 17 additions & 3 deletions src/resources/filters/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,9 @@ initCrossrefIndex()

initShortcodeHandlers()

-- see whether the cross ref filter is enabled
local enableCrossRef = param("enable-crossref", true)
-- whether crossref numbers are presented, and whether quarto itself
-- assigns them, are now separate questions: see
-- _quarto.modules.crossref_numbering (crossref_present / assign_crossref_numbers)

local quarto_init_filters = {
{ name = "init-quarto-meta-init", filter = quarto_meta_init() },
Expand Down Expand Up @@ -715,7 +716,20 @@ table.insert(quarto_filter_list, { name = "post-ast", filter = {} }) -- entry po

table.insert(quarto_filter_list, { name = "pre-quarto", filter = {} }) -- entry point for user filters
tappend(quarto_filter_list, quarto_pre_filters)
if enableCrossRef then
if not _quarto.modules.crossref_numbering.assign_crossref_numbers() and
_quarto.modules.crossref_numbering.crossref_present() and
(_quarto.format.isLatexOutput() or _quarto.format.isTypstOutput()) then
-- `crossref-numbering: external` skips crossrefMetaInject() (LaTeX
-- preamble for codelisting/theorem environments) and resolveRefs()
-- (which is what stops Typst's native `@id` citation syntax from
-- colliding with quarto's `@id` crossref syntax). Both failures only
-- surface deep inside the LaTeX/Typst compiler, so fail fast here
-- instead of emitting output that won't compile.
fail("crossref-numbering: external is not currently supported for " .. FORMAT ..
" output (only docx, odt, and pptx are supported); rendering would produce " ..
"malformed LaTeX/Typst output.")
end
if _quarto.modules.crossref_numbering.assign_crossref_numbers() then
tappend(quarto_filter_list, quarto_crossref_filters)
end
table.insert(quarto_filter_list, { name = "post-quarto", filter = file_metadata() }) -- entry point for user filters
Expand Down
Loading
Loading