How to determine if a string is formatted in multiple lines?

Is there a way to detect whether a string in Typst has been split into multiple lines, and if possible also to get exactly how many lines it spans?

#let break-check(text) = {
  if (<text is broken into multiple lines>) {
    text + " I'm BROKEN!"
  } else {
    text
  }
}

#break-check[To seek truth is to wander eternally between the certainty of what is and the possibility of what could be.]

Thanks!

Hey.

It’s not a string, it’s content, see Syntax – Typst Documentation and Content Type – Typst Documentation. Which makes it so much harder, as for string it’s just usually string.split("\n").len().

Basically, you need to use layout and measure to get the current layout width, and content’s height. Then, using par.leading, you can determine the approximate number of lines used. To make it better, add 0.5 and floor it.

1 Like

Thank you so much for putting me in the right direction!
With Cursor’s help I solved it without relying on the par.leading:

#let break-check(text) = {
  layout(size => {
    // 1. Measure the height of the actual text
    let actual_height = measure(
      block(width: size.width, text),
    ).height
    // 2. Measure the height of a known single-line text block for comparison
    // We use a short string that is guaranteed not to break on its own line.
    let single_line_height = measure(
      block(width: size.width, "A"),
    ).height
    // 3. Check if the actual height is greater than the single-line height.
    // We use a small tolerance (e.g., 0.1pt) because floating point comparisons
    // can sometimes be tricky, although often not necessary for block height.
    let broken = actual_height > single_line_height * 1.01

    if broken {
      [#text I'M BROKEN!]
    } else {
      [#text]
    }
  })
}

// Single line
#break-check(lorem(10))
// Multiple lines
#break-check(lorem(16))
1 Like

The block in measure is not the correct approach, but since height is measured while width is locked, it probably won’t change the result.

The par.leading is not needed if you only need to compare 1 vs. multiple lines, since multiple lines will always have bigger height than one (unless cursed par.leading is set).

1.01 might break, not sure.

2 Likes

I understand, thanks for the clarification. For now, my concern is only the height. I may refine this later, but the current method already achieves my goal of formatting this tricky outline:

As you can see, the first entry’s title collides with the author name and wraps onto a new line. I handled this with an if-else block that applies different formatting.

Cheers

EDIT:

Here’s the original:

Source: https://archive.org/details/sim_philosophical-review_1954-10_63_4/page/n2/mode/1up?view=theater