quartztz · 05/06/2028
it all started with an innocent message to my friend emily.
quartztz: is there a way to define custom syntax in typst
emily: define custom syntax
q: like if i want|content|to be interpreted as#emph[content]
e: nope
e: no way
q: so sad
and i was genuinely sad. i really enjoy writing typst, in particular the ease of defining variables for arbitrarily complex series of symbols i might need for a given project. it’s made writing technical documents actually fun!
however, the flexibility stopped at #let declarations, which while cool are
fairly limited in the you can have: in particular, calling functions with #
bothers me greatly. It’s not yet LaTeX-\ level, but if i can avoid it, i most
definitely will.
so, without much conviction, i started scanning the typst documentation, and in
plain sight, there they were: show: regex rules.
#show rules allow you to select and restyle document elements
programmatically. the selectors go from builtin content types such as heading
to <label>s to arbitrary "text", with optional filtering option. however,
there is another possible selector i’d never seen! i quote:
Regex:
show regex("\w+"): ..
Select and transform text with a regular expression for even more flexibility. See the documentation of the regex type for details.
that sounds exactly like what i need! while it’s not completely arbitrary (you are bottlenecked by the syntax you can match using the regex engine shipped with typst) you can still do all of the slightly-above-basic stuff you want.
for example, my previous use case can be easily written as:
#show regex("\|[^\|]+\|") : it => {
let t = it.text
// cleanup: turn |<ct>| to <ct>
let len = t.len()
emph[t.slice(1, len - 1)]
}
the cleanup is unfortunately necessary. i’m reasonably sure this could be extended to use capture groups and simplify the usage, but that’s out of scope for the current work. i’m far from a regexpert and i’m just happy to have found a solution.
another more involved example: markdown-style links in typst!
#show regex(
"\[[^\]]+\]\((http(s)?:\/\/)([\w~+*]+\.)+[\w~+*]+(\/[\w~+*]+(\.[\w~+*]+)?)*\)",
): it => {
let len = it.text.len()
// cleanup: turn [<s>](<e>) into (<s>, <e>)
let (s, e) = it.text.slice(1, len - 1).split("](")
link(e)[#s]
}
again. not a regexpert. surely there’s ways to simplify this. in particular, the regex doesn’t have to validate the link, but it was more fun to write like this.
i’ll be ironing out some kinks and adding some sensible details to my template. for now, i’m just glad there’s a technique i can do fun stuff with!