You might consider a different interpolation syntax (viz. GitHub - camlp5/pa_ppx_fmtformat: A PPX rewriter to provide string-interpolation, using Fmt as the underlying mechanism )
The advantage of the suggested format for interpolated expressions over “%{…%}” is that with the multiple forms, there’s never a need to escape – you can just pick a different form.
====
The simplest interpolated expression is of the form $(...) but all of the following are accepted:
$(...), $(|...|)
$[...], $[|...|]
${...}, ${|...|}
$<...>, $<|...|>
So basically, ‘$’ followed by any of [ ‘(’, ‘[’, ‘{’, ‘<’ ],
optionally ‘|’, and then at the end, the matching text. Between these
8 forms, it should be possible to enclose any interpolated expression
without difficulty, I would think.
In the text surrounded by these delimiter, anything other than the
end-string is acceptable, and there is no provision made for escaping.
The contents of the interpolated expression can be of three forms:
==== interpolated expression with format-specifier: $( <expression> | <format-specifier> )
an interpolated expression of the form $(abc|%d) specifies that the
expression abc will be formatted with %d. So {%fmt_str|a $(abc|%d)|} expands to
Fmt.(str "a %d" abc).
==== interpolated expression with Fmt formatter: $( <expression> | <Fmt formatter expression> )
an interpolated expression of the form $(abc|int) specifies that the
expression abc will be formatted with the Fmt formatter int. So {%fmt_str|a $(abc|int)|} expands to
Fmt.(str "a %a" int abc).
==== interpolated expression without specifier/formatter: $( <expression> )
an interpolated expression of the form $(abc) specifies that the
expression abc will be formatted with %s. So {%fmt_str|a $(abc)|} expands to
Fmt.(str "a %s" abc).