Universe

This package allows you to make counters depend on the current chapter/section number.

The advantage compared to rich-counter is that it is more efficient and you stick with native counters.

Showcase

In the following example, mycounter inherits the first level from headings (but not deeper levels).

#import "@preview/headcount:0.1.0": *
#import "@preview/great-theorems:0.1.0": *

#show: great-theorems-init

#set heading(numbering: "1.1")

// contruct theorem environment with counter that inherits 2 levels from heading
#let thmcounter = counter("hello")
#let theorem = mathblock(
  blocktitle: [Theorem],
  counter: thmcounter,
  numbering: dependent-numbering("1.1", levels: 2)
)
#show heading: reset-counter(thmcounter, levels: 2)

// set figure counter so that it inherits 1 level from heading
#set figure(numbering: dependent-numbering("1.1"))
#show heading: reset-counter(counter(figure.where(kind: image)))

= First heading

The theorems inherit 2 levels from the headings and the figures inherit 1 level from the headings.

#theorem[Some theorem.]
#theorem[Some theorem.]
#figure([SOME FIGURE], caption: [some figure])
#figure([SOME FIGURE], caption: [some figure])

== Subheading

#theorem[Some theorem.]
#figure([SOME FIGURE], caption: [some figure])
#figure([SOME FIGURE], caption: [some figure])

= Second heading

#theorem[Some theorem.]
#figure([SOME FIGURE], caption: [some figure])
#theorem[Some theorem.]

Usage

To make another counter inherit from the heading counter, you have to do two things.

  1. For the numbering of your counter, you have to use dependent-numbering(...).

    • dependent-numbering(style, level: 1) (needs context)

      Is a replacement for the numbering function, with the difference that it precedes any counter value with level many values of the heading counter.

    #import "@preview/headcount:0.1.0": *
    
    #set heading(numbering: "1.1")
    
    #let mycounter = counter("hello")
    
    = First heading
    
    #context mycounter.step()
    #context mycounter.display(dependent-numbering("1.1"))
    
    = Second heading
    
    #context mycounter.step()
    #context mycounter.display(dependent-numbering("1.1"))
    
    #context mycounter.step()
    #context mycounter.display(dependent-numbering("1.1"))
    

    This displays the desired amount of levels of the heading counter in front of the actual counter. However, as you can see in the code above, our actual counter does not yet reset in each section.

  2. For resetting the counter at the appropriate places, you need to equip heading with the show rule that reset-counter(...) returns.

    • reset-counter(counter, level: 1) (needs context)

      Returns a function that should be used as a show rule for heading. It will reset counter if the level of the heading is less than or equal to level.

    #import "@preview/headcount:0.1.0": *
    
    #set heading(numbering: "1.1")
    #show heading: reset-counter(mycounter, levels: 1)
    
    #let mycounter = counter("hello")
    
    = First heading
    
    #context mycounter.step()
    #context mycounter.display(dependent-numbering("1.1"))
    
    = Second heading
    
    #context mycounter.step()
    #context mycounter.display(dependent-numbering("1.1"))
    
    #context mycounter.step()
    #context mycounter.display(dependent-numbering("1.1"))
    

Note: The level that you pass to dependent-numbering(...) and the level that you pass to reset-counter(...) must be the same.

Limitations

Due to current Typst limitations, there is no way to detect manual updates or steps of the heading counter, like counter(heading).update(...) or counter(heading).step(...). Only occurrences of actual headings can be detected. So make sure that after you call e.g. counter(heading).update(...), you place a heading directly after it, before you use any counters that depend on the heading counter.