How can I modify the reference format of equations?

To elaborate on @quachpas’s answer, here is how rules are applied for a particular element according to my understanding:

  1. 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.

  2. 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].

  3. 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
    image

    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.

image

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.

image

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.

image

In this case the brackets are added in a context where text(red) is active.

4 Likes