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
231 changes: 155 additions & 76 deletions src/resources/filters/layout/pandoc3_figure.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
-- never cross-referenceable but they need to be rendered as
-- if they were.

local scope_utils = require("modules/scope")

function render_pandoc3_figure()
local function html_handle_linked_image(figure)
local div = pandoc.Div({})
Expand Down Expand Up @@ -70,90 +72,167 @@ function render_pandoc3_figure()
end
}
elseif _quarto.format.isLatexOutput() then
-- split local declaration because Lua's local is not
-- a letrec
local filter
filter = function(state)
state = state or {}
local function figure_renderer(figure, is_subfig)
-- this is a figure that is not cross-referenceable
-- if this ends up in a layout without fig-pos = H, it'll fail
-- 'H' forces it to not float
if figure.identifier == "" then
figure = _quarto.ast.walk(figure, {
Image = function(image)
image.attributes['fig-pos'] = 'H'
return image
end
})
end
local image
_quarto.ast.walk(figure, {
Image = function(img)
image = img
local function is_inside_float(scope)
for i = #scope, 1, -1 do
local s = scope[i]
local data = _quarto.ast.resolve_custom_data(s)
if data then
if (data.t == "PanelLayout" and data.is_float_reftarget == true) then
return true
elseif (data.t == "FloatRefTarget") then
return true
end
})
if image == nil then
return figure
end
if figure.caption.long ~= nil then
image.caption = quarto.utils.as_inlines(figure.caption.long)
end
for k, v in pairs(figure.attributes) do
image.attributes[k] = v
end
if is_subfig then
image.attributes['quarto-caption-env'] = 'subcaption'
end
image.classes:extend(figure.classes)
if state.in_column_margin then
image.classes:insert("column-margin")
end
end
local function is_subfig(scope)
for i = #scope, 1, -1 do
local s = scope[i]
local data = _quarto.ast.resolve_custom_data(s)
if data and (data.t == "PanelLayout") then
return true
end
return latexImageFigure(image)
end
local function float_renderer(float)
local count = 0
local new_content = _quarto.ast.walk(float.content, {
Figure = function(fig)
count = count + 1
return figure_renderer(fig, true), false
end

return false
end

local function figure_renderer(figure, scope)
if is_inside_float(scope) then
return nil, false
end
local subfig = is_subfig(scope)
-- this is a figure that is not cross-referenceable
-- if this ends up in a layout without fig-pos = H, it'll fail
-- 'H' forces it to not float
if figure.identifier == "" then
figure = _quarto.ast.walk(figure, {
Image = function(image)
image.attributes['fig-pos'] = 'H'
return image
end
})
if count > 0 then
float.content = new_content
return float, false
end
end
return {
traverse = "topdown",
PanelLayout = function(panel)
panel.rows = _quarto.ast.walk(panel.rows, {
Figure = function(fig)
return figure_renderer(fig, true), false
end
})
return panel, false
end,
FloatRefTarget = float_renderer,
Div = function(div)
if div.classes:includes("column-margin") then
local new_state = {}
for k, v in pairs(state) do
new_state[k] = v
end
new_state.in_column_margin = true

div.content = _quarto.ast.walk(div.content, filter(new_state))
div.classes = div.classes:filter(function(x) return x ~= "column-margin" end)
return div
end
end,
Figure = function(figure)
return figure_renderer(figure, false)
local image
_quarto.ast.walk(figure, {
Image = function(img)
image = img
end
}
})
if image == nil then
return figure
end
if figure.caption.long ~= nil then
image.caption = quarto.utils.as_inlines(figure.caption.long)
end
for k, v in pairs(figure.attributes) do
image.attributes[k] = v
end
if subfig then
image.attributes['quarto-caption-env'] = 'subcaption'
end
image.classes:extend(figure.classes)
if scope_utils.lookup_class(scope, "column-margin") then
image.classes:insert("column-margin")
end
return latexImageFigure(image)
end
return filter()

local filter = {
Figure = function(figure, scope)
return figure_renderer(figure, scope), false
end
}
return {
Pandoc = function(doc)
_quarto.ast.scoped_walk(doc.blocks, filter)
end
}

-- split local declaration because Lua's local is not
-- a letrec
-- local filter
-- filter = function(state)
-- state = state or {}
-- local function figure_renderer(figure, is_subfig)
-- -- this is a figure that is not cross-referenceable
-- -- if this ends up in a layout without fig-pos = H, it'll fail
-- -- 'H' forces it to not float
-- if figure.identifier == "" then
-- figure = _quarto.ast.walk(figure, {
-- Image = function(image)
-- image.attributes['fig-pos'] = 'H'
-- return image
-- end
-- })
-- end
-- local image
-- _quarto.ast.walk(figure, {
-- Image = function(img)
-- image = img
-- end
-- })
-- if image == nil then
-- return figure
-- end
-- if figure.caption.long ~= nil then
-- image.caption = quarto.utils.as_inlines(figure.caption.long)
-- end
-- for k, v in pairs(figure.attributes) do
-- image.attributes[k] = v
-- end
-- if is_subfig then
-- image.attributes['quarto-caption-env'] = 'subcaption'
-- end
-- image.classes:extend(figure.classes)
-- if state.in_column_margin then
-- image.classes:insert("column-margin")
-- end
-- return latexImageFigure(image)
-- end
-- local function float_renderer(float)
-- local count = 0
-- local new_content = _quarto.ast.walk(float.content, {
-- Figure = function(fig)
-- count = count + 1
-- return figure_renderer(fig, true), false
-- end
-- })
-- if count > 0 then
-- float.content = new_content
-- return float, false
-- end
-- end
-- return {
-- traverse = "topdown",
-- PanelLayout = function(panel)
-- panel.rows = _quarto.ast.walk(panel.rows, {
-- Figure = function(fig)
-- return figure_renderer(fig, true), false
-- end
-- })
-- return panel, false
-- end,
-- FloatRefTarget = float_renderer,
-- Div = function(div)
-- if div.classes:includes("column-margin") then
-- local new_state = {}
-- for k, v in pairs(state) do
-- new_state[k] = v
-- end
-- new_state.in_column_margin = true

-- div.content = _quarto.ast.walk(div.content, filter(new_state))
-- div.classes = div.classes:filter(function(x) return x ~= "column-margin" end)
-- return div
-- end
-- end,
-- Figure = function(figure)
-- return figure_renderer(figure, false)
-- end
-- }
-- end
-- return filter()
elseif _quarto.format.isTypstOutput() then
return {
traverse = "topdown",
Expand Down
3 changes: 2 additions & 1 deletion src/resources/filters/modules/scope.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ local function lookup_class(scope, class_name)
else
attr = scope[i].classes
end
if classes:includes(class_name) then
if classes and classes:includes(class_name) then
return true
end
i = i - 1
end
end

Expand Down
21 changes: 21 additions & 0 deletions tests/docs/smoke-all/2024/04/18/9414.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: hello
_quarto:
tests:
latex:
ensureFileRegexMatches:
- []
- ['\\begin{figure}\n\n.*\n\n\\begin{figure}']
---

::: {#fig-1 layout=[1,2]}

![Hanno](./hanno.png)

![Surus](./surus.png)

Elephants

:::

See @fig-1