#[ SOLVED ] Function call at the end of page (or some other solution).

1 messages · Page 1 of 1 (latest)

ocean star
#

Hi. I'm new to typst, and trying to use it for my thesis.

I want to accumulate some data in every page, and draw them as margin notes at the end. (I need to have it accumulated before drawing them.

#let code_note(content) = {
  place(
    top,
    code_note_inner(side: "outer")[#content],
  )
}

This should draw margin notes using some lib called marginalia.

#let print_code_refs() = context {
 /* Some data manipulation here */

  for (path, names) in grouped_dict.pairs() {
    if (path == "x") { continue }

    code_note[
      #text(path, size: 8pt, font: code_font)
      #line()
      #names.map(x => text(x, size: 6pt, font: code_font)).join(linebreak())
    ]
  }
}

Then in my document template

#let template(doc) = {
  set page(
    numbering: "1",
    foreground: context {
      print_code_refs()
    },
    footer: context {
      print_code_refs()
      reset_code_refs()
    },
  )
/* More settings */
}

When I place it in the footer, it draws the margin notes on the bottom of the margin. (Instead of the top)
However, when I manually place print_code_refs(), it puts the margin notes at the top of the page (just like I want it). I think the footer is at fault.

Ideally, I'd want some equivalent of placing print_code_refs() at the end of every page just before the break.

Thanks a lot for any help, and thanks to the people who responded in the quick questions channel.

terse lance
#

you could try putting it in floating figures

#show: doc => {
  show pagebreak: it => it + figure(bottom, ...)
  
  figure(bottom, ...)
  doc
}

(just a rough idea in my head tho)

#

in general, this is a very complicated layout problem and even typst itself cannot currently solve all the edge cases (see this issue https://github.com/typst/typst/issues/5314 for example).
so a really robust solution for this problem might just not exist

GitHub

Description Sometimes a footnote precedes a reference to it. For example: = Lorem #lorem(580) == Ipsum #lorem(10)#footnote[#lorem(20)] #lorem(2000) Here, the reference to a footnote is located at P...

ocean star
#

Thank you, I will look into it

ocean star
#

I did not even need the figures, and it worked. However, it only works with an explicit pagebreak.

ocean star
#

[ SOLVED ] Function call at the end of page (or some other solution).

#

I solved this. The function which accumulates the data draws it on the last invocation. I used query for this.

terse lance
#

mind sharing a working example?
does it work if the manual pagebreak is close to the natural one?

ocean star
#

Well. In my case, it doesn't need to be before the pagebreak, but it has to be the "last of" on the page. I'm doing margin notes, where I group references by the file they are in.

This function collects the references on one page, and if it's the last one on the page, it invokes the drawing of them.

#let cnote(..names, path) = {
  [#metadata((path: path, names: names.pos()))#_code_ref_label]

  context {
    let old = code_refs.get()
    let num = old.entries.map(x => x.names.len()).sum(default: 0) + 1

    let fnum = numbering("I", num)
    code_refs.update(old => {
      let entry = (path: path, names: names.pos())
      (entries: old.entries + (entry,))
    })

    super(text(fnum)) // draws the number in the text.

    let pos = here().position()
    let later = query(_code_ref_label).filter(m => {
      let mp = m.location().position()

      mp.page == pos.page and (mp.y > pos.y or (mp.y == pos.y and mp.x > pos.x))
    })

    if later.len() == 0 {
      print_code_refs()
      reset_code_refs()
    }
  }
}

And here I print them.

#let print_code_refs() = context {
  let refs = code_refs.get().entries

  // Group names by file path while preserving insertion order
  let grouped = (:)
  for ref in refs {
    let existing = grouped.at(ref.path, default: ())
    grouped.insert(ref.path, existing + ref.names)
  }

  let number = 1
  for (path, names) in grouped.pairs() {
    let items = ()
    for name in names {
      let fnum = super(text(numbering("I", number)))
      items.push(fnum + text(name, size: 6pt, font: code_font))
      number += 1
    }
    _code_note[
      #text(path, size: 8pt, font: code_font)
      #line()
      #items.join(linebreak())
    ]
  }
}

You can notice the numbering isn't correct. I will fix it later.
Also, and that's unfortunate, I get warning that the layout did not converge in 5 attempts :/

#

It draws margin notes like this. Not sure how it behaves when the manual pagebreak is close to the natural one, but on some pages, the margin notes collide. Will look into it more.

lyric fable
#

Also, and that's unfortunate, I get warning that the layout did not converge in 5 attempts
Oh yeah that's unfortunate. IMO that needs to be fixed before it's truly solved. It's unfortunately the case that we can't trust typst's output when this warning appears