I was trying to minimize an issue in fletcher’s manual and reduced it down to the following (this still depends on CeTZ and fletcher so it’s not properly minimal, but hopefully small enough to discuss the issue):
#import "@preview/cetz:0.3.1": draw, vector
#import "@preview/fletcher:0.5.2" as fletcher: diagram, node
// this is copy-pasted from fletcher
#let pill(node, extrude) = {
let size = node.size.map(i => i + 2*extrude)
// assert(size.any(x => x > 0pt))
draw.rect(
vector.scale(size, -0.5),
vector.scale(size, +0.5),
radius: calc.min(..size)/2,
)
}
#diagram(node((0,0), link(label("pill()"), raw("pill")), shape: pill,
fill: green.lighten(90%), stroke: green))
= pill#label("pill()")
This does not compile, with the following error:
error: array is empty
┌─ @preview/cetz:0.3.1/src/drawable.typ:45:10
help: error occurred in this call of function `path`
┌─ @preview/cetz:0.3.1/src/draw/shapes.typ:1145:8
help: error occurred in this function call
┌─ @preview/cetz:0.3.1/src/process.typ:17:22
...
After some bisecting (because the stack trace is incomplete due to context being involved) I figured out that a rectangle with zero size causes this error inside CeTZ, and that the function that drew the rectangle was the one reproduced above.
I thought an assert()
check could at least bring the mistake to light earlier, so I inserted assert(size.any(x => x > 0pt))
– and that made the document compile!
I have a rough idea what’s happening here: the node’s label from which the node size is computed is link(label("pill()"), raw("pill"))
. The link element probably gets its measurements late (probably because links in general also need to handle things such as inferring the text from the referenced label), thus an “early” measure()
returns (0pt, 0pt)
, making CeTZ fail. By the time the size would be known, the compilation has already failed.
assert()
seems to be handled differently, just trying again and eventually resulting in the node size to be positive, and thus a successful compilation.
My question now is: is this supposed to happen/expected or should Typst’s behavior not be influenced by a successful assert?
I assume there’s something wrong in how fletcher measures and then stores the result for later use, but I’m also pretty sure that this assert is not the ideal fix for that. I’d also be interested in uncovering the specific anti-pattern that is at fault here – but that’s probably my responsibility, further minimizing the example I’ve come up with here.