How to Create Nested Containers

Based on a question I recently asked on how to wrap the content of a section, I think I have been able to do it:

First, the function from my previous question. The only difference is that I have used positional instead of named arguments.

#let is-heading(it) = {
  it.func() == heading
}

/// A show rule that wrap everything between two headings of the same level
///
/// Usage: ```
/// #show: wrapp-section.with(
///   depth: 1, // optional
///   wrapper: (heading: none, section: none) => {
///    rect[
///      heading: #box[#rect[#heading]]
///      
///      section: #box[#rect[#section]]
///    ]
///  }
/// )
/// ```
///
/// Note: `#set` rules (like `#set text(lang: "fr")`) must be declared before calling `#show: wrapp-section`
#let wrapp-section(
  body,
  depth: 1,
  wrapper: none,
) = {
  // The heading of the current section
  let heading = none
  // The content of the current section
  let section = ()

  for it in body.children {
    let x = it.func();
    
    if (is-heading(it) and it.fields().at("depth") < depth) {
      if heading != none {
        // Complete the last section
        wrapper(heading: heading, section: section.join())
        heading = none
        section = ()
      }
      it
    } else if is-heading(it) and it.fields().at("depth") == depth {
      if heading != none {
        // Complete the last section
        wrapper(heading, section.join())
        heading = none
        section = ()
      }

      heading = it
    } else if heading != none {
      // Continue the current section
      section.push(it)
    } else {
      it // if not in any section (before the first heading of the appropriate depth)
    }
  }

  // Complete the last section
  if heading != none {
    wrapper(heading, section.join())
  }
}

Then, a recursive function that create the nesting from a heading and what I call a section (everything before the next heading of the same level)

#let nest-block(body, depth: 1) = {
  wrapp-section(
    depth: depth,
    wrapper: (heading, content) => {
      block(
        stroke: (left: black),
        inset: (left: 1em),
      )[
        #heading
        #nest-block(depth: depth + 1, content)
      ]
    }
  )[#body]
}

And finally, we can use it:

// For some reason, must be done before calling #show
#set text(lang: "en")

#show: wrapp-section.with(
  depth: 1,
  wrapper: (heading, content) => {
    heading
    nest-block(depth: 2, content)
  }
)

= heading 1 - a

== heading 2 - a

some
text _and_ 
more

=== heading 3 - a

stuff

== heading 2 - b
test


= heading 1 - c

== heading 2 - c

some
text _and_ 
more

=== heading 3 - c

stuff

== heading 2 - d
test

If you prefer to have the level 1 heading being nested too, you can replace the #show rule by

#show: nest-block