Hi !
New user of Typst, so far it’s sooo good. I really wish it was a thing when I was going through uni ahah.
I’m trying to add a pagebreak
before every heading(level: 1)
, but only if they are below half the page.
Adding a pagebreak is easy with :
show heading.where(level: 1, outlined: true): it => {
pagebreak()
it
}
But when trying to add a little logic, I keep getting redundancy errors.
show heading.where(level: 1, outlined: true): it => {
if it.location().position().y > page.height * .5 {
pagebreak()
}
it
}
And I think I understand why (feel free to explain either way :)) ), but what I don’t understand is :
- Why adding the line
v(0pt)
above the pagebreak
fixes the redundancy error ? (afterward, the outline is garbage, containing the wrong page number)
- How can I fix this issue without a hacky trick, if it’s even possible.
1 Like
Hello and welcome!
If your error is
warning: layout did not converge within 5 attempts
= hint: check if any states or queries are updating themselves
This is normal, do not panic.
Let’s start with a simple question: if your heading was to be before the pagebreak, do you think you would get the same error? The answer is no.
What you wrote diverges in an infinite loop:
- You add a pagebreak if the heading is halfway through the page by comparing to the heading element’s y position
- You add the heading itself.
- Backtracking, the heading’s position has … changed!
- Typst tries to resolve this layout, but cannot do it within 5 attempts, hence the error, and you probably don’t have the result you hoped for.
Now, how do you actually write this condition? You have to use an element that does not move with your pagebreak. The simplest way is to add a metadata
element. By querying that element’s position instead, you make sure you don’t have any “loops”
#show heading.where(level: 1, outlined: true): it => {
let h1 = query(metadata.where(value: "foo").before(here()))
if h1.len() != 0 and h1.first().location().position().y > page.height * .5 {
pagebreak()
}
it
}
= A
#lorem(500)
#metadata("foo")
= B
For additional reading, you might want to take a look at the following threads:
1 Like
Thank you so much for your answer.
So I did understand correctly why the warning was shown.
Sadly, that mean I cannot achieve what I want without a manual intervention ?
If the only way to pagebreak
after mid-page is to use a metadata tag before every heading, I do think the best solution is to just write the whole document and manually add pagebreak
at the end.
1 Like
I think the point in this case is that where is here()
exactly calculated. I’m not sure since I did not read the source code, but I made an alternative my-location
to make it work:
#let my-location = state("my-location", (:))
#let smartbreak(percentage) = (
context {
if my-location.get().y > page.height * (100% - percentage) {
pagebreak()
}
}
)
#show heading.where(level: 1, outlined: true): it => {
context my-location.update(here().position())
smartbreak(50%)
it
}
And the outline should be working properly using this impl.
However the compiler (Tinymist) is still telling me the layout does not converge in 5 attempts on may laptop, but not on another device. This is kinda weird and I’m not sure is this an issue about Tinymist or Typst.
2 Likes