Can you make a horizontal `enum`/`list`?

I remember making this in LaTeX (which is pretty trivial), but this was so long ago that I now think I’ve seen this done in Typst. I’ve looked at available parameters for enum and didn’t find anything related to direction of items. My last obvious choice was to redefine a show rule for enum, but I immediately realized that it wouldn’t be anywhere near a one-liner, so I didn’t create one. Having ready to use code snippets of Typst elements for this exact reason would be awesome: How can I document my own user defined functions/variables?.

In short, I want to have something like this:

a) item 1; b) item 2; c) item 3.

by writing:

#set enum(numbering: "a)")
+ item 1
+ item 2
+ item 3

The delimiter can also be , or nothing. The last automatic period would be a cool addition. But all this can be added directly:

#set enum(numbering: "a)")
+ item 1;
+ item 2;
+ item 3.

So I want to focus on the horizontal aspect of it. For now, I think having them all be inside a paragraph, i.e., in a single sentence.


Separately, I remembered that there also can be instance like:

a) item 1     b) item 2     c) item 3
d) item 4     e) item 5     f) item 6

or this:

a) item 1     c) item 3     e) item 5
b) item 2     d) item 4     f) item 6

But I now realized that this is probably the best case for using grid with n columns and some permutation logic for swapping cells/array elements before adding the into grid(). Although, how would you specify the numbering part correctly? With cells.enumerate().map(((i, cell)) => numbering("a)", i + 1) + " " + cell)? But that would be less of an enum and more of just an array with elements. Perhaps this can be another topic for discussion. Because I don’t see any other way around this, the next best UX form would be:

#custom-enum[
  + item 1
  + item 2
  + item 3
  + item 4
  + item 5
  + item 6
]

(But internally this will probably be the same .enumerate().map() thingy.)

Lastly, I think that this could be a good potential built-in feature (set enum(horizontal: true)).

1 Like

The first request can be achieved by something like this:

#show enum: s => s.children.enumerate(
  start: s.start
).map(((k, it)) => {
  numbering(s.numbering, k)
  " "
  it.body
}).join("; ")

In the same fashion, the other cases can be achieved – however one has to figure out how to deal with longer items.

1 Like

That’s a good attempt, and for the most part this would be enough, but you didn’t consider a bunch of other parameters:

#set enum(
  // body-indent: 2em,
  // full: true,
  // indent: 2em,
  // number-align: left,
  numbering: "1)",
  // spacing: auto,
  start: 5,
  // tight: false,
)
#show enum: it => {
  it
  .children
  .enumerate(start: it.start)
  .map(((k, child)) => numbering(it.numbering, k) + " " + child.body)
  .join(" ")
}

+ this
  + one;
  + one;
  + one.

Some of them aren’t really useful anymore, but some of them still are. And when lists get nested, stuff gets this much more complicated:

image

The nested example is probably rarer, but is still valid if you want to have a vertical enum and the switch to horizontal inside. But then it would probably become even more complex.

Here’s a fun alternative which doesn’t discard any parameters, for short enough enums:

#block(height: 1em, columns(4)[
  1. Hello world
  2. Around the
  3. The world
  4. World world
])

For manually numbered enums specifically (1. 2. 3. instead of + + +), this more automatic solution also works:

#let henum(it) = [
  #let items = if it.func() == enum {
    enum.children.len()
  } else if it.has("children") {
    it.children.filter(x => x.func() == enum.item).len()
  } else {
    panic("Unknown input")
  }
  #show enum.item: it => [#it #colbreak()]
  #columns(items)[
    #it
  ]
]

// Add a colbreak after every item
#henum[
  1. aaaa
  2. bbbb
  3. ccccc
  4. ddddd
]