How to fix the bug (?) for outline entries with long titles?

Sorry I couldn’t find a title that concisely described the bug.

Here is the code:

#outline()
= This is a very very very very very very very very very very very very very very very very long title

Here the page number in the outline is pushed to the next line, but it is not right-aligned. Is this normal, and if not, is there a way to fix this?

It’s a known issue, but in my thesis I had to fix this + first line indent issue. The code I used is too complicated, and I need to extract it, so I don’t wanna do this. But I copied the core logic down and changed it a bit:

#let fix-multi-line-outline-entries = it => {
  let indent = {
    let indent = outline.indent
    if type(indent) != relative {
      indent = 0pt
    }
    h(indent * (it.level - 1))
  }
  let count = counter(heading).at(it.element.location())
  let space-width = measure("| |").width - measure("||").width
  let make-entry(body) = {
    let content = [#body #box(width: 1fr, it.fill) #it.page]
    let content = if it.element.numbering != none {
      grid(
        columns: 2,
        gutter: space-width,
        numbering(it.element.numbering, ..count),
        content,
      )
    } else {
      content
    }
    link(it.element.location(), content)
  }
  box(layout(((width, height)) => {
    let entry = make-entry(it.element.body)
    // Fix long headings that don't trigger filler to extend to the end.
    if measure(indent + box(entry)).width > width {
      let content = it.element.body
      // If heading is `sequence`.
      if content.func() == [].func() {
        let mapper = x => if x != [ ] { x.text } else { " " }
        content = content.children.map(mapper).join()
        content = [#content]
      }
      assert(content.func() == text, message: "not implemented")
      let parts = content.text.split()
      let last = parts.pop()
      let first = parts.join(" ")
      let new = first + parbreak() + last
      // Ignore headings that are long enough to trigger the filler.
      if measure(new).width <= width {
        entry = make-entry(new)
      }
    }
    indent + box(entry)
  }))
}

#show outline.entry: fix-multi-line-outline-entries

#outline()

#let prefix = "This is a" + " very" * 16

= #prefix long titl
= #prefix long title
= #prefix long titlee

#set heading(numbering: "1.")

= #prefix longg
= #prefix long tit
= #prefix long titl

Few notes:

  1. here the indentation feature is broken, but it can probably be fixed somehow or removed completely if not needed;
  2. I made headings so that 1st is one-liner, then the bug, then two-liner (without and with numbering);
  3. it’s so huge and (somewhat) broken, there should be something more practical, but an ultimate solution might be even bigger;
  4. the underlying outline.entry structure is most definitely different, so styling will be applied incorrectly in some cases.
1 Like

Unfortunately, this is not a copy paste solution.

1 Like

I suspect that the outline issue is essentially the same as this problem with a QED symbol that needs to be on the right:

And indeed Laurenz’ solution can be adapted to this use case:

#show outline.entry: it => {
  link(it.element.location(), {
    it.body
    box(width: 0pt)
    box(width: 1fr, it.fill)
    sym.wj
    [#it.element.location().page()]
  })
}

#outline()
#outline(
  title: [List of Figures],
  target: figure.where(kind: image)
)


#let prefix = "This is a" + " very" * 16
= #prefix long title
= #prefix long! title
== #prefix long title

#set heading(numbering: (..nums) => "Ch " + numbering("1.", ..nums))
#let prefix = "This is a" + " very" * 15
= #prefix looong title
= #prefix loooong title
== #prefix long title

#let prefix = "This is a" + " very" * 13
#figure(
  [a],
  caption: [#prefix looong caption]
)
#figure(
  [a],
  caption: [#prefix looong! caption]
)
#figure(
  [a],
  caption: [#prefix loooong caption]
)
Rendered outlines

What I didn’t attempt is duplicate @Andrew’s indentation of follow-up lines: for example, the word “title” in the second line of the third entry starts to the left of the start of the entry. Other than that, I think this solution worked pretty well.

1 Like