Skip to content

Commit

Permalink
Merge pull request #7449 from quarto-dev/bugfix/1829
Browse files Browse the repository at this point in the history
Respect *-cap-location everywhere
  • Loading branch information
cscheid authored Nov 2, 2023
2 parents a406ade + 95c6dd6 commit 825c78d
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 20 deletions.
2 changes: 2 additions & 0 deletions src/resources/filters/crossref/crossref.lua
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ local quarto_normalize_filters = {
return quarto_global_state.active_filters.normalization
end, normalize_filter()) },

{ name = "normalize-capture-reader-state", filter = normalize_capture_reader_state() },

{ name = "pre-table-merge-raw-html",
filter = table_merge_raw_html()
},
Expand Down
23 changes: 15 additions & 8 deletions src/resources/filters/customnodes/floatreftarget.lua
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,28 @@ _quarto.ast.add_handler({
end
})

function cap_location(float)
local ref = refType(float.identifier)
function cap_location(float_or_layout)
local ref = refType(float_or_layout.identifier)
-- layouts might not have good identifiers, but they might have
-- ref-parents
if ref == nil then
ref = refType(float_or_layout.attributes["ref-parent"] or "")
end
-- last resort, pretend we're a figure
if ref == nil then
ref = "fig"
end
local qualified_key = ref .. '-cap-location'
local result = (
float.attributes[qualified_key] or
float.attributes['cap-location'] or
float_or_layout.attributes[qualified_key] or
float_or_layout.attributes['cap-location'] or
option_as_string(qualified_key) or
option_as_string('cap-location') or
capLocation(ref) or
crossref.categories.by_ref_type[ref].default_caption_location)

if result ~= "margin" and result ~= "top" and result ~= "bottom" then
-- luacov: disable
error("Invalid caption location for float: " .. float.identifier ..
error("Invalid caption location for float: " .. float_or_layout.identifier ..
" requested " .. result ..
".\nOnly 'top', 'bottom', and 'margin' are supported. Assuming 'bottom'.")
result = "bottom"
Expand Down Expand Up @@ -203,9 +211,8 @@ end, function(float)
local figEnv = latexFigureEnv(float)
local figPos = latexFigurePosition(float, figEnv)
local float_type = refType(float.identifier)
local crossref_category = crossref.categories.by_ref_type[float_type] or crossref.categories.by_name.Figure

local capLoc = capLocation(float_type, crossref_category.default_caption_location)
local capLoc = cap_location(float)
local caption_cmd_name = latexCaptionEnv(float)

if float.parent_id then
Expand Down
6 changes: 3 additions & 3 deletions src/resources/filters/layout/html.lua
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ end)
-- captionPara.content:insert(pandoc.RawInline("html", figcaption))
-- tappend(captionPara.content, caption.content)
-- captionPara.content:insert(pandoc.RawInline("html", "</figcaption>"))
-- if capLocation('fig', 'bottom') == 'bottom' then
-- if cap_location_from_option('fig', 'bottom') == 'bottom' then
-- panel.content:insert(captionPara)
-- else
-- tprepend(panel.content, { captionPara })
Expand All @@ -198,7 +198,7 @@ end)
-- local panelCaption = pandoc.Div(caption, pandoc.Attr("", { "panel-caption" }))
-- if hasTableRef(divEl) then
-- panelCaption.attr.classes:insert("table-caption")
-- if capLocation('tbl', 'top') == 'bottom' then
-- if cap_location_from_option('tbl', 'top') == 'bottom' then
-- panel.content:insert(panelCaption)
-- else
-- tprepend(panel.content, { panelCaption })
Expand Down Expand Up @@ -312,7 +312,7 @@ function renderHtmlFigure(el, render)
))
tappend(figureCaption.content, captionInlines)
figureCaption.content:insert(pandoc.RawInline("html", "</figcaption>"))
if capLocation('fig', 'bottom') == 'top' then
if cap_location_from_option('fig', 'bottom') == 'top' then
figureDiv.content:insert(figureCaption)
tappend(figureDiv.content, figure)
else
Expand Down
10 changes: 2 additions & 8 deletions src/resources/filters/layout/latex.lua
Original file line number Diff line number Diff line change
Expand Up @@ -328,13 +328,7 @@ function latexCell(cell, vAlign, endOfRow, endOfTable)
local miniPageVAlign = latexMinipageValign(vAlign)
latexAppend(prefix, "\\begin{minipage}" .. miniPageVAlign .. "{" .. width .. "}\n")

local capType = "fig"
local locDefault = "bottom"
if isTable then
capType = "tbl"
locDefault = "top"
end
local capLoc = capLocation(capType, locDefault)
local capLoc = cap_location(cell)

if (capLoc == "top") then
tappend(prefix, subcap)
Expand Down Expand Up @@ -653,7 +647,7 @@ function renderLatexFigure(el, render)
-- get the figure content and caption inlines
local figureContent, captionInlines = render(figure)

local capLoc = capLocation("fig", "bottom")
local capLoc = cap_location_from_option("fig", "bottom")

-- surround caption w/ appropriate latex (and end the figure)
if captionInlines and inlinesToString(captionInlines) ~= "" then
Expand Down
2 changes: 1 addition & 1 deletion src/resources/filters/quarto-pre/options.lua
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function parseOption(name, options, def)
end
end

function capLocation(scope, default)
function cap_location_from_option(scope, default)
local loc = option(scope .. '-cap-location', option('cap-location', nil))
if loc ~= nil then
return inlinesToString(loc)
Expand Down
73 changes: 73 additions & 0 deletions src/resources/filters/quarto-pre/parsefiguredivs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@

local patterns = require("modules/patterns")

local function process_div_caption_classes(div)
-- knitr forwards "cap-location: top" as `.caption-top`...
-- and in that case we don't know if it's a fig- or a tbl- :facepalm:
-- so we have to use cap-locatin generically in the attribute
if div.classes:find_if(
function(class) return class:match("caption%-.+") end) then
local matching_classes = div.classes:filter(function(class)
return class:match("caption%-.+")
end)
div.classes = div.classes:filter(function(class)
return not class:match("caption%-.+")
end)
for i, c in ipairs(matching_classes) do
div.attributes["cap-location"] = c:match("caption%-(.+)")
end
return true
end
return false
end

local function coalesce_code_blocks(content)
local result = pandoc.Blocks({})
local state = "start"
Expand Down Expand Up @@ -134,6 +154,7 @@ function parse_reftargets()
end

local function parse_float_div(div)
process_div_caption_classes(div)
local ref = refType(div.identifier)
if ref == nil then
fail("Float div without crossref identifier?")
Expand All @@ -151,6 +172,24 @@ function parse_reftargets()
local content = div.content
local caption_attr_key = ref .. "-cap"

-- caption location handling

-- .*-cap-location
local caption_location_attr_key = ref .. "-cap-location"
local caption_location_class_pattern = ".*cap%-location%-(.*)"
local caption_location_classes = div.classes:filter(function(class)
return class:match(caption_location_class_pattern)
end)

if #caption_location_classes then
div.classes = div.classes:filter(function(class)
return not class:match(caption_location_class_pattern)
end)
for _, class in ipairs(caption_location_classes) do
local c = class:match(caption_location_class_pattern)
div.attributes[caption_location_attr_key] = c
end
end
local caption = refCaptionFromDiv(div)
if caption ~= nil then
div.content:remove(#div.content)
Expand Down Expand Up @@ -381,6 +420,40 @@ function parse_reftargets()
elseif is_theorem_div(div) then
return parse_theorem_div(div)
end

if div.classes:includes("cell") then
process_div_caption_classes(div)
-- forward cell attributes to potential FloatRefTargets
div = _quarto.ast.walk(div, {
Figure = function(fig)
if div.attributes["cap-location"] then
fig.attributes["cap-location"] = div.attributes["cap-location"]
end
for i, c in ipairs(div.classes) do
local c = c:match(".*%-?cap%-location%-(.*)")
if c then
fig.attributes["cap-location"] = c
end
end
return fig
end,
CodeBlock = function(block)
for _, k in ipairs({"cap-location", "lst-cap-location"}) do
if div.attributes[k] then
block.attributes[k] = div.attributes[k]
end
end
for i, c in ipairs(div.classes) do
local c = c:match(".*%-?cap%-location%-(.*)")
if c then
block.attributes["cap-location"] = c
end
end
return block
end,
})
return div
end
end,

Para = function(para)
Expand Down

0 comments on commit 825c78d

Please sign in to comment.