typdiff can generate invalid Typst when diffing labels and cross-references
Summary
I ran typdiff on two Typst files generated by Quarto from different versions of the same report. The source files compiled individually, but the generated diff file did not compile with Typst.
The main issue is that typdiff appears to treat Typst labels as ordinary text. When labels are renamed, or when content immediately after a label changes, diff markup can be inserted inside label syntax or can wrap the label itself. This breaks downstream #ref(...) calls and sometimes produces invalid Typst syntax.
I have a PR prepared for this issue and will submit it shortly.
Environment
typst 0.14.2
quarto 1.9.37
typdiff 0.1.1
Command used:
typdiff -o diff.typ old.typ new.typ
typst compile diff.typ diff.pdf
Problem 1: Diff markup inserted inside label syntax
old.typ
= Sample
<sample-widget-anchor>
Body.
new.typ
= Sample
<sample-widget_anchor>
Body.
Generated output
#let diff-added(body) = {
set text(fill: rgb("#0000ff"))
underline(body)
}
#let diff-deleted(body) = {
set text(fill: rgb("#cc0000"))
strike(body)
}
= Sample
<sample#diff-deleted[-]#diff-added[_]widget-anchor>
Body.
Error
error: unclosed delimiter
<sample#diff-deleted[-]#diff-added[_]widget-anchor>
Expected / preferred generated output
#let diff-added(body) = {
set text(fill: rgb("#0000ff"))
underline(body)
}
#let diff-deleted(body) = {
set text(fill: rgb("#cc0000"))
strike(body)
}
= Sample
// label changed from <sample-widget-anchor>
<sample-widget_anchor>
Body.
At minimum, typdiff should choose one valid label and avoid inserting diff markup inside <...> label syntax.
Problem 2: Labels can be wrapped in #diff-added[...], breaking refs
old.typ
#set heading(numbering: "1.")
See #ref(<sample-anchor>, supplement: [Section]).
= Sample
<sample-anchor>
Alpha beta gamma delta epsilon zeta eta theta.
new.typ
#set heading(numbering: "1.")
See #ref(<sample-anchor>, supplement: [Section]).
= Sample
<sample-anchor>
Inserted paragraph before old text.
Alpha beta gamma delta changed epsilon zeta eta theta.
Generated output
#let diff-added(body) = {
set text(fill: rgb("#0000ff"))
underline(body)
}
#let diff-deleted(body) = {
set text(fill: rgb("#cc0000"))
strike(body)
}
#set heading(numbering: "1.")
See #ref(<sample-anchor>, supplement: [Section]).
= Sample
#diff-added[<sample-anchor>
Inserted paragraph before old text.]
#diff-deleted[\<sample-anchor>
]Alpha beta gamma delta #diff-added[changed ]epsilon zeta eta theta.
Error
warning: label `<sample-anchor>` is not attached to anything
error: label `<sample-anchor>` does not exist in the document
Expected / preferred generated output
#let diff-added(body) = {
set text(fill: rgb("#0000ff"))
underline(body)
}
#let diff-deleted(body) = {
set text(fill: rgb("#cc0000"))
strike(body)
}
#set heading(numbering: "1.")
See #ref(<sample-anchor>, supplement: [Section]).
= Sample
<sample-anchor>
#diff-added[Inserted paragraph before old text.]
Alpha beta gamma delta #diff-added[changed ]epsilon zeta eta theta.
Since the label is unchanged between versions, it should remain outside the diff wrapper and continue to attach to the heading.
Suggested behavior
- Treat
<label> as atomic Typst syntax.
- Never insert
#diff-added / #diff-deleted inside a label.
- Keep unchanged labels outside styled diff wrappers.
- Preserve label attachment to structural elements, especially headings, figures, tables, and equations.
- If labels differ, prefer a valid new label plus an optional comment, rather than visible/styled inline diff markup.
typdiffcan generate invalid Typst when diffing labels and cross-referencesSummary
I ran
typdiffon two Typst files generated by Quarto from different versions of the same report. The source files compiled individually, but the generated diff file did not compile with Typst.The main issue is that
typdiffappears to treat Typst labels as ordinary text. When labels are renamed, or when content immediately after a label changes, diff markup can be inserted inside label syntax or can wrap the label itself. This breaks downstream#ref(...)calls and sometimes produces invalid Typst syntax.I have a PR prepared for this issue and will submit it shortly.
Environment
typst 0.14.2quarto 1.9.37typdiff 0.1.1Command used:
Problem 1: Diff markup inserted inside label syntax
old.typnew.typGenerated output
Error
Expected / preferred generated output
At minimum,
typdiffshould choose one valid label and avoid inserting diff markup inside<...>label syntax.Problem 2: Labels can be wrapped in
#diff-added[...], breaking refsold.typnew.typGenerated output
Error
Expected / preferred generated output
Since the label is unchanged between versions, it should remain outside the diff wrapper and continue to attach to the heading.
Suggested behavior
<label>as atomic Typst syntax.#diff-added/#diff-deletedinside a label.