Ok, I found some solutions which solve my original question in three different ways. I combined them all into one example so anyone can pick and choose what fits best for them:
- In-Document-Warning (Summary): use a state to collect and typeset a warning summary
- In-Document-Warning (Outline): use invisible headings to record the warnings into the outline
- Metadata: put the warning into a metadata label which can then be queried from the CLI
// file: overfull.typ
// --- page setup ---
#set page(width: 10cm, height: 6cm)
// --- example dataset ---
#let records = (
(firstname: "Alice", lastname: "Anderson", affiliation: "ACME"),
(firstname: "Bob", lastname: "Baker", affiliation: "A Company that Manufactures Everything\ - Sales Department -"),
)
// In-Document-Warning (Summary): create a state
#let overfull_box_on_pages = state("overfull", ())
// --- overfull aware box (vertical limit detection) ---
#let box_vlim(body, width: auto, height: auto, highlight: red, ..box_args) = layout(
parent_size => {
let width = width
if width == auto {
width = parent_size.width
}
let boxed = box(body, width: width, ..box_args)
let size = measure(boxed)
if type(height) == length and size.height.mm() > height.to-absolute().mm() {
boxed = box(body, width: width, height: height, fill: highlight, ..box_args)
// Metadata: this can be queried from the CLI with:
// `typst query overfull.typ "<overfull>" --field value`
[#metadata(here().page())<overfull>]
// In-Document-Warning (Summary): collect page information into state
let pages = overfull_box_on_pages.get()
pages.push(here().page())
overfull_box_on_pages.update(pages)
// In-Document-Warning (Outline): create an invisible heading which shows up in the outline
// https://forum.typst.app/t/how-to-add-an-invisible-heading-to-an-outline/685/2?u=jacob
{
show heading: none
heading(numbering: none)[Overfull Box]
}
}
boxed
})
// interpret dataset fields as markup
#let typeset(src) = {
eval(src, mode: "markup")
}
// construct document page by page
#for i in range(records.len()) {
box_vlim(height: 2em)[
#typeset(records.at(i).firstname)\
#typeset(records.at(i).lastname)
]+"\n"
box_vlim(height: 1em)[
#typeset(records.at(i).affiliation)
]
if i < (records.len() - 1) {
pagebreak()
}
}
// In-Document-Warning (Outline, Summary): show outline and summary
#context {
let pages = overfull_box_on_pages.final()
if pages != () {
pagebreak()
outline(title: "Warnings")
pagebreak()
[= Warnings Summary]
[overfull box on pages: #pages]
}
}