How to set an enum numbering rule with multiple levels

I am looking to produce something like the following:

Setting a custom rule for enum works partly, but obviously applies to all the sublevels as well.


#set enum(numbering: n => [*Question #n.*])
+ Suppose two balanced coins are tossed. Assume equally likely outcomes.
  +  List the sample space for this experiment.
  +  Let $A $ denote the event that _exactly_ one head is observed. Let $B $ be the event _atleast_ one head is observed. List the sample points in $A $ and $B $.
  +  Find $P(A)$, $P(B)$, $P(A union B)$, and $P(A sect B)$.

This produces something like


which not only appends the “Question” part to the inner list, but also produces an indentation that I would like to avoid.

I found a related thread but it’s a bit beyond what I can understand.

I also know there is an itemize package and I am going through it, but it’s taking some time.

I found somewhat of a solution, from a online post somewhere.


#set enum(numbering: n => [*Question #n*.])
#show enum.item: it => {
  if repr(it.body.func()) == "sequence" {
    let children = it.body.children
    let index = children.position(x => x.func() == enum.item)
    if index != none {
      enum.item({
        children.slice(0, index).join()
        set enum(indent: -4.5em, numbering: "a.") // Note that this stops an infinitly recursive show rule
        children.slice(index).join() // basically the inner enum.items (all of them)
      })
    } else { 
      it 
    }
  } else {
    it
  }
}

This seems to work as long as I maintain the spacing


+ Suppose two balanced coins are tossed. Assume equally likely outcomes
  + List the sample space for this experiment.
  + Let $A $ denote the event that _exactly_ one head is observed. Let $B $ be the event _atleast_ one head is observed. List the sample points in $A $ and $B $.
  + Find $P(A)$, $P(B)$, $P(A union B)$, and $P(A inter B)$.

  | any text follows original indentation of the enum 

except the | any text follows original indentation of the enum is completely misaligned. See the image. How can I force the text to go back to 0 indentation?

It seems that this is not so easy to do. With the help of itemize, you can do like this:

#import "@preview/itemize:0.2.0" as el
#let body-indent = .5em
#set enum(
  numbering: "1.1.",
  body-indent: body-indent,
)
#show: el.default-enum-list.with(
  label-format: it => {
    if it.level == 1 {
      show: strong
      [Question #it.body]
    } else {
      it.body
    }
  },
  label-width: ((amount: -body-indent, style: "auto"), auto), // for level-1 
)
+ Suppose two balanced coins are tossed. Assume equally likely outcomes.

  +  List the sample space for this experiment.
  +  Let $A $ denote the event that _exactly_ one head is observed. Let $B $ be the event _atleast_ one head is observed. List the sample points in $A $ and $B $.
  +  Find $P(A)$, $P(B)$, $P(A union B)$, and $P(A inter B)$.
    + #lorem(2)
    
  #lorem(10) // other text
    
+ #lorem(10)
  + #lorem(2)
  + #lorem(2)

For more details about label-width, see the package document.

If you need indent or other numbering for level 2 enums, then you can do like:

#import "@preview/itemize:0.2.0" as el
#let body-indent = .5em
#set enum(
  numbering: "1.a.1.", // level 2: a
  body-indent: body-indent,
)
#show: el.default-enum-list.with(
  label-format: it => {
    if it.level == 1 {
      show: strong
      [Question #it.body]
    } else {
      it.body
    }
  },
  label-width: ((amount: -body-indent, style: "auto"), auto), // for level-1
  indent: (auto, 1em, auto), // indent for level 2
)
+ Suppose two balanced coins are tossed. Assume equally likely outcomes.

  +  List the sample space for this experiment.
  +  Let $A $ denote the event that _exactly_ one head is observed. Let $B $ be the event _atleast_ one head is observed. List the sample points in $A $ and $B $.
  +  Find $P(A)$, $P(B)$, $P(A union B)$, and $P(A inter B)$.
     + #lorem(2)
    
  #lorem(10) // other text
    
+ #lorem(10)
  + #lorem(2)
  + #lorem(2)

Or define a function like Question:

  #import "@preview/itemize:0.2.0" as el
  #let Question(doc) = {
    let body-indent = .5em
    set enum(
      numbering: "1.a.1.", // level 2: a
      body-indent: body-indent,
    )
    show: el.default-enum-list.with(
      label-format: it => {
        if it.level == 1 {
          show: strong
          [Question #it.body]
        } else {
          it.body
        }
      },
      label-width: ((amount: -body-indent, style: "auto"), auto), // for level-1
      indent: (auto, 1em, auto), // indent for level 2
    )
    doc
  }

  #Question[
    + Some Question
      + Option 1
      + Option 2

      Some text
    + Some Question
  ]

1 Like

Thank you, that seems like a valid solution. I was actually thinking something even easier. Is there a way to have an automatic incrementing counter? It might be easier to do

#Question Suppose two balance coins are tossed. Assume equally likely outcomes.
+ Option 1
+ Option 2 

#Question Second Question

Using an enum seems not the right move here given the level of hackiness required.

This is even easier. You can define:

  #let question-counter = counter("question") // use `counter`
  #let Question = {
    question-counter.step()
    context [
      *Question #question-counter.get().first().*
    ]
  }
  #Question Suppose two balance coins are tossed. Assume equally likely outcomes.
  + Option 1
  + Option 2

  #Question Second Question