How does the `lang` property of a raw block affects ligatures?

I don’t understand how the language property affects which ligatures are rendered? I created a small MRE:

  • why is the pipe (|>) ligature not rendered when using r as language
  • why is there no ligature for => with the language r but there is one with the language js?

As long as I don’t define a language the ligatures work es expected. Could it be related to the theme as well?

It’s definitely strange behaviour. Could it be that the ligatures are syntax dependent?

#raw("
  foo |> bar(buz)
  buz >= foo
  buz -> test('=>')
", lang: "r")

I had to reformat the syntax snippet to make it highlighted here. But this gives me the rendering of:

grafik

It seems like the ligatures are applied in a syntax sensitive manner since R - as far as i know - has no “=>” as formal operator.

The characters | and > both are their own operator, which are probably defined with a higher priority in the syntax. Thus, when applying the syntax highlighting, The | and > characters are styled separately, leading to two separate text nodes, which makes ligatures impossible. You can see this when using a show rule like

#show raw: it => repr(it.lines)

where the code

```r
foo |> bar
buz -> test('|>')
```

is then converted to the lines

line(
  body: sequence(
    [foo ],
    styled(child: [|], ..),    // These characters are
    styled(child: [>], ..),    // styled separately.
    styled(child: [ bar], ..),
  ),
  ..
),
line(
  body: sequence(
    [buz ],
    styled(child: [->], ..),   // These are styled together.
    styled(child: [ ], ..),
    styled(child: [test], ..),
    styled(child: [(], ..),
    styled(child: ['], ..),
    styled(child: [|>], ..),   // These are styled together.
    styled(child: ['], ..),
    styled(child: [)], ..),
  ),
  ..
)

Different languages then differ in this behaviour as they may define their operators with different priorities, such that e.g. |> comes before | and >. This also explains, why the ligature works inside a string, as the whole string is styled in a single text node.

3 Likes

Uhh - thanks @Eric - that’s a really interesting finding.

Thanks a lot for the explanation! One follow-up question: @Eric the only way to make the ligature show up would be to adjust how the r language syntax highlighter works?

Yes, you can actually just get the R language syntax from GitHub as it seems that the one Typst uses by default is outdated. The updated one already includes the pipe operator with the correct ordering, so the ligatures work with that.

However, as apparently you can’t override the syntax of an already included language (Edit: Fixed in the latest development version), you need to edit the name or the file_extensions list at the top of the syntax file to something new (e.g. R_new), and then load that syntax file and use the new value as the lang of your code block.

#show raw: set text(font: "Fira Code") // any font supporting ligatures
#set raw(syntaxes: "R.sublime-syntax")

```r_new
foo |> bar
```

image

3 Likes