#How to recursively iterate over content block as token-chain?

5 messages · Page 1 of 1 (latest)

void thorn
#

(Migrated from #discussions)

I need glues to control inter-character horizontal spacing, like how cjkglue and cjkecglue work in xeCJK. I am informed that Typst core runtime does not expose a glue API. I wonder if I can write a preprocessor function that inserts #h(...) at each inter-character boundary, (recursively) iterating over content token-chain ([abc] being interpreted as a token-chain array([a],[b],[c]), for example). So my function returns a content block [a#h(...)b#h(...)c] (without impairing Knuth-Plass line breaking). It is like how Array.reduce works in JS. The parameters to each #h() is individually decided by consulting the type (western char / CJK char / inline block / etc) of the left token and the right token. An inline block is atomic and shall be treated as single token among plain characters.

Specifically, the major challenge here is whether a way to do the iteration is available. I did not find any specific mention on token-chain iteration or methods of content blocks in the documentation. Do enlighten me if some information is already documented.

tame summit
#

The methods of content are described here, specifically interesting for you are func() (to know the kind of content) and fields() (to know the properties of the content).

You want to transform the whole content tree, for this you can take this for inspiration: https://forum.typst.app/t/is-there-a-way-to-convert-content-to-bytes-for-use-in-plugins/2233/2?u=sillyfreak

In that post, content is recursively transformed into a dictionary; you would transform content into content instead.

#

?r

However...

It sounds like you can potentially do this even easier. You want to transform all texts somewhere inside your content, and you can find text with a show rule too:

#show text: it => {
  // after adding spaces, each text is only one character long
  // don't transform those again, so that the show rule terminates
  if it.text.len() < 2 {
    return it
  }

  // split, then join with spacing
  it.text.clusters().join(h(1pt))
}

hello *world*
tame summit
#

Since show text is very general, you may have unintended effects; if that's the case, the recursive approach may still be the right one.