Skip to content

Allow {{< contents >}} to use inline elements #13122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions news/changelog-1.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,4 @@ All changes included in 1.8:
- ([#12782](https://github.com/quarto-dev/quarto-cli/pull/12782)): fix bug on `safeRemoveDirSync`'s detection of safe directory boundaries.
- ([#12853](https://github.com/quarto-dev/quarto-cli/issues/12853)): fix replaceAll() escaping issue with embedded notebooks containing `$` in their Markdown.
- ([#12939](https://github.com/quarto-dev/quarto-cli/pull/12939)): Upgrade `mermaidjs` to 11.6.0.
- ([#13121](https://github.com/quarto-dev/quarto-cli/issues/13121)): Allow `contents` shortcode to find inline elements.
54 changes: 40 additions & 14 deletions src/resources/filters/quarto-pre/contentsshortcode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ function contents_shortcode_filter()
local divs = {}
local spans = {}

local function handle_inline_with_attr(el)
if ids_used[el.attr.identifier] then
spans[el.attr.identifier] = el
return {}
end

-- remove 'cell-' from identifier, try again
local truncated_id = el.attr.identifier:match("^cell%-(.+)$")
if ids_used[truncated_id] then
spans[truncated_id] = el
-- FIXME: this is a workaround for the fact that we don't have a way to
-- distinguish between divs that appear as the output of code cells
-- (which have a different id creation mechanism)
-- and "regular" divs.
-- We need to fix https://github.com/quarto-dev/quarto-cli/issues/7062 first.
return {}
else
return nil
end
end

return {
Pandoc = function(doc)
_quarto.ast.walk(doc.blocks, {
Expand Down Expand Up @@ -43,13 +64,10 @@ function contents_shortcode_filter()
return nil
end
end,
Span = function(el)
if not ids_used[el.attr.identifier] then
return nil
end
spans[el.attr.identifier] = el
return {}
end
Code = handle_inline_with_attr,
Image = handle_inline_with_attr,
Span = handle_inline_with_attr,
Link = handle_inline_with_attr
})

local handle_block = function(el)
Expand All @@ -75,14 +93,22 @@ function contents_shortcode_filter()
return {}
end
local div = divs[data]
if div == nil then
warn(
"[Malformed document] Found `contents` shortcode without a corresponding div with id: " .. tostring(data) .. ".\n" ..
"This might happen because the shortcode is used in div context, while the id corresponds to a span.\n" ..
"Removing from document.")
return {}
if div ~= nil then
-- if we have a div, return it
return div
end
-- if we don't have a div, try to find a span
-- and wrap it in a div
local span = spans[data]
if span ~= nil then
-- if we have a span, return it wrapped in a div
return pandoc.Div(pandoc.Plain({span}))
end
return div
quarto.log.warning(
"[Malformed document] Found `contents` shortcode without a corresponding div with id: " .. tostring(data) .. ".\n" ..
"This might happen because the shortcode is used in div context, while the id corresponds to a span.\n" ..
"Removing from document.")
return {}
end
-- replace div-context entries
doc.blocks = _quarto.ast.walk(doc.blocks, {
Expand Down
34 changes: 34 additions & 0 deletions tests/docs/smoke-all/2025/07/23/13121.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
format: typst
title: Another section
_quarto:
tests:
typst:
noErrorsOrWarnings: true
---

## A section

Here we define a plot.

::: {.cell execution_count=1}

::: {.cell-output .cell-output-display}
`code`{#a-cell}
:::
:::



Here we use the plot, inside a callout:


::: callout-note

## Note the following plot

{{< contents a-cell >}}

:::


3 changes: 3 additions & 0 deletions tests/smoke/smoke-all.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ function resolveTestSpecs(
} else if (key === "noErrors") {
checkWarnings = false;
verifyFns.push(noErrors);
} if (key === "noErrorsOrWarnings") {
checkWarnings = false;
verifyFns.push(noErrorsOrWarnings);
} else {
// See if there is a project and grab it's type
const projectPath = findRootTestsProjectDir(input)
Expand Down
5 changes: 5 additions & 0 deletions tests/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ export const noErrorsOrWarnings: Verify = {
const isErrorOrWarning = (output: ExecuteOutput) => {
return output.levelName.toLowerCase() === "warn" ||
output.levelName.toLowerCase() === "error";
// I'd like to do this but many many of our tests
// would fail right now because we're assuming noErrorsOrWarnings
// doesn't include warnings from the lua subsystem
// ||
// output.msg.startsWith("(W)"); // this is a warning from quarto.log.warning()
};

const errorsOrWarnings = outputs.some(isErrorOrWarning);
Expand Down
Loading