Tracking Revisions in LaTeX
As a PhD student, an essential part of my job is sending drafts to my advisor for his feedback.
Because his time is limited, it is crucial that I direct his attention to the parts of the document that I modified.
A useful tool for tracking changes is the changes
LaTeX package.
To import the package, add \usepackage{changes}
to your document’s preamble.
The changes
package defines four types of annotations: \added
, \deleted
, \replaced
, and \comment
and also imports the \todo
macro from the todo
package.
Example:
Here is \added{added}, \deleted{deleted} and \replaced{replaced}{replaysed} text. \comment{Maybe I shouldn't have written this?} \todo[inline]{To-do: Write something worthwhile.}
Output:
Workflow
In order for annotations to be useful they must be up-to-date. This raises the question of when to remove annotations. The best workflow depends on the way your reviewer gives feedback. If your reviewer will read the entire document, then you can delete annotations immediately after sending them a draft. In my case, however, my advisor only reads a portion of each draft I send, so I leave annotations until he has given feedback. To this motivates the following workflow:
- Annotate each change to the PDF.
- Compile PDF and share with reviewer.
- Commit changes to the source code into Git or another source control management software. (If you aren’t tracking the changes to your source code, then start!)
- Wait for reviewer to give comments or continue editing the document (as in step 1).
Once the reviewer gives you comments:
- Commit current version to Git.
- Delete the annotations only from the sections of the document that were reviewed.
- Commit the new version, without the deleted annotations.
Annotating Blocks of Text
When annotating a sentence or more, I format my LaTeX code with \added{
and }
on their own lines.
Including %
immediately after \added{
and after }
prevents LaTeX from inserting extra spaces (LaTeX treats a new line in the code the same as a space).
\added{% Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. }% End \added block
If you use Visual Studio Code, see below for snippets that will wrap selected text in annotation commands.
The commands \added
, \deleted
, and \replaced
cannot contain a paragraph break.
This precludes empty lines, such as
\added{ % Paragraph 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. % Paragraph 2 (Causes error!) Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. }
To mark multiple paragraphs as changed, I define a new color called added
using the xcolor
package
\usepackage{xcolor} \colorlet{added}{blue!80!black}
Then, add \color{added}
before a multiple paragraph change, and add \color{black}
afterward.
\color{added} % Paragraph 1 (Added) Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. % Paragraph 2 (Added) Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. \color{black} % Paragraph 3 (No change) Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Output:
Package Configuration
There are various package options. For my documents, I use the following:
\usepackage[ % import "changes" package % If any of the changes commands are already defined, then the option "commandnameprefix=ifneeded" % tells changes to append "ch" to the name of the changes command in order to avoid a name collision. % Commonly, "\comment" will be changed to "\chcomment". commandnameprefix=ifneeded, % Changes imports the "todo" package. The following options are passed to the "todo" package. todonotes={colorinlistoftodos, prependcaption, textsize=small, backgroundcolor=orange!10, textcolor=black, linecolor=orange, bordercolor=orange} % % draft, % <- enable line to show annotations regardless of the document being in 'final' mode. % final, % <- enable line to hide annotations regardless of the document being in 'draft' mode. ]{changes}
For comments in the margin, the margin size for many document classes is too narrow, so it is necessary to adjust it.
One way to this is with the geometry
package.
In the following snippet, we also use the ifdraft
package so that our changes to the margins only apply in draft mode.
% Create \ifdraft{}{} conditional % that switches based on whether "draft" % is passed to document class. \usepackage{ifdraft} \ifdraft{ % Adjust spacing to fit margin notes. \usepackage[inner=20mm, outer=40mm, marginparwidth=34mm]{geometry} }{}
My full LaTeX configuration file is available here.
Resolve Name Conflict For \comment
Command
There are several packages that define a \comment
command that would clash with the one defined by changes
.
If the prependcaption
is included in the options for changes
, then \comment
is automatically renamed to \chcomment
and a warning is shown.
I would prefer to use \comment
for the changes
command, however.
To do this, you can redefine the existing \comment
command.
If comment
is an environment, as is defined by the verbatim
package, then you must redefine both \comment
and \endcomment
, prior to importing changes
, as follows:
% Redefine "comment" environment (from "verbatim" package) % to "commentsection" so that \comments{} can be defined % by the `changes` package. \makeatletter \let\commentsection\comment \let\endcommentsection\endcomment \let\comment\@undefined \let\endcomment\@undefined \makeatother
Visual Studio Configuration
When writing LaTeX with Visual Studio Code, you can define snippets that are automatically inserted when you type particular text.
To set up snippets, type CTRL+SHIFT+P
, type Preferences: Configure User Snippets
, and select latex.json
.
Add the following code to latex.json
:
{ "Added":{ "prefix": ["\\added"], "body": [ "\\added{$TM_SELECTED_TEXT$1}$0" ] }, "Added Block":{ "prefix": ["\\added%", "\\addedblock"], "body": [ "\\added{%", "\t$TM_SELECTED_TEXT$0", "}% End \\added block", "" // Ensure there is a new line at end ] }, "Deleted":{ "prefix": ["\\deleted"], "body": [ "\\deleted{$TM_SELECTED_TEXT$1}$0" ] }, "Deleted Block":{ "prefix": ["\\deleted%", "\\deletedblock"], "body": [ "\\deleted{%", "\t$TM_SELECTED_TEXT$0", "}% End \\deleted block", "" // Ensure there is a new line at end ] }, "Replaced":{ "prefix": ["\\replaced"], "body": [ "\\replaced{$TM_SELECTED_TEXT$1}{$TM_SELECTED_TEXT}$0" ] }, "Replaced Block":{ "prefix": ["\\replaced%", "\\replacedblock"], "body": [ "\\replaced{% New Text", "\t$TM_SELECTED_TEXT$0", "}{% Old Text", "\t$TM_SELECTED_TEXT", "}% End \\replaced block", "" // Ensure there is a new line at end ] } }
For each command \added
, \deleted
, and \replaced
, there are two versions of snippets an “inline” version and a “block” version.
To use the block version append %
or block
.
For example, to add a \replaced
block:
- Select the text you are replacing.
- Type
\replaced%
or\replacedblock
. The selected text will temporarily disappear as you type. - Select “Replaced Block” from the drop-down menu. At this point, the text you had selected reappears in both arguments of
\replaced
. - Modify the first argument to the new version.
I find the \replaced
block snippet particularly useful because the comments % New Text
and % Old Text
remind me of the order of the arguments, which I always forget.
COMMENTS
You can use your Mastodon account to comment on this article by replying to the associated post.