Writing the exchanges

reviewer(n, body)
groups a reviewer’s comments under a heading colored by their number.
editor(body)
same, for the editor’s own comments.
exchange(anchor, comment, response)
renders the quoted comment (in italics) and the response, with a header generated from the anchor.
#import "../../lib.typ": *

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

// Manuscript-side passages, matched by the exchanges below.
#added(<r1-1>)[A justification for the sample size.]
#added(<r1-2>)[A sensitivity analysis, added alongside it.]
#added(<e1>)[A clarified abstract word count.]

// Response-side exchanges -- a reviewer's block holds as many
// successive exchanges as needed, one heading for the whole group.
#reviewer(1)[
  #exchange(<r1-1>)[The sample size is not justified.][
    We agree and have added a justification.
  ]

  #exchange(<r1-2>)[A sensitivity analysis would strengthen this.][
    Added, using the same assumptions.
  ]
]

#editor[
  #exchange(<e1>)[Please double-check the abstract word count.][
    Confirmed within the journal's limit.
  ]
]

exchange checks, unconditionally, that its anchor matches a passage somewhere — an orphan comment answering nothing is always worth flagging, so this check has no require-exchange-style opt-out.

Co-authors: author, note

author(id, body)
groups one co-author’s own notes under a heading, colored and named the same way an anchor like <bob-3> already would be.
note(anchor, text)
a single block — no comment to quote, just the author’s own explanation. exchange(anchor, text), with two arguments instead of three, renders identically.
#import "../../lib.typ": *

#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)
#set-revisions(authors: (bob: "Bobby Fischer"))

// Manuscript-side passages.
#added(<bob-1>)[Bobby's own addition.]
#added(<bob-2>)[Bobby's second change.]

// Response-side notes -- no reviewer comment to quote, just an author
// explaining their own change.
#author("bob")[
  #note(<bob-1>)[Explaining why I made this change.]

  // exchange() with two arguments renders identically to note() above.
  #exchange(<bob-2>)[Explaining the second change, via exchange() instead.]
]

xcomment

xcomment(anchor)
a clickable cross-reference to another exchange, plus its page — “as already answered in comment R1-2.”
#import "../../lib.typ": *

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

#added(<r1-1>)[The scope was narrowed to three use cases.]
#added(<r1-2>)[A sensitivity analysis was added, consistent with the narrower scope.]

#reviewer(1)[
  #exchange(<r1-1>)[The scope seems too broad.][
    Narrowed as suggested.
  ]

  #exchange(<r1-2>)[A sensitivity analysis would help.][
    Added --- see also our response to #xcomment(<r1-1>).
  ]
]

Header wording: comment-word, change-word, term:

The noun in a header — “comment” for reviewer/editor, “change” for a co-author — is set-revisions(comment-word:, change-word:), global from that point on, or term: on one exchange/note call for just that occurrence:

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

#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)
#set-revisions(authors: (bob: "Bobby Fischer"))

#added(<r1-1>)[Default word: "comment".]
#added(<bob-1>)[Default word: "change".]
#added(<r2-1>)[Global override applies here.]
#added(<bob-2>)[Per-call override applies here.]

#reviewer(1)[
  #exchange(<r1-1>)[A remark.][The default reviewer word.]
]
#author("bob")[
  #note(<bob-1>)[The default author word.]
]

#set-revisions(comment-word: "remark", change-word: "revision")

#reviewer(2)[
  #exchange(<r2-1>)[Another remark.][Now under the global override --- "remark", not "comment".]
]

#author("bob")[
  #note(<bob-2>, term: "aside")[This one overrides the word for just this call.]
]

Cross-references: #xcomment(<r1-1>), #xcomment(<r2-1>), and #xcomment(<bob-2>).

xcomment echoes whichever word the exchange it points to actually used — reading it back from that exchange’s own data rather than recomputing it, so #xcomment(<bob-2>)‘s explicit term: "aside" stays “aside” no matter where it’s cited from. An unoverridden word, though, is resolved at the position where it’s read, not where it was written: <r1-1>‘s own exchange, near the top, renders “comment” — the default, in effect at that point — but #xcomment(<r1-1>) at the very bottom, after the global override, reads back “remark” for that same exchange. A global change to comment-word/change-word partway through a file affects every unoverridden reference read afterward, regardless of which word was showing where that exchange itself was originally written.

← Shortcutspinpoint →