///|
/// `[ a, b ]` on one line, or one item per line with leading commas (the
/// elm-format form): `[ a\n, b\n]`. With no items: `[]`. `leads[i]` (for
/// `i >= 1`) comes before the `,` of item `i` (see `Ctx::before_item`).
/// `inner` comes before the closing token (see `Ctx::inner`, and
/// `Ctx::inner_alone` for no items).
fn sequence(
  split : Split,
  open : String,
  close : String,
  items : Array[@pretty.Doc],
  leads? : Array[@pretty.Doc] = [],
  inner? : @pretty.Doc = @pretty.empty(),
) -> @pretty.Doc {
  guard !items.is_empty() else {
    return @pretty.text(open) + inner + @pretty.text(close)
  }
  let mut body = @pretty.text(open + " ") + @pretty.nest(2, items[0])
  for i in 1.. @pretty.Doc {
  let mut body = @pretty.text("| ") + @pretty.nest(2, fields[0])
  for i in 1.. @pretty.Doc {
  label + separator + @pretty.group(@pretty.tab(4, split_line(split) + value))
}

///|
/// `(d)`; when `d` breaks, the `)` goes on its own line in the column of
/// the `(`, and the lines of `d` are indented from the column after the `(`
/// (the elm-format form). `inner` comes before the `)`.
fn parens(
  split : Split,
  d : @pretty.Doc,
  inner? : @pretty.Doc = @pretty.empty(),
) -> @pretty.Doc {
  @pretty.group(
    @pretty.align(
      @pretty.text("(") +
      @pretty.nest(1, d + inner) +
      split_softline(split) +
      @pretty.text(")"),
    ),
  )
}

///|
/// `head a b` on one line, or each item on its own line at the next tab
/// stop (a multiple of 4), as elm-format indents.
fn spaced(
  split : Split,
  head : @pretty.Doc,
  items : Array[@pretty.Doc],
) -> @pretty.Doc {
  let mut rest = @pretty.empty()
  for x in items {
    rest = rest + split_line(split) + x
  }
  @pretty.group(head + @pretty.tab(4, rest))
}

///|
/// `head a b c` as elm-format lays out an application
/// (`ElmStructure.application`). `first` is `Split` for `FASplitFirst`:
/// each argument on its own line. `rest` is `Split` for
/// `FAJoinFirst SplitAll`: the first argument on the line, the others on
/// their own lines. With `Join` for both (`FAJoinFirst JoinAll`), the first
/// argument leaves the line only when the head or it is multi-line, and the
/// others leave it when one of them is multi-line. With `Fit`, this is
/// `spaced`. `args` is not empty.
fn application(
  first : Split,
  rest : Split,
  head : @pretty.Doc,
  args : Array[@pretty.Doc],
) -> @pretty.Doc {
  match first {
    Fit | Split => spaced(first, head, args)
    Join => {
      let mut tail = @pretty.empty()
      for i in 1.. @pretty.Doc {
  guard !items.is_empty() else {
    return @pretty.text(open) + inner + @pretty.text(close)
  }
  let mut body = @pretty.text(open + " ") + items[0]
  for i in 1.. @pretty.Doc {
  @pretty.text("(") + d + @pretty.text(")")
}

///|
/// `n` line breaks.
fn line_breaks(n : Int) -> @pretty.Doc {
  let mut d = @pretty.empty()
  for _ in 0..