Styling marks: set-revisions

Call set-revisions once, before any passage, to change how tracked marks look. Takes effect for everything after the call — a document can use different styles in different sections.

#set-revisions(
  style: "inline",           // "inline" | "bar" | "none"
  color: auto,                // auto, or a fixed color for every mark
  add-style: underline,       // body -> content
  del-style: (smart default), // body -> content
  highlight-passage: false,   // tint the whole passage's background
  show-anchor: true,          // show [R1-2] at the end of the passage
  del-numbering: "none",      // "none" | "keep"
)

style

#import "../../lib.typ": *

#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)

*style: "inline" (default)*
#passage[This whole sentence is marked #add[with an inline addition] in the flow of text.]

#v(0.8em)
#set-revisions(style: "bar")
*style: "bar"*
#passage[This whole sentence is marked #add[with an addition] under the bar style instead.]

#v(0.8em)
#set-revisions(style: "none")
*style: "none"*
#passage[This whole sentence is marked #add[with an addition] but renders exactly like the clean version — a layout sanity check.]

"inline" (the default) underlines additions and strikes deletions in the flow of text. "bar" keeps that same underline/strike on the marks themselves and adds a colored vertical bar to the left of the whole passage’s block — best when a passage forms its own block, not text mid-paragraph. "none" turns underline/strike off entirely, rendering exactly like the clean version even in the tracked compile — a layout sanity check, to confirm marking hasn’t shifted anything.

color

#import "../../lib.typ": *

#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)
#set-revisions(require-exchange: false)

*color: auto (default) — one color per reviewer*
#passage(<r1-1>)[Reviewer 1's #add[addition].]
#passage(<r2-1>)[Reviewer 2's #add[addition] — a different color, automatically.]

#v(0.8em)
#set-revisions(color: rgb("#7a7a7a"))
*color: a fixed value — overrides per-reviewer colors*
#passage(<r1-1>)[Reviewer 1's #add[addition], now in the fixed color.]
#passage(<r2-1>)[Reviewer 2's #add[addition], the same fixed color, not a different one.]

auto (the default) colors each mark by its anchor — one color per reviewer, a separate palette per co-author, as introduced in the previous chapter. A fixed color — rgb(...), a named color — overrides that entirely: every mark gets the same color, regardless of anchor.

add-style / del-style

#import "../../lib.typ": *

#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)

*add-style: underline, del-style: default (strikes plain text like this)*
#passage[Some text with #add[an addition] and #del[a deletion].]

#v(0.8em)
#let boxed-mark(body) = box(stroke: 0.6pt, inset: (x: 2pt), radius: 1.5pt, body)
#set-revisions(add-style: boxed-mark, del-style: boxed-mark)
*add-style/del-style: a custom `body -> content` function*
#passage[Some text with #add[an addition] and #del[a deletion], both boxed instead of underlined/struck. The reviewer color still applies on top --- it's added separately by the passage, not by this function.]

Both take a single body -> content function — not (body, color): the color is applied afterward, wrapped around whatever this function returns, so a custom style only needs to decide the visual treatment (box, highlight, …), never the color itself.

add-style’s default is plain underline. del-style’s default is smarter, because strike() never decorates a real math glyph or a figure’s drawing — only literal text: ordinary text still gets struck, but a block equation, a figure, or a table gets a diagonal cross instead (figures/tables also keep their caption struck natively, since a caption is real text), and an inline equation gets a line straight through it rather than a full cross. A custom function passed here always replaces this default outright for every kind of content, the same way it would replace plain strike.

Deletions are also automatically desaturated relative to additions — a muted, darker version of the same reviewer’s color, not merely “the same color with a different decoration”. This matters specifically because the strike/cross/line above is the only other signal on math or on a figure’s drawing: without a color difference, an added and a removed equation would otherwise look identical at a glance. This isn’t a del-style option — it always applies, on top of whatever del-style renders.

highlight-passage

#import "../../lib.typ": *

#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)

*highlight-passage: false (default)*
#passage[Only the #add[actually changed words] are tinted --- the rest of the sentence stays plain black text.]

#v(0.8em)
#set-revisions(highlight-passage: true)
*highlight-passage: true*
#passage[The whole passage's background is lightly tinted, not just #add[the changed words] --- useful when a reviewer asked for a full rewrite.]

false (the default) tints only the marks themselves — a passage where one word changed doesn’t light up entirely. true tints the whole passage’s background lightly, useful when a reviewer asked for a full rewrite and marking only the changed words would understate how much moved.

show-anchor

#import "../../lib.typ": *

#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)
#set-revisions(require-exchange: false)

*show-anchor: true (default)*
#passage(<r1-2>)[The #add[anchor tag] appears in superscript at the end of the passage.]

#v(0.8em)
#set-revisions(show-anchor: false)
*show-anchor: false*
#passage(<r1-2>)[No tag at the end of #add[the passage] anymore --- still colored by reviewer, just no visible label.]

The [R1-2] superscript at the end of a marked passage — what reviewers use most in practice to find their own comment in the manuscript without cross-referencing the letter. false removes the tag; the passage is still colored.

del-numbering

A figure, table, equation, or heading that gets deleted still exists as a real element in the tracked manuscript — and by default would still consume a number, shifting every one of its kind that comes after it out of sync with the clean version. del-numbering: "none" (the default) keeps the deleted element’s own real number visible, struck through, but resets the count right after it, so the next real one of that kind keeps the same number in both versions:

#import "../../lib.typ": *

#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)
#set math.equation(numbering: "(1)")
#set heading(numbering: "1.1.")
#set-revisions(require-exchange: false)

*del-numbering: "none" (default)*

= Methods

#figure(rect(width: 2cm, height: 1cm, fill: luma(230)), caption: [Kept figure.]) <fig-a>
#passage(<x1>)[
  #del[#figure(rect(width: 2cm, height: 1cm, fill: luma(230)), caption: [Removed figure.]) <fig-b>]
]
#figure(rect(width: 2cm, height: 1cm, fill: luma(230)), caption: [Next figure --- same number as in the clean version.]) <fig-c>

#figure(table(columns: 2, [Kept], [table]), caption: [Kept table.]) <tab-a>
#passage(<x2>)[
  #del[#figure(table(columns: 2, [Removed], [table]), caption: [Removed table.]) <tab-b>]
]
#figure(table(columns: 2, [Next], [table]), caption: [Next table --- same number as in the clean version.]) <tab-c>

Kept equation. $ a = b $ <eq-a-kept>
#passage(<x3>)[
  #del[$ E = m c^2 $ <eq-a>]
]
Next equation --- same number as in the clean version. $ c = d $ <eq-c-kept>

== Kept subsection.
#passage(<x7>)[
  #del[
    == Removed subsection.
    Removed content.
  ]
]
== Next subsection --- same number as in the clean version.

Tracked:

The clean compile of that same source, for comparison — the numbers match:

"keep" lets a deleted element consume a number like anything else — rarely what you want (the whole point of del-numbering: "none" above is that a reviewer reading the tracked manuscript and citing “Figure 3” is citing the same Figure 3 that exists in the clean version you submit), but available:

#import "../../lib.typ": *

#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)
#set math.equation(numbering: "(1)")
#set heading(numbering: "1.1.")
#set-revisions(require-exchange: false, del-numbering: "keep")

*del-numbering: "keep"*

= Methods

#figure(rect(width: 2cm, height: 1cm, fill: luma(230)), caption: [Kept figure.]) <fig-d>
#passage(<x4>)[
  #del[#figure(rect(width: 2cm, height: 1cm, fill: luma(230)), caption: [Removed figure --- still consumes a number here.]) <fig-e>]
]
#figure(rect(width: 2cm, height: 1cm, fill: luma(230)), caption: [Next figure --- number has shifted, diverging from the clean version.]) <fig-f>

#figure(table(columns: 2, [Kept], [table]), caption: [Kept table.]) <tab-d>
#passage(<x5>)[
  #del[#figure(table(columns: 2, [Removed], [table]), caption: [Removed table --- still consumes a number here.]) <tab-e>]
]
#figure(table(columns: 2, [Next], [table]), caption: [Next table --- number has shifted, diverging from the clean version.]) <tab-f>

Kept equation. $ a = b $ <eq-a-kept-b>
#passage(<x6>)[
  #del[$ E = m c^2 $ <eq-b>]
]
Next equation --- number has shifted, diverging from the clean version. $ c = d $ <eq-c-kept-b>

== Kept subsection.
#passage(<x8>)[
  #del[
    == Removed subsection --- still consumes a number here.
    Removed content.
  ]
]
== Next subsection --- number has shifted, diverging from the clean version.

Tracked:

The clean compile of that same source — watch the third and fifth figures’ numbers diverge from the tracked version above:

Both examples also include a table, an equation, and a heading, deleted the same way, worth looking at closely: the table’s cells and caption are struck through, same as ordinary text, and its diagonal cross covers the drawing itself. The equation gets the same diagonal cross rather than a strikethrough (see del-style above for why), and the heading is struck like any other text. All three keep their own number visible, frozen under del-numbering: "none" so whatever comes after them stays in sync with the clean version, or consume a real number under "keep", exactly the same freeze/consume distinction shown above for figures.

This works the same way under a template that recomputes its own figure or table numbers via a custom show rule — @preview/charged-ieee, for instance — since the underlying counter it reads is the same one being frozen here.

← AnchorsShortcuts →