I want to make the reference of equations like this:
It seems that I can only remove the “Equation” in reference by:
#set math.equation(numbering: "(R1)", supplement: none)
How can I add the parenthesis?
I want to make the reference of equations like this:
#set math.equation(numbering: "(R1)", supplement: none)
How can I add the parenthesis?
Here it’s the reference you want to customize, so you need a show rule on ref
. I think there’s an example in the documentation that does what you want:
#set heading(numbering: "1.")
#set math.equation(numbering: "(1)")
#show ref: it => {
let eq = math.equation
let el = it.element
if el != none and el.func() == eq {
// Override equation references.
numbering(
el.numbering,
..counter(eq).at(el.location())
)
} else {
// Other references as usual.
it
}
}
= Beginnings <beginning>
In @beginning we prove @pythagoras.
$ a^2 + b^2 = c^2 $ <pythagoras>
Thanks! I will read the documentation later.
Sorry for the obvious question (I am new to Typst), but can one package this show
rule in a composable way, so that the user can just load this as an option?
My concern is that, since this is a closure, another customization of ref
will just override it.
Hello, this is not obvious actually, it’s rather precise!
I recommend going through the tutorial about templates
Sorry, I guess my question was not clear, it is not about the template mechanism but how show
rules compose (if at all).
Suppose that in addition to the solution suggested above, someone wants to define a
#show ref: it => {
...
}
for something else than equations, either in the main file or in a template.
Then I am assuming that one of the rules would overwrite the other. Is that correct? Is there a workaround/solution for this?
I did read too fast, it would indeed be overwritten. Below, a show ref rule to display Bar does not trigger, because it is overwritten by the first one.
#let template(doc) = {
show ref: it => [Foo]
doc
}
#show ref: it => [Bar]
#show: template
#figure([Foo]) <foo>
@foo
#figure([Bar]) <bar>
@bar
I think it is best if you write it like the following one. Basically, as long as you target your element and return the ref for other references, you can compose show ref rules.
#let template(doc) = {
show ref: it => {
let el = it.element
if el != none and el.func() == figure and el.kind == "foo" {
[Foo]
} else {
it
}
}
doc
}
#show ref: it => [Bar]
#show: template
#figure([Foo], kind: "foo", supplement: "") <foo>
@foo
#figure([Bar]) <bar>
@bar
To elaborate on @quachpas’s answer, here is how rules are applied for a particular element according to my understanding:
All applicable show-set rules are gathered, with later rules overwriting previous ones so
#show ref: set text(red, weight: "bold")
#show ref: set text(blue)
will show refs in blue and bold.
The element is materialized in accordance with these show-set rules. For example after
#show ref: set ref(supplement: [X])
all ref elements with unspecified supplement will be materialized with supplement [X]
.
Normal show rules (i.e. functions, not show-set) are applied starting with the most local one. The rule functions are called with the materialized element as argument. Each rule is applied recursively to its own output, until the output contains nothing new that matches the show rule. For example
#set math.equation(numbering: "(1)")
#set ref(supplement: [0])
#show ref: it => {
let i = int(it.supplement.text)
if i < 3 {
let new = ref(it.target, supplement: [#(i + 1)])
return [{it: #it, new: #new}]
}
[{final: #it}]
}
$ x = y $ <eq>
See @eq.
produces
Indeed the first time the show rule is applied, it returns the content {it: #it, new: #new}
. The rule is then applied again on the new ref, but not on #it
as that has already been processed. This is repeated until the new ref has supplement [3]
: then the show rule simply returns {final: #it}
. This output contains nothing new matching the show rule, so Typst moves on to the next (more outer) show rule.
So in principle show rules compose in the sense that outer rules are applied to the output of inner rules.
Where it breaks is if a rule on Element doesn’t include a corresponding Element in its output: in this case, an outer rule on Element will not be applied since the thing that would have matched the rule has been removed (replaced) by the inner rule.
In the present case, when the ref is to a figure the show rule returns the ref unchanged, so there’s no problem: the ref is still there to be found by other show rules.
It also works fine if you have a show-set rule for refs:
#set math.equation(numbering: "(1)")
#show ref: set text(red)
#show ref: it => {
let el = it.element
if el != none and el.func() == math.equation {
numbering(el.numbering, ..counter(math.equation).at(el.location()))
} else {
it
}
}
$ x = y $ <eq>
See @eq.
The show ref: set text(red)
composes well with the show rule to add brackets.
What doesn’t work is if we have another regular show rule before the rule that adds brackets:
#set math.equation(numbering: "(1)")
// This won't work here...
#show ref: it => {
set text(red)
it
}
#show ref: it => {
let el = it.element
if el != none and el.func() == math.equation {
numbering(el.numbering, ..counter(math.equation).at(el.location()))
} else {
it
}
}
// but it would work here
$ x = y $ <eq>
See @eq.
To avoid this problem, we’d have to make a show rule for brackets that still returns a ref:
#set math.equation(numbering: "(1)", supplement: none)
#show ref: it => {
set text(red)
it
}
#show ref: it => {
let el = it.element
if el != none and el.func() == math.equation {
link(el.location(), [(#it)])
} else {
it
}
}
$ x = y $ <eq>
See @eq.
This works except that the brackets are added around the ref. They’re not part of the ref, so the show ref: set text(red)
doesn’t apply to them. But it does if we switch the order of rules:
#set math.equation(numbering: "(1)", supplement: none)
#show ref: it => {
let el = it.element
if el != none and el.func() == math.equation {
link(el.location(), [(#it)])
} else {
it
}
}
#show ref: it => {
set text(red)
it
}
$ x = y $ <eq>
See @eq.
In this case the brackets are added in a context where text(red)
is active.