Repository navigation
Conversation
Problem: Typst output fails to compile when user text contains "$"
("Costs in US$ 2020": unclosed delimiter), "@" ("a@b": label does not
exist), a backtick, "//" or "/*" (comment swallows the cell's "]"), a
user-escaped "\*", or an unpaired "*" in a header/caption. "~" renders
as a space, and a leading "- ", "+ ", "= " or "/ " turns the cell into a
list, numbered item, heading or term.
Cause: _escape_typst only escaped \ [ ] # * < > _, not the rest of the
markup-mode syntax; "\*" was preserved by a lookbehind that runs after
backslashes have already been doubled.
Fix: escape $ ` @ ~ as well, comment openers (except after ":" so URLs
stay links), leading block markers, and unpaired asterisks where
asterisks are otherwise passed through for bold; protect a user "\*"
before backslash escaping. Every text slot (cells, row labels, headers,
spanners, row-group names, notes, caption) already goes through this
function.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 9, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What problem do you want to solve?
make(type="typst")escapes\ [ ] # * < > _, but not the rest of Typst's markup-mode syntax (https://typst.app/docs/reference/syntax/). Ordinary text in a label, cell, caption or note therefore either stops the document from compiling or is rendered as markup:Observed with typst 0.13 for each text slot (cell, row label, column header, spanner, row-group name, notes, caption):
Costs in US$ 2020contact a@b<b>does not exist (reference)code `xa // b]a /* bModel*,*bolda \* b\is doubled first, leaving a bare*~0.50.5(~is a non-breaking space)- sub,+ ctrl,= base,/ term: x1. ctrl, a heading, a term listExpected: the text prints as typed. (The docs' own
Annual Salary ($)label in UsingLabels.ipynb hits the first case if rendered to Typst.)Fix
All in
_escape_typst, through which every text slot already passes:$,`,@and~like#,<,>and_;/that starts//or/*, except after:, so URLs (https://...) are still lexed as links;=,-,+or/followed by a space, at the start of each line. A bare-or-0.12is left alone, so Typst still typesets negative numbers with a minus sign;*bold*(headers, spanners, row-group names, caption), escape them only when their count is odd, i.e. when one would be left unclosed;\*before backslashes are doubled, so it renders as*, which is what the old comment said the lookbehind was for.Left as is: smart quotes,
--/---dashes and.... Typst typesets these like LaTeX does, and they compile.Tests
test_typst_markup_characters_render_literally: 12 texts × 7 slots. Each one compiles with the typst CLI and checks that the text appears unchanged in the PDF text (pdfplumber).test_typst_escaped_asterisk_renders_as_asterisk(cell, header).test_typst_url_in_notes_stays_a_link: a guard that a URL is left unescaped and still prints.The tests use the existing
needs_typstskip marker andcompile_typsthelper intests/api/test_output_formats.py. 77 of the 87 new cases fail on main and all 87 pass with the fix. The other 10 already pass on main and guard against regressions:a /* b,Model*and*boldin slots where asterisks were already escaped, plus the URL case. Full suite: 585 passed, and all 135 snapshots are unchanged. pre-commit andtyare clean.Open question
This is a proposal that typst text is always literal, which is how
\,_,#and<were already handled. The alternative is to let users write Typst math such as$beta$in labels, astexoutput lets them write$\beta$. That would need an opt-out, because$in plain text (currency) is common and currently breaks compilation.Not changed here:
tab_labelis inserted as a raw<label>, andtypst_stylevalues are inserted verbatim.🤖 Generated with Claude Code