From 66543815ae6cbf6e576a889c9291678744243953 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Thu, 20 Aug 2026 09:53:33 +0200 Subject: feat(render): Typst as a seventh escaping flavour Adds Escape.Typst: type, all, to_string ("typst"), of_string, of_extension (.typ), and a per-character expand function, structured identically to the existing latex escaper (one pass, no re-scan, so double-escaping stays impossible by construction). The metacharacter set was verified against the installed typst 0.14.2 binary, not assumed: a probe document escaping each of #, *, _, $, @, <, >, `, \, ~ and - was compiled and pdftotext'd back to confirm the literal character survives, and each was separately confirmed to do something else when left bare (# opens code mode, */_ toggle strong/emph, $ opens math, @ opens a reference -- a bare unresolved @word is a hard compile error, not merely mangled output -- can close around a bare word into label syntax that swallows it whole, ` opens raw, ~ is a non-breaking space, and a run of two or three '-' becomes an en/em dash). All ten are backslash-escapable; none needed a non-backslash workaround. '-' is escaped unconditionally rather than only inside a detected run, since this escaper has no lookahead -- a probe confirmed escaping every hyphen independently still typesets as literal hyphens for a run of any length, so the single per-character rule is sufficient. test_escape.ml's new Typst cases were written first and shown to fail against a stubbed identity apply before the real escaper landed, per this project's own regression-test discipline. Comments in both files mark which new tests are genuine regression tests (the per-character escaping, including a real shipped citation and a synthetic markdown-habit overlay name) versus characterisation (to_string/ of_string/of_extension are flat table lookups with no logic to have been wrong). --- test/test_escape.ml | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/test_escape.ml b/test/test_escape.ml index 35a9b9d..7c55395 100644 --- a/test/test_escape.ml +++ b/test/test_escape.ml @@ -12,6 +12,56 @@ let test_latex () = check "real name" "Ss.mi Nominis Iesu \\& Mari\xc3\xa6" (E.apply E.Latex "Ss.mi Nominis Iesu & Mari\xc3\xa6") +(* Typst's markup metacharacters, verified against the installed `typst` + 0.14.2 binary rather than trusted from a spec list: a probe document + escaping each one individually, `typst compile`'d and `pdftotext`'d + back, confirmed the literal character survives (and, separately, that + the UNescaped form really does something else -- #box[..] consumes a + bare '#', *x* renders bold, @word errors "cannot reference text", a + bare