How to handle numbering and linebreaks in nested theorem function?

I have tried this.

#let thorem_counter = counter("thorem")
#let thorem_level = state("thorem_level", 1)
#let thorem(numbering: "1.1", text: ("Thorem", "Lemma"), level: thorem_level, thorem_state: none, ..args) = {
  level.update(v => v + 1)
  for i in args.pos() {
    context [
      #thorem_counter.step(level: level.get() - 1)
      #strong(text.at(level.get() - 2))
      #thorem_counter.display(numbering)
      :#h(0.5em)#i \
    ]
  }
  level.update(v => v - 1)
}
#thorem[#lorem(5)][#lorem(5) \ #thorem[#lorem(5)]][#lorem(5)]
#thorem[#lorem(5)][#lorem(5) \ #thorem[#lorem(5)]][#lorem(5)]


But It have some problem

  1. the numeber is start from 0 [Fixed]
  2. A thorem after a lemma will shou like 2.1 but not 3[Fixed]
  3. if a lemma and a thorem both in a block, the space after them will too long
  • Thanks for your question. Please update your post title to be more descriptive of at least one of the issues you’re having.
  • For #1, I don’t think the step method can share the same context as where the counter is used. Add an inner-level context for the line that you display the thorem_counter, e.g. #context thorem_counter.display(numbering). The last paragraph of this section about context addresses your case explicitly if you want more explanation.
  • Your goals for #2 are not very clear. Can you please try to restate that and give an example?
  • For #3, this is because of the way you coded it, specifically this line: :#h(0.5em)#i \. If i is itself a thorem or contains one, then it will introduce its own line break, and then will be followed by another one.
  • I imagine you meant “Theorem” not “Thorem”, yes?
#let thorem_counter = counter("thorem")
#let thorem_level = state("thorem_level", 1)
#let thorem(numbering: "1.1", text: ("Thorem", "Lemma"), level: thorem_level, thorem_state: none, ..args) = {
  level.update(v => v + 1)
  for i in args.pos() {
    context [
      #thorem_counter.step(level: level.get() - 1)
      #strong(text.at(level.get() - 2))
      #context [#thorem_counter.display(numbering)]
      :#h(0.5em)#i \
    ]
  }
  level.update(v => v - 1)
}

By function: \
#thorem[#lorem(5)][#lorem(5) \ #thorem[#lorem(5)]][#lorem(5)]

I want:

*Thorem* 1 :Lorem ipsum dolor sit amet. \
*Thorem* 2 :Lorem ipsum dolor sit amet. \
*Lemma* 2.1 :Lorem ipsum dolor sit amet. \
*Thorem* 3 :Lorem ipsum dolor sit amet. \

Thorem3 and Lemmma 2.1 are more closer, there are no more linebreak between them.

Don’t care this, just some typing error.

You could use blocks:

#let thorem_counter = counter("thorem")
#let thorem_level = state("thorem_level", 1)
#let thorem(numbering: "1.1", text: ("Thorem", "Lemma"), level: thorem_level, thorem_state: none, ..args) = {
  level.update(v => v + 1)
  for i in args.pos() {
    context block(spacing: 0.65em)[
      #thorem_counter.step(level: level.get() - 1)
      #strong(text.at(level.get() - 2))
      #context [#thorem_counter.display(numbering)]
      :#h(0.5em)#i
    ]
  }
  v(1.2em, weak: true)
  level.update(v => v - 1)
}

  • 0.65em is the default par.leading, i.e. line spacing
  • 1.2em is the default par.spacing, i.e. space between paragraphs.

You might also be happy with one of the theorem packages on universe. From a quick glance at the readmes, it seems like theorion – Typst Universe, great-theorems – Typst Universe (via rich counters) or ctheorems – Typst Universe support nested numbering like you want.

1 Like