How to get the number of the first and last paragraph on a page and show the result in the header?

Ah that’s because of the dedup call which only checks the id. I’ve refactored the code a bit to avoid that, also using two metadata values per paragraph to simplify the logic:

#let get-chap-short(x) = {
  let shorts = query(selector(<h1-short>).before(x.location()))
  return shorts.at(-1, default: none)
}

#let short-and-id(x) = {
  let short = get-chap-short(x)
  return (short: short.value, id: x.value)
}

#let format-header(a, b) = {
  if b == none or b == a {
    return [#a.short: #a.id]
  }
  if a.short == b.short {
    return [#a.short: #a.id -- #b.id]
  }
  return [#a.short: #a.id -- #b.short: #b.id]
}

#set page(
  width: 100mm,
  height: 100mm,
  header: context {
    let pars = query(selector.or(<h4-start>, <h4-end>))
      .filter(x => x.location().page() == here().page())
      .map(short-and-id)
      .dedup()
    if pars.len() == 0 {
      // No paragraph starting or ending on this page
      // -> check if a paragraph starts before and ends after this page
      let prevs = query(selector(<h4-start>).before(here()))
      let nexts = query(selector(<h4-end>).after(here()))
      if prevs.len() == 0 or nexts.len() == 0 {
        return none
      }
      let prev = short-and-id(prevs.last())
      let next = short-and-id(nexts.first())
      if prev != next { // should not happen
        return none
      }
      return format-header(prev, next)
    }
    return format-header(pars.first(), pars.at(-1, default: none))
  },
)

#show heading.where(level: 4): it => it.body + h(1em)

#let my-par(id: none, body) = par({
  [#metadata([#id])<h4-start>]
  if id != none {
    heading(level: 4, id)
  }
  body
  [#metadata([#id])<h4-end>]
})

#let my-h1(short: none, ..args) = {
  heading(level: 1, ..args)
  [#metadata(short)<h1-short>]
}

#my-h1(short: "A-Chapter")[This is Chapter A]
#my-par(id: "1", lorem(20))
#my-par(id: "2", lorem(20))
#my-h1(short: "B-Chapter")[This is Chapter B]
#my-par(id: "1", lorem(50))
#my-par(id: "2", lorem(20))

#pagebreak()

#my-h1(short: "C-Chapter")[This is Chapter C]
#my-par(id: "1", lorem(20))
#my-par(id: "2", lorem(20))
#my-par(id: "3", lorem(150))

#my-h1(short: "D-Chapter")[This is Chapter D]
#my-par(id: "11", lorem(50))
#my-par(id: "11a", lorem(20))

1 Like