How to enable word wrapping of long strings in tables that allows for correct copy-paste of cell contents?

Hello Typst,

I am trying to create a table with very long and potentially “unbreakable” strings, similar to:

Consider the following minimal example:

Original source code:

#table(
  columns: (1fr, 1fr),
  [`veryveryveryveryveryveryveryveryverylongraw`], [],
)

With the default #set: page rule, the contents of the first cell overflows into the second.

In the similar topics listed above, the proposed solution was to split the string into multiple smaller tokens with invisible spaces inbetween, as seen in the following example:

Previously proposed source code:

// Solution A
#show raw: it => { it.text.codepoints().join[-?] }

// Solution B
#show raw: it => { it.text.codepoints().join(sym.zws) }

#table(
  columns: (1fr, 1fr),
  [`veryveryveryveryveryveryveryveryverylongraw`], []
)

(I know the show rule should be more tightly scoped in a real scenario, but for this example, it’s besides the point.)

Issue:
Visually, this solves the issue. However, if the text is copied from the table, the clipboard also contains all the zws chars + the actual line breaks.

The following snippet is the contents of the clipboard (I don’t know if the HTML input text preprocessor removes the invisible spaces):

v­e­r­y­v­e­r­y­v­e­r­y­v­e­r­y­v­e­r­y­v­e­r­y­v­e­r­y­v­e­r­y­v­e­r­y­l­o­n­­
g­r­a­w

Expected behaviour:
… but what I would expect is:

veryveryveryveryveryveryveryveryverylongraw

I.e. the original, unmodified input string that was used in the Typst source code.

Is there any way to accomplish this behaviour using Typst?

Alternatively, is there a way to make a show rule that queries the render width of a string and manually adjusts the font size to a smaller value?

I don’t know of a fix for copying split up content but for this question:

@Y.D.X created a function as an answer to Scale content to max height and width keeping aspect ratio .

#let fit-content(max-width: 100%, max-height: 9pt, body) = layout(available => {
  let max-width = if type(max-width) == length {
    max-width
  } else {
    assert.eq(type(max-width), ratio)
    max-width * available.width
  }

  let (width, height) = measure(body)
  let factor = 100% * calc.min(max-width / width, max-height / height)

  scale(factor, reflow: true, body)
})


#table(
  columns: 3,
  [Normal], [Another normal column], fit-content(`veryveryveryveryveryveryveryveryverylongraw`)
)

1 Like

Ah, that’s really neat. Works well enough for me :)

Thanks for the help!

1 Like