From e644af3a47306a5c28fce42b63c27874d0f3adf2 Mon Sep 17 00:00:00 2001
From: Carlos Scheidegger
Date: Fri, 15 Dec 2023 16:09:18 -0700
Subject: [PATCH] feature: crossreferenceable remarks
---
news/changelog-1.4.md | 1 -
src/project/project-config.ts | 27 +--
.../types/website/website-navigation-md.ts | 6 +-
.../types/website/website-navigation.ts | 6 +-
src/resources/filters/common/theorems.lua | 25 ---
src/resources/filters/crossref/crossref.lua | 5 +-
src/resources/filters/crossref/theorems.lua | 52 ++---
.../filters/customnodes/floatreftarget.lua | 37 +---
src/resources/filters/customnodes/proof.lua | 177 ++++++++++++++++++
.../filters/layout/columns-preprocess.lua | 12 +-
src/resources/filters/main.lua | 2 +
src/resources/filters/mainstateinit.lua | 25 ++-
.../filters/normalize/astpipeline.lua | 3 +-
src/resources/filters/normalize/flags.lua | 2 +-
src/resources/filters/quarto-post/latex.lua | 4 -
.../quarto-pre/parseblockreftargets.lua | 73 ++++++++
.../filters/quarto-pre/parsefiguredivs.lua | 32 +---
src/resources/pandoc/datadir/_format.lua | 2 +-
.../website/templates/sidebaritem.ejs | 12 +-
version.txt | 2 +-
20 files changed, 341 insertions(+), 164 deletions(-)
create mode 100644 src/resources/filters/customnodes/proof.lua
create mode 100644 src/resources/filters/quarto-pre/parseblockreftargets.lua
diff --git a/news/changelog-1.4.md b/news/changelog-1.4.md
index bea3587246..409e17bdb5 100644
--- a/news/changelog-1.4.md
+++ b/news/changelog-1.4.md
@@ -91,7 +91,6 @@
- ([#5969](https://github.com/quarto-dev/quarto-cli/issues/5969)): Correctly detect a required rerun for biblatex when using backref link options.
- ([#5690](https://github.com/quarto-dev/quarto-cli/issues/5690)): Improve validation of `pdf-engine`
- ([#6077](https://github.com/quarto-dev/quarto-cli/issues/6077)): Make sure proof environments are tight around contents.
-- ([#6298](https://github.com/quarto-dev/quarto-cli/issues/6298)): Handle multiple margin and caption specifiers on a single image.
- ([#6907](https://github.com/quarto-dev/quarto-cli/issues/6907)): Fix issue with footnote mark line processor not triggering.
- ([#6990](https://github.com/quarto-dev/quarto-cli/issues/6990)): Fix an issue where underscore in `filename` code cell attribute were not escaped.
- ([#7175](https://github.com/quarto-dev/quarto-cli/issues/7175)): Fix an issue with code annotations when more than one digit is used for annotation number.
diff --git a/src/project/project-config.ts b/src/project/project-config.ts
index a80940b1d7..02f0f82675 100644
--- a/src/project/project-config.ts
+++ b/src/project/project-config.ts
@@ -1,8 +1,9 @@
/*
- * project-config.ts
- *
- * Copyright (C) 2020-2022 Posit Software, PBC
- */
+* project-config.ts
+*
+* Copyright (C) 2020-2022 Posit Software, PBC
+*
+*/
import { join } from "path/mod.ts";
@@ -16,34 +17,28 @@ import { SidebarItem } from "./types.ts";
export type SidebarContext = {
counter: number;
- itemCounter: number;
};
export const sidebarContext = (): SidebarContext => {
- return { counter: 0, itemCounter: 0 };
+ return { counter: 0 };
};
export function normalizeSidebarItem(
projectDir: string,
item: SidebarItem,
- context: SidebarContext,
+ context: { counter: number },
): SidebarItem {
// clone so we can mutate
item = ld.cloneDeep(item);
- if (typeof item === "string") {
- context.itemCounter = context.itemCounter + 1;
- const id = `${kQuartoSidebarItemPrefix}${context.itemCounter}`;
-
+ if (typeof (item) === "string") {
if (safeExistsSync(join(projectDir, item))) {
item = {
href: item,
- id,
};
} else {
item = {
text: item,
- id,
};
}
} else {
@@ -72,11 +67,6 @@ export function normalizeSidebarItem(
// If this is a section, we should insist that it have 'contents'
// even if they are empty.
item.contents = item.contents || [];
- } else {
- context.itemCounter = context.itemCounter + 1;
- item.id = item.id === undefined
- ? `${kQuartoSidebarItemPrefix}${context.itemCounter}`
- : item.id;
}
// handle subitems
@@ -95,7 +85,6 @@ export function normalizeSidebarItem(
}
const kQuartoSidebarPrefix = "quarto-sidebar-section-";
-const kQuartoSidebarItemPrefix = "quarto-sidebar-item-";
export function resolveHrefAttribute(
item: { href?: string; file?: string; url?: string },
diff --git a/src/project/types/website/website-navigation-md.ts b/src/project/types/website/website-navigation-md.ts
index 8b5f81eb6d..4985f29d63 100644
--- a/src/project/types/website/website-navigation-md.ts
+++ b/src/project/types/website/website-navigation-md.ts
@@ -243,7 +243,7 @@ const sidebarContentsHandler = (context: NavigationPipelineContext) => {
if (item.sectionId) {
markdown[`${kSidebarIdPrefix}${item.sectionId}`] = item.text;
} else {
- markdown[`${kSidebarIdPrefix}${item.id || ""}${item.href}`] =
+ markdown[`${kSidebarIdPrefix}${item.href}${item.text}`] =
item.text;
}
}
@@ -258,11 +258,11 @@ const sidebarContentsHandler = (context: NavigationPipelineContext) => {
);
for (let i = 0; i < sidebarItemEls.length; i++) {
const sidebarEl = sidebarItemEls[i] as Element;
- const link = sidebarEl.querySelector(".menu-text");
const href = sidebarEl.getAttribute("href");
+ const link = sidebarEl.querySelector(".menu-text");
if (link) {
const sidebarText =
- rendered[`${kSidebarIdPrefix}${sidebarEl.id}${href}`];
+ rendered[`${kSidebarIdPrefix}${href}${link.innerText}`];
if (sidebarText) {
link.innerHTML = sidebarText.innerHTML;
}
diff --git a/src/project/types/website/website-navigation.ts b/src/project/types/website/website-navigation.ts
index 163fb2de8a..241ed3cbfe 100644
--- a/src/project/types/website/website-navigation.ts
+++ b/src/project/types/website/website-navigation.ts
@@ -75,7 +75,6 @@ import {
import {
normalizeSidebarItem,
resolveHrefAttribute,
- SidebarContext,
sidebarContext,
} from "../../project-config.ts";
import { projectType } from "../project-types.ts";
@@ -1058,10 +1057,7 @@ async function resolveSidebarItems(
}
}
-async function resolveSidebarItem(
- project: ProjectContext,
- item: SidebarItem,
-) {
+async function resolveSidebarItem(project: ProjectContext, item: SidebarItem) {
if (item.href) {
item = await resolveItem(
project,
diff --git a/src/resources/filters/common/theorems.lua b/src/resources/filters/common/theorems.lua
index 49ff6d173d..a88eb355a5 100644
--- a/src/resources/filters/common/theorems.lua
+++ b/src/resources/filters/common/theorems.lua
@@ -1,27 +1,2 @@
-- theorems.lua
-- Copyright (C) 2020-2022 Posit Software, PBC
-
-proofTypes = {
- proof = {
- env = 'proof',
- title = 'Proof'
- },
- remark = {
- env = 'remark',
- title = 'Remark'
- },
- solution = {
- env = 'solution',
- title = 'Solution'
- }
-}
-
-function proofType(el)
- local type = el.attr.classes:find_if(function(clz) return proofTypes[clz] ~= nil end)
- if type ~= nil then
- return proofTypes[type]
- else
- return nil
- end
-
-end
\ No newline at end of file
diff --git a/src/resources/filters/crossref/crossref.lua b/src/resources/filters/crossref/crossref.lua
index 1ea56d0acf..e97d3cdcb7 100644
--- a/src/resources/filters/crossref/crossref.lua
+++ b/src/resources/filters/crossref/crossref.lua
@@ -97,6 +97,7 @@ import("../quarto-pre/panel-input.lua")
import("../quarto-pre/panel-layout.lua")
import("../quarto-pre/panel-sidebar.lua")
import("../quarto-pre/parsefiguredivs.lua")
+import("../quarto-pre/parseblockreftargets.lua")
import("../quarto-pre/project-paths.lua")
import("../quarto-pre/resourcefiles.lua")
import("../quarto-pre/results.lua")
@@ -117,6 +118,7 @@ import("../customnodes/decoratedcodeblock.lua")
import("../customnodes/callout.lua")
import("../customnodes/panel-tabset.lua")
import("../customnodes/floatreftarget.lua")
+import("../customnodes/proof.lua")
import("../customnodes/theorem.lua")
import("../customnodes/panellayout.lua")
@@ -176,7 +178,8 @@ local quarto_normalize_filters = {
name = "normalize-combine-2",
filter = combineFilters({
parse_md_in_html_rawblocks(),
- parse_reftargets(),
+ parse_floatreftargets(),
+ parse_blockreftargets(),
}),
},
}
diff --git a/src/resources/filters/crossref/theorems.lua b/src/resources/filters/crossref/theorems.lua
index 7899ed0ea8..a006ad0905 100644
--- a/src/resources/filters/crossref/theorems.lua
+++ b/src/resources/filters/crossref/theorems.lua
@@ -3,11 +3,10 @@
-- preprocess theorem to ensure that embedded headings are unnumered
function crossref_preprocess_theorems()
- local types = theorem_types
return {
Div = function(el)
local type = refType(el.attr.identifier)
- if types[type] ~= nil or proofType(el) ~= nil then
+ if theorem_types[type] ~= nil or proof_type(el) ~= nil then
return _quarto.ast.walk(el, {
Header = function(el)
el.classes:insert("unnumbered")
@@ -15,15 +14,11 @@ function crossref_preprocess_theorems()
end
})
end
-
end
}
end
function crossref_theorems()
-
- local types = theorem_types
-
return {
Theorem = function(thm)
local label = thm.identifier
@@ -32,19 +27,29 @@ function crossref_theorems()
thm.order = add_crossref(label, type, title)
return thm
end,
+ Proof = function(proof)
+ local label = proof.identifier
+ if label == "" then
+ return nil -- it's an unnumbered proof
+ end
+ local type = refType(label)
+ local title = quarto.utils.as_blocks(proof.name)
+ proof.order = add_crossref(label, type, title)
+ return proof
+ end,
Div = function(el)
local type = refType(el.attr.identifier)
- local theoremType = types[type]
+ local theoremType = theorem_types[type]
if theoremType then
internal_error()
else
-- see if this is a proof, remark, or solution
- local proof = proofType(el)
+ local proof = proof_type(el)
if proof ~= nil then
-- ensure requisite latex is injected
- crossref.usingTheorems = true
+ crossref.using_theorems = true
if proof.env ~= "proof" then
el.attr.classes:insert("proof")
@@ -135,7 +140,7 @@ function jatsTheorem(el, label, title)
--
--
- if title then
+ if #title > 0 then
tprepend(el.content, {
pandoc.RawBlock("jats", ""),
pandoc.Plain(title),
@@ -179,19 +184,17 @@ end
function theoremLatexIncludes()
-- determine which theorem types we are using
- local types = theorem_types
- local refs = tkeys(crossref.index.entries)
- local usingTheorems = crossref.usingTheorems
+ local using_theorems = crossref.using_theorems
for k,v in pairs(crossref.index.entries) do
local type = refType(k)
- if types[type] then
- usingTheorems = true
- types[type].active = true
+ if theorem_types[type] then
+ using_theorems = true
+ theorem_types[type].active = true
end
end
-- return requisite latex if we are using theorems
- if usingTheorems then
+ if using_theorems then
local secType
if crossrefOption("chapters", false) then
secType = "chapter"
@@ -199,19 +202,22 @@ function theoremLatexIncludes()
secType = "section"
end
local theoremIncludes = "\\usepackage{amsthm}\n"
- for _, type in ipairs(tkeys(types)) do
- if types[type].active then
+ for _, type in ipairs(tkeys(theorem_types)) do
+ if theorem_types[type].active then
theoremIncludes = theoremIncludes ..
- "\\theoremstyle{" .. types[type].style .. "}\n" ..
- "\\newtheorem{" .. types[type].env .. "}{" ..
- titleString(type, types[type].title) .. "}[" .. secType .. "]\n"
+ "\\theoremstyle{" .. theorem_types[type].style .. "}\n" ..
+ "\\newtheorem{" .. theorem_types[type].env .. "}{" ..
+ titleString(type, theorem_types[type].title) .. "}[" .. secType .. "]\n"
end
end
theoremIncludes = theoremIncludes ..
"\\theoremstyle{remark}\n" ..
"\\AtBeginDocument{\\renewcommand*{\\proofname}{" .. envTitle("proof", "Proof") .. "}}\n" ..
"\\newtheorem*{remark}{" .. envTitle("remark", "Remark") .. "}\n" ..
- "\\newtheorem*{solution}{" .. envTitle("solution", "Solution") .. "}\n"
+ "\\newtheorem*{solution}{" .. envTitle("solution", "Solution") .. "}\n" ..
+ "\\newtheorem{refremark}{" .. envTitle("remark", "Remark") .. "}[" .. secType .. "]\n" ..
+ "\\newtheorem{refsolution}{" .. envTitle("solution", "Solution") .. "}[" .. secType .. "]\n"
+
return theoremIncludes
else
return nil
diff --git a/src/resources/filters/customnodes/floatreftarget.lua b/src/resources/filters/customnodes/floatreftarget.lua
index 25f11deadd..483e35886a 100644
--- a/src/resources/filters/customnodes/floatreftarget.lua
+++ b/src/resources/filters/customnodes/floatreftarget.lua
@@ -363,7 +363,7 @@ end, function(float)
-- do the longtable fixups below
float.content = _quarto.ast.walk(quarto.utils.as_blocks(float.content), {
Table = function(tbl)
- return pandoc.RawBlock("latex-merge", pandoc.write(pandoc.Pandoc({tbl}), "latex"))
+ return pandoc.RawBlock("latex", pandoc.write(pandoc.Pandoc({tbl}), "latex"))
end
})
@@ -371,33 +371,12 @@ end, function(float)
local raw
-- have to call as_blocks() again here because assigning to float.content
-- goes through our AST metaclasses which coalesce a singleton list to a single AST element
- float.content = _quarto.ast.walk(quarto.utils.as_blocks(float.content), {
- -- coalesce rawblocks ahead of table fixups
- Blocks = function(blocks)
- local result = pandoc.Blocks({})
- local prev
- for _,block in ipairs(blocks) do
- if prev == nil then
- prev = block
- elseif prev.t == "RawBlock" and block.t == "RawBlock" and prev.format == block.format then
- prev.text = prev.text .. "\n" .. block.text
- else
- result:insert(prev)
- prev = block
- end
- end
- if prev ~= nil then
- result:insert(prev)
- end
- return result
- end
- })
_quarto.ast.walk(quarto.utils.as_blocks(float.content), {
RawBlock = function(el)
if _quarto.format.isRawLatex(el) and el.text:match(_quarto.patterns.latexLongtablePattern) then
raw = el
end
- end,
+ end
})
-- special case for singleton longtable floats
if raw then
@@ -434,14 +413,14 @@ end, function(float)
local result = pandoc.Blocks({latex_caption, pandoc.RawInline("latex", "\\tabularnewline")})
-- if cap_loc is top, insert content on bottom
if cap_loc == "top" then
- result:insert(pandoc.RawBlock("latex-merge", content))
+ result:insert(pandoc.RawBlock("latex", content))
else
- result:insert(1, pandoc.RawBlock("latex-merge", content))
+ result:insert(1, pandoc.RawBlock("latex", content))
end
- result:insert(1, pandoc.RawBlock("latex-merge", start))
- result:insert(1, pandoc.RawBlock("latex-merge", longtable_preamble))
- result:insert(pandoc.RawBlock("latex-merge", "\\end{longtable}"))
- result:insert(pandoc.RawBlock("latex-merge", longtable_postamble))
+ result:insert(1, pandoc.RawBlock("latex", start))
+ result:insert(1, pandoc.RawBlock("latex", longtable_preamble))
+ result:insert(pandoc.RawBlock("latex", "\\end{longtable}"))
+ result:insert(pandoc.RawBlock("latex", longtable_postamble))
return result
end
end
diff --git a/src/resources/filters/customnodes/proof.lua b/src/resources/filters/customnodes/proof.lua
new file mode 100644
index 0000000000..fa7d27be6a
--- /dev/null
+++ b/src/resources/filters/customnodes/proof.lua
@@ -0,0 +1,177 @@
+-- proof.lua
+-- custom AST node for proofs, remarks, solutions, etc.
+
+-- Copyright (C) 2023 Posit Software, PBC
+
+-- available proof types
+
+proof_types = {
+ proof = {
+ env = 'proof',
+ title = 'Proof'
+ },
+ remark = {
+ env = 'remark',
+ title = 'Remark'
+ },
+ solution = {
+ env = 'solution',
+ title = 'Solution'
+ }
+}
+
+function proof_type(el)
+ local type = el.attr.classes:find_if(function(clz) return proof_types[clz] ~= nil end)
+ if type ~= nil then
+ return proof_types[type]
+ else
+ return nil
+ end
+end
+
+_quarto.ast.add_handler({
+ -- empty table so this handler is only called programmatically
+ class_name = {},
+
+ -- the name of the ast node, used as a key in extended ast filter tables
+ ast_name = "Proof",
+
+ -- generic names this custom AST node responds to
+ -- this is still unimplemented
+ interfaces = {"Crossref"},
+
+ -- Proofs are always blocks
+ kind = "Block",
+
+ parse = function(div)
+ -- luacov: disable
+ internal_error()
+ -- luacov: enable
+ end,
+
+ slots = { "div", "name" },
+
+ constructor = function(tbl)
+ return {
+ name = tbl.name,
+ div = tbl.div,
+ identifier = tbl.identifier,
+ type = tbl.type -- proofs can be unnumbered and lack an identifier; we need to know the type explicitly
+ }
+ end
+})
+
+function is_proof_div(div)
+ local ref = refType(div.identifier)
+ if ref ~= nil then
+ local tbl = crossref.categories.by_ref_type[ref]
+ if tbl then
+ local key = tbl.name:lower()
+ return proof_types[key]
+ end
+ end
+ return is_regular_node(div, "Div") and proof_type(div) ~= nil
+end
+
+_quarto.ast.add_renderer("Proof", function()
+ return true
+end, function(proof_tbl)
+ local el = proof_tbl.div
+ -- see if this is a proof, remark, or solution
+ local proof = proof_types[proof_tbl.type:lower()]
+ if proof == nil then
+ internal_error()
+ return pandoc.Blocks({})
+ end
+
+ -- ensure requisite latex is injected
+ crossref.using_theorems = true
+
+ if proof.env ~= "proof" then
+ el.attr.classes:insert("proof")
+ end
+
+ local name = quarto.utils.as_inlines(proof_tbl.name or pandoc.Inlines({}))
+
+ -- output
+ if _quarto.format.isLatexOutput() then
+ local preamble = pandoc.List()
+ local env = proof.env
+
+ local has_ref = refType(proof_tbl.identifier) ~= nil
+ if has_ref then
+ env = "ref" .. env
+ end
+
+ preamble:insert(pandoc.RawInline("latex", "\\begin{" .. env .. "}"))
+ if #name ~= 0 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
+ if has_ref then
+ el.content:insert(pandoc.RawInline("latex",
+ "\\label{" .. proof_tbl.identifier .. "}")
+ )
+ end
+ local end_env = "\\end{" .. 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
+ el.classes:insert(proof.title:lower())
+ local span_title = pandoc.Emph(pandoc.Str(envTitle(proof.env, proof.title)))
+ local entry = crossref.index.entries[proof_tbl.identifier]
+ local type = refType(proof_tbl.identifier)
+ if type then
+ el.identifier = proof_tbl.identifier
+ end
+ if entry then
+ span_title.content:insert(pandoc.Space())
+ span_title.content:extend(refNumberOption(type, entry))
+ end
+
+ local span = pandoc.Span({ span_title }, pandoc.Attr("", { "proof-title" }))
+ if #name > 0 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
+ print(el)
+ end
+
+ return el
+
+end)
\ No newline at end of file
diff --git a/src/resources/filters/layout/columns-preprocess.lua b/src/resources/filters/layout/columns-preprocess.lua
index d4bd98f314..d68df8e366 100644
--- a/src/resources/filters/layout/columns-preprocess.lua
+++ b/src/resources/filters/layout/columns-preprocess.lua
@@ -9,9 +9,7 @@ function columns_preprocess()
end
local location = cap_location(float)
if location == 'margin' then
- if not float.classes:includes("column-margin") then
- float.classes:insert('margin-caption')
- end
+ float.classes:insert('margin-caption')
noteHasColumns()
return float
end
@@ -34,13 +32,7 @@ function columns_preprocess()
resolveElementForScopedColumns(figure, 'fig')
end
return el
- end,
-
- Image = function(img)
- if img.classes:find_if(function(class) return class:match("^column%-") end) then
- noteHasColumns()
- end
- end
+ end
}
end
diff --git a/src/resources/filters/main.lua b/src/resources/filters/main.lua
index dd173c01e0..4d90c54856 100644
--- a/src/resources/filters/main.lua
+++ b/src/resources/filters/main.lua
@@ -145,6 +145,7 @@ import("./quarto-pre/panel-input.lua")
import("./quarto-pre/panel-layout.lua")
import("./quarto-pre/panel-sidebar.lua")
import("./quarto-pre/parsefiguredivs.lua")
+import("./quarto-pre/parseblockreftargets.lua")
import("./quarto-pre/project-paths.lua")
import("./quarto-pre/resourcefiles.lua")
import("./quarto-pre/results.lua")
@@ -174,6 +175,7 @@ import("./customnodes/callout.lua")
import("./customnodes/panel-tabset.lua")
import("./customnodes/floatreftarget.lua")
import("./customnodes/theorem.lua")
+import("./customnodes/proof.lua")
import("./layout/confluence.lua")
import("./layout/ipynb.lua")
diff --git a/src/resources/filters/mainstateinit.lua b/src/resources/filters/mainstateinit.lua
index f3f7bfccb4..079aa972f8 100644
--- a/src/resources/filters/mainstateinit.lua
+++ b/src/resources/filters/mainstateinit.lua
@@ -19,7 +19,7 @@ quarto_global_state = {
}
crossref = {
- usingTheorems = false,
+ using_theorems = false,
startAppendix = nil,
-- initialize autolabels table
@@ -87,10 +87,29 @@ crossref = {
prefix = "Important",
ref_type = "imp", -- this will look weird but we decided to do it for consistency with the original callout types
},
+
+ -- proof envs
+ {
+ kind = "Block",
+ name = "Proof",
+ prefix = "Proof",
+ ref_type = "prf",
+ },
+ {
+ kind = "Block",
+ name = "Remark",
+ prefix = "Remark",
+ ref_type = "rem",
+ },
+ {
+ kind = "Block",
+ name = "Solution",
+ prefix = "Solution",
+ ref_type = "sol",
+ },
}
- -- eventually we'll have other block kinds here
- -- with theorem and proof envs
+ -- eventually we'll have other block kinds here, specifically theorem envs
-- eventually we'll have inline kinds here
-- with equation refs
diff --git a/src/resources/filters/normalize/astpipeline.lua b/src/resources/filters/normalize/astpipeline.lua
index 6a97cb9501..80ba526a75 100644
--- a/src/resources/filters/normalize/astpipeline.lua
+++ b/src/resources/filters/normalize/astpipeline.lua
@@ -21,7 +21,8 @@ function quarto_ast_pipeline()
name = "normalize-combine-2",
filter = combineFilters({
parse_md_in_html_rawblocks(),
- parse_reftargets(),
+ parse_floatreftargets(),
+ parse_blockreftargets()
}),
},
}
diff --git a/src/resources/filters/normalize/flags.lua b/src/resources/filters/normalize/flags.lua
index f080de6d72..5f3bddd2a3 100644
--- a/src/resources/filters/normalize/flags.lua
+++ b/src/resources/filters/normalize/flags.lua
@@ -69,7 +69,7 @@ function compute_flags()
end,
Div = function(node)
local type = refType(node.attr.identifier)
- if theorem_types[type] ~= nil or proofType(node) ~= nil then
+ if theorem_types[type] ~= nil or proof_type(node) ~= nil then
flags.has_theorem_refs = true
end
diff --git a/src/resources/filters/quarto-post/latex.lua b/src/resources/filters/quarto-post/latex.lua
index 55b65a7e92..42ab1a765c 100644
--- a/src/resources/filters/quarto-post/latex.lua
+++ b/src/resources/filters/quarto-post/latex.lua
@@ -276,10 +276,6 @@ function render_latex()
})
return float, false
end,
- Figure = function(fig)
- -- defer rendering of figure to own pass
- return nil, false
- end,
Image = function(img)
if img.classes:includes("column-margin") then
return handle_column_classes(pandoc.Span(img, img.attr))
diff --git a/src/resources/filters/quarto-pre/parseblockreftargets.lua b/src/resources/filters/quarto-pre/parseblockreftargets.lua
new file mode 100644
index 0000000000..68631e69f5
--- /dev/null
+++ b/src/resources/filters/quarto-pre/parseblockreftargets.lua
@@ -0,0 +1,73 @@
+-- parseblockreftargets.lua
+-- Copyright (C) 2023 Posit Software, PBC
+
+-- parses Proofs, Theorems, Lemmas, etc.
+
+function parse_blockreftargets()
+
+ local function parse_theorem_div(el)
+ if not has_theorem_ref(el) then
+ return
+ end
+ -- capture then remove name
+ local name = markdownToInlines(el.attr.attributes["name"])
+ if not name or #name == 0 then
+ name = resolveHeadingCaption(el)
+ end
+ el.attr.attributes["name"] = nil
+ local identifier = el.attr.identifier
+ -- remove identifier to avoid infinite recursion
+ el.attr.identifier = ""
+ return quarto.Theorem {
+ identifier = identifier,
+ name = name,
+ div = el
+ }, false
+ end
+
+ local function parse_proof_div(el)
+ if not is_proof_div(el) then
+ return
+ end
+
+ local name = string_to_quarto_ast_inlines(el.attributes["name"] or "")
+ if not name or #name == 0 then
+ name = resolveHeadingCaption(el) or pandoc.Inlines({})
+ end
+ el.attributes["name"] = nil
+ local identifier = el.identifier
+ el.identifier = ""
+
+ local ref = refType(identifier)
+ local proof_type
+ if ref ~= nil then
+ proof_type = crossref.categories.by_ref_type[ref].name
+ else
+ proof_type = el.classes:find_if(function(clz) return proof_types[clz] ~= nil end)
+ if proof_type == nil then
+ internal_error()
+ return
+ end
+ proof_type = proof_types[proof_type].title
+ end
+ el.classes = el.classes:filter(function(clz) return proof_types[clz] == nil end)
+ crossref.using_theorems = true
+ local tbl = {
+ identifier = identifier,
+ name = name,
+ div = el,
+ type = proof_type
+ }
+ return quarto.Proof(tbl), false
+ end
+
+ return {
+ Div = function(div)
+ if is_theorem_div(div) then
+ return parse_theorem_div(div)
+ elseif is_proof_div(div) then
+ return parse_proof_div(div)
+ end
+ end
+ }
+end
\ No newline at end of file
diff --git a/src/resources/filters/quarto-pre/parsefiguredivs.lua b/src/resources/filters/quarto-pre/parsefiguredivs.lua
index fe57eee022..34e8a80de6 100644
--- a/src/resources/filters/quarto-pre/parsefiguredivs.lua
+++ b/src/resources/filters/quarto-pre/parsefiguredivs.lua
@@ -126,33 +126,8 @@ local function kable_raw_latex_fixups(content, identifier)
return matches, content
end
-function parse_reftargets()
+function parse_floatreftargets()
- local function parse_theorem_div(div)
- if has_theorem_ref(div) then
- local el = div
- -- capture then remove name
- local name = markdownToInlines(el.attr.attributes["name"])
- if not name or #name == 0 then
- name = resolveHeadingCaption(el)
- end
- el.attr.attributes["name"] = nil
- local identifier = el.attr.identifier
- -- remove identifier to avoid infinite recursion
- el.attr.identifier = ""
- return quarto.Theorem {
- identifier = identifier,
- name = name,
- div = div
- }, false
- end
- -- local types = theorem_types
- -- local type = refType(el.attr.identifier)
- -- local theorem_type = types[type]
- -- if theorem_type then
- -- end
- end
-
local function parse_float_div(div)
process_div_caption_classes(div)
local ref = refType(div.identifier)
@@ -253,9 +228,6 @@ function parse_reftargets()
local layout_classes = attr.classes:filter(
function(c) return c:match("^column-") end
)
- div.classes = div.classes:filter(
- function(c) return not c:match("^column-") end
- )
if #layout_classes then
attr.classes = attr.classes:filter(
function(c) return not layout_classes:includes(c) end)
@@ -423,8 +395,6 @@ function parse_reftargets()
return parse_float_div(div)
elseif isTableDiv(div) then
return parse_float_div(div)
- elseif is_theorem_div(div) then
- return parse_theorem_div(div)
end
if div.classes:includes("cell") then
diff --git a/src/resources/pandoc/datadir/_format.lua b/src/resources/pandoc/datadir/_format.lua
index 5f61bc624c..a709357b62 100644
--- a/src/resources/pandoc/datadir/_format.lua
+++ b/src/resources/pandoc/datadir/_format.lua
@@ -21,7 +21,7 @@ local function isRawHtml(rawEl)
end
local function isRawLatex(rawEl)
- return isRaw(rawEl) and (rawEl.format == "tex" or rawEl.format == "latex" or rawEl.format == "latex-merge" or rawEl.format == "tex-merge")
+ return isRaw(rawEl) and (rawEl.format == "tex" or rawEl.format == "latex")
end
-- check for latex output
diff --git a/src/resources/projects/website/templates/sidebaritem.ejs b/src/resources/projects/website/templates/sidebaritem.ejs
index 7b68805cba..8796ad6689 100644
--- a/src/resources/projects/website/templates/sidebaritem.ejs
+++ b/src/resources/projects/website/templates/sidebaritem.ejs
@@ -1,7 +1,7 @@
<% if (item.href && item.text && !item.contents) { %>
<% } else if (item.contents && item.text) { %>
@@ -17,11 +17,11 @@
<% if (item.contents.length > 0) { %>
@@ -31,8 +31,8 @@
<% }) %>
<% } else { %>
-
- <% } %>
+
+ <% } %>
<% } else if (item.text && item.text.match(/^\-+$/)) { %>
diff --git a/version.txt b/version.txt
index a0d80da657..fb7a165737 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-1.4.529
+1.4.528