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
92 changes: 0 additions & 92 deletions src/resources/filters/crossref/theorems.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,98 +37,6 @@ function crossref_theorems()
proof.order = add_crossref(label, type, title)
return proof
end,
Div = function(el)
local type = refType(el.attr.identifier)
local theoremType = theorem_types[type]
if theoremType then
internal_error()
else
-- see if this is a proof, remark, or solution
local proof = proof_type(el)
if proof ~= nil then

-- ensure requisite latex is injected
crossref.using_theorems = true

if proof.env ~= "proof" then
el.attr.classes:insert("proof")
end

-- capture then remove name
--
-- we have string_to_quarto_ast_inlines but we don't need it here
-- because this filter happened after shortcode processing, and this
-- is a regular div we're processing
local name = markdownToInlines(el.attr.attributes["name"])
if not name or #name == 0 then
name = resolveHeadingCaption(el)
end
el.attr.attributes["name"] = nil

-- output
if _quarto.format.isLatexOutput() then
local preamble = pandoc.List()
preamble:insert(pandoc.RawInline("latex", "\\begin{" .. proof.env .. "}"))
if name ~= nil then
preamble:insert(pandoc.RawInline("latex", "["))
tappend(preamble, name)
preamble:insert(pandoc.RawInline("latex", "]"))
end
preamble:insert(pandoc.RawInline("latex", "\n"))
-- https://github.com/quarto-dev/quarto-cli/issues/6077
if el.content[1].t == "Para" then
preamble:extend(el.content[1].content)
el.content[1].content = preamble
else
if (el.content[1].t ~= "Para") then
-- required trick to get correct alignement when non Para content first
preamble:insert(pandoc.RawInline('latex', "\\leavevmode"))
end
el.content:insert(1, pandoc.Plain(preamble))
end
local end_env = "\\end{" .. proof.env .. "}"
-- https://github.com/quarto-dev/quarto-cli/issues/6077
if el.content[#el.content].t == "Para" then
el.content[#el.content].content:insert(pandoc.RawInline("latex", "\n" .. end_env))
elseif el.content[#el.content].t == "RawBlock" and el.content[#el.content].format == "latex" then
-- this is required for no empty line between end_env and previous latex block
el.content[#el.content].text = el.content[#el.content].text .. "\n" .. end_env
else
el.content:insert(pandoc.RawBlock("latex", end_env))
end
elseif _quarto.format.isJatsOutput() then
el = jatsTheorem(el, nil, name )
else
local span = pandoc.Span(
{ pandoc.Emph(pandoc.Str(envTitle(proof.env, proof.title)))},
pandoc.Attr("", { "proof-title" })
)
if name ~= nil then
span.content:insert(pandoc.Str(" ("))
tappend(span.content, name)
span.content:insert(pandoc.Str(")"))
end
tappend(span.content, { pandoc.Str(". ")})

-- if the first block is a paragraph, then prepend the title span
if #el.content > 0 and
el.content[1].t == "Para" and
el.content[1].content ~= nil and
#el.content[1].content > 0 then
el.content[1].content:insert(1, span)
else
-- else insert a new paragraph
el.content:insert(1, pandoc.Para{span})
end
end

end

end

return el

end
}

end
Expand Down
13 changes: 5 additions & 8 deletions src/resources/filters/layout/pandoc3_figure.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,8 @@ function render_pandoc3_figure()
local function html_handle_linked_image(figure)
local div = pandoc.Div({})
div.identifier = "fig-yesiamafigure" -- this is a bad hack to make discoverLinkedFigureDiv work
local link = nil
if figure.content[1].t == "Plain" then
local plain = figure.content[1]
if plain.content[1].t == "Link" then
link = plain.content[1]
end
end
if link == nil then
local link = quarto.utils.match("[1]/Plain/[1]/Link")(figure)
if not link then
return nil
end
div.content:insert(pandoc.Para({link}))
Expand Down Expand Up @@ -197,6 +191,9 @@ function render_pandoc3_figure()
end
end
end
if #figure.content == 0 then
return nil
end
return make_typst_figure({
content = figure.content[1],
caption = figure.caption.long[1],
Expand Down
2 changes: 1 addition & 1 deletion src/resources/filters/quarto-post/latexdiv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function latexDiv()

-- if the first and last div blocks are paragraphs then we can
-- bring the environment begin/end closer to the content
if divEl.content[1].t == "Para" and divEl.content[#divEl.content].t == "Para" then
if quarto.utils.match("[1]/Para")(divEl) and divEl.content[#divEl.content].t == "Para" then
table.insert(divEl.content[1].content, 1, pandoc.RawInline('tex', beginEnv .. "\n"))
table.insert(divEl.content[#divEl.content].content, pandoc.RawInline('tex', "\n" .. endEnv))
else
Expand Down
10 changes: 4 additions & 6 deletions src/resources/filters/quarto-pre/parsefiguredivs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,9 @@ function parse_floatreftargets()
local identifier = div.identifier
local attr = pandoc.Attr(identifier, div.classes, div.attributes)
assert(content)
if (#content == 1 and content[1].t == "Para" and
content[1].content[1].t == "Image") then
-- if the div contains a single image, then we simply use the image as
-- the content
content = content[1].content[1]
local single_image = quarto.utils.match("[1]/Para/[1]/Image")(content)
if #content == 1 and single_image then
content = single_image

-- don't merge classes because they often have CSS consequences
-- but merge attributes because they're needed to correctly resolve
Expand Down Expand Up @@ -486,7 +484,7 @@ function parse_floatreftargets()
if category == nil then
return nil
end
if #fig.content ~= 1 and fig.content[1].t ~= "Plain" then
if #fig.content ~= 1 or fig.content[1].t ~= "Plain" then
-- we don't know how to parse this pandoc 3 figure
-- just return as is
return nil
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- Test helper: empties Figure content to trigger unguarded .content[1].t access
function Figure(fig)
if fig.identifier == "fig-emptied" then
fig.content = pandoc.Blocks({})
return fig
end
end
25 changes: 25 additions & 0 deletions tests/docs/smoke-all/crossrefs/float/empty-figure-content.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: Empty Figure content guard
format: pdf
keep-tex: true
filters:
- at: pre-ast
path: empty-figure-content-filter.lua
_quarto:
tests:
pdf:
noErrors: default
ensureLatexFileRegexMatches:
-
- '\\begin\{figure\}'
---

## Normal figure

![A caption](img/surus.jpg){#fig-normal}

See @fig-normal.

## Figure with content stripped by filter

![Emptied caption](img/surus.jpg){#fig-emptied}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- Test helper: empties non-crossref Figure content to trigger
-- unguarded .content[1].t access in pandoc3_figure.lua
function Figure(fig)
if fig.identifier == "" then
fig.content = pandoc.Blocks({})
return fig
end
end
15 changes: 15 additions & 0 deletions tests/docs/smoke-all/crossrefs/float/empty-pandoc3-figure.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: Empty Pandoc 3 Figure content guard
format: html
filters:
- at: pre-ast
path: empty-pandoc3-figure-filter.lua
_quarto:
tests:
html:
noErrors: default
---

## Figure without cross-ref identifier

![A plain figure caption](img/surus.jpg)
10 changes: 10 additions & 0 deletions tests/docs/smoke-all/crossrefs/float/empty-para-inlines-filter.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Test helper: creates a fig-div with a single empty Para (no inlines)
-- and a fig-cap attribute for caption, triggering unguarded
-- content[1].content[1].t access in parsefiguredivs.lua:309
function Div(div)
if div.identifier == "fig-empty-para" then
div.content = pandoc.Blocks({pandoc.Para({})})
div.attributes["fig-cap"] = "External caption"
return div
end
end
21 changes: 21 additions & 0 deletions tests/docs/smoke-all/crossrefs/float/empty-para-inlines.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: Empty Para inlines guard
format: html
filters:
- at: pre-ast
path: empty-para-inlines-filter.lua
_quarto:
tests:
html:
noErrors: default
---

## Figure div with content replaced by empty Para

::: {#fig-empty-para}
![Normal image](img/surus.jpg)

Normal caption
:::

See @fig-empty-para.
35 changes: 35 additions & 0 deletions tests/docs/smoke-all/crossrefs/theorem/proof-rendering-html.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
title: Proof rendering (HTML)
format: html
_quarto:
tests:
html:
noErrors: default
ensureHtmlElements:
-
- 'div.proof'
- '.proof-title'
---

## Proof with content

::: {.proof}
This is a proof with content.
:::

## Named proof

::: {.proof name="Of the main theorem"}
Named proof body.
:::

## Empty proof

::: {.proof}
:::

## Remark

::: {.remark}
This is a remark.
:::
39 changes: 39 additions & 0 deletions tests/docs/smoke-all/crossrefs/theorem/proof-rendering.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: Proof rendering
format: pdf
keep-tex: true
_quarto:
tests:
pdf:
noErrors: default
ensureLatexFileRegexMatches:
-
- '\\begin\{proof\}'
- '\\end\{proof\}'
- '\\begin\{proof\}\[Of the main theorem\]'
- '\\begin\{remark\}'
- '\\end\{remark\}'
---

## Proof with content

::: {.proof}
This is a proof with content.
:::

## Named proof

::: {.proof name="Of the main theorem"}
Named proof body.
:::

## Empty proof

::: {.proof}
:::

## Remark

::: {.remark}
This is a remark.
:::
26 changes: 26 additions & 0 deletions tests/docs/smoke-all/latex/empty-latex-div.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: Empty LaTeX div
format: pdf
keep-tex: true
_quarto:
tests:
pdf:
noErrors: default
ensureLatexFileRegexMatches:
-
- '\\begin\{center\}'
- '\\end\{center\}'
- '\\begin\{flushright\}'
- '\\end\{flushright\}'
---

## Non-empty LaTeX div

::: {.center latex="true"}
Some centered content.
:::

## Empty LaTeX div

::: {.flushright latex="true"}
:::
Loading