How to start the heading-numbering from 0?

Normally the first heading has the number 1 (which makes sense).
How can I have the first heading to be number 0 and the second number 1 and so on?

A simple #counter(heading).update(0) before the first heading does not work, because the counter already starts at 0, and #counter(heading).update(-1) gives a syntax error, because counters must be natural numbers.

1 Like

The command #counter(heading).update(0) doesn’t work because its value is already 0. You can verify this by running #context counter(heading).get() and checking the result.

As an alternative, you could define a numbering function that subtracts 1 from the input arguments before returning the results. For example:

#set heading(numbering: (..x) => numbering("1.", ..x.pos().map(n => n - 1)))

= hello
= test

This would output:

0. hello
1. test
2 Likes

Thank you :) This works, but only for top level headings.
If I use this and include lower level headings this outputs

0. hello
0.0. One sublevel
0.1. next
0.1.0. two sublevels 
1. ... 

But I want my top level headings to start with 0 but the levels beneath it with the usual 1.

So using your idea of subtracting one, but only for the first level and not the others, I tried instead of using the map function to just remove the first entry and add it again as follows.

#set heading(numbering: (..x) => {
   let numbers = x.pos()
   let n1 = numbers.at(0)
   numbers.remove(0)
   numbers.insert(0, int(n1 - 1))
   numbering("1.a", ..numbers)
}
)

This gives the error on the numbering line stating, can not join integer with a string. So somehow this operation destroys the possibility to use the normal numbering command. What am I doing wrong?

The problem is that the result of a Typst function is created by “joining” all expressions, and apart from the final numbering() call, numbers.remove(0) also returns a value!

There are a couple of ways around this:

  • you can opt out of this behavior by using return numbering(...)
  • you can prevent remove() from leaking by using let _ = ...
  • since remove() returns the element, you can use let n1 = numbers.remove(0)
  • you could also use numbers.at(0) -= 1
  • finally, you could destructure your numbers differently:
    #set heading(numbering: (n1, ..x) => numbering("1.a", n1 - 1, ..x))
    
3 Likes

Ah, that makes a lot of sense! Everyday I am learning something. Thank you! :)

2 Likes