Use now, define later!
Basic usage
This package exposes a single function, latedef-setup
.
#let (undef, def) = latedef-setup(simple: true)
My #undef is #undef.
#def("dog")
#def("cool")
Note that the definition doesn’t actually have to come after the usage, but if you want to define something beforehand, you’re better off using a variable instead.
#let (undef, def) = latedef-setup(simple: true)
// Instead of
#def("A")
The first letter is #undef.
// you should use
#let A = "A"
The first letter is #A.
The simple
parameter
When simple: false
(which is the default), undef
becomes a function you have to call. It takes an optional positional or named parameter id
of type str
, which can be used to define things out of order.
#let (undef, def) = latedef-setup() // or `latedef-setup(simple: false)`
// Note that you can still call it without an id, which works just like when `simple: true`.
My letters are #undef("1"), #undef(id: "2"), and #undef().
// `def` now takes one positional and either another positional or a named parameter.
#def("C")
#def(id: "2", "B")
#def("1", "A")
The footnote
parameter
This is a convenience feature that automatically wraps undef
in footnote
, either directly (when simple: true
) or as a function (when simple: false
).
This corresponds to LaTeX’s \footnotemark
and \footnotetext
, hence the different names in the example.
#let (fmark, ftext) = latedef-setup(simple: true, footnote: true)
Do#fmark you#fmark believe#fmark in God?#fmark
#let wdym = "What do you mean"
#ftext[#wdym "Do"?]
#ftext[#wdym "you"?]
#ftext[#wdym "believe"?]
#ftext[And w#wdym.slice(1) "God"?]
The stand-in
parameter
This is a function that takes a single positional parameter (id
) of type none | str
and produces a stand-in value that gets shown when a late-defined value is missing a corresponding definition.
#let (undef, def) = latedef-setup()
// This is the default stand-in
#undef()
#undef("with an id")
// Custom stand-in
#let (undef, def) = latedef-setup(stand-in: id => emph[No #id!])
#undef()
#undef("id")
Since stand-in
is a function, which is only called when a definition is actually missing, you can even set it to panic to enforce that all late-defined values have a definiton.
#let (undef, def) = latedef-setup(stand-in: id => panic("Missing definition for value with id " + repr(id)))
#undef()
#undef("id")
The output will look something like
error: panicked with: "Missing definition for value with id none"
┌─ example.typ:1:50
│
│ #let (undef, def) = latedef-setup(stand-in: id => panic("Missing definition for value with id " + repr(id)))
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: panicked with: "Missing definition for value with id \"id\""
┌─ example.typ:1:50
│
│ #let (undef, def) = latedef-setup(stand-in: id => panic("Missing definition for value with id " + repr(id)))
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
And there is no error when everything has a definition:
#let (undef, def) = latedef-setup(stand-in: id => panic("Missing definition for value with id " + repr(id)))
#undef() is #undef("id").
#def("This")
#def("id", "fine")
The group
parameter
Sometimes you may want to use multiple instances of latedef
in parallel. This is done using the group
parameter, which can be none
(the default) or any str
.
Note that using footnote: true
sets the default group to "footnote"
instead.
// Use a group for the figure stuff...
#let (caption-undef, caption) = latedef-setup(simple: true, group: "figure")
#let figure = std.figure.with(caption: caption-undef)
// ...so you can still use the regular mechanism in parallel.
#let (undef, def) = latedef-setup(simple: true)
#figure(raw(block: true, lorem(5)))
#caption[The #undef _lorem ipsum_.]
#def("classic")