6

I'm writing a package that uses both changes (v3.1.2) and comment (v3.8), and I'd like to expose their functionality to consumers of my package without having to modify either one's interface.

The problem is that both changes.sty and comment.sty define \comment. Hence

\documentclass{article}
\usepackage{comment}
\usepackage{changes}
\begin{document}\end{document}

throws the error

Command \comment already defined.

I understand this can be fixed using savesym by (essentially) modifying changes.sty's interface, e.g.

\documentclass{article}
\usepackage{savesym}

\usepackage{changes}
\savesymbol{comment} % rename \comment -> \origcomment
\usepackage{comment}

\begin{document}
\origcomment{pdf comment using 'changes.sty'}
\begin{comment}
code comment using 'comment.sty'
\end{comment}
\end{document}

Alternatively, comment.sty provides \excludecomment for defining custom comment environments, e.g.

\documentclass{article}
\usepackage{savesym}

\usepackage{comment}
\savesymbol{comment}
\excludecomment{mycomment}
\usepackage{changes}

\begin{document}
\comment{pdf comment using 'changes.sty'}
\begin{mycomment}
code comment using 'comment.sty'
\end{mycomment}
\end{document}

but changes.sty breaks the default comment environment.

Is it possible to build a layer in my package which mediates between changes.sty's \comment command and comment.sty's comment environment? The aim is to expose the original interface of each to a consumer of my package.


The two clashing definitions are as follows:

% changes.sty line 791
\newcommand{\comment}[2][\@empty]{%
\setkeys{Changes@comment}{#1}%
\Changes@output%
{comment}%
{\Changes@comment@id}%
{}%
{}%
{#2}%
{\changescommentname}%
{#2}%
}
% comment.sty line 241
\def\excludecomment
 #1{\message{Excluding comment '#1'}%
    \csarg\def{#1}{\endgroup \message{Excluding '#1' comment.}%
        \begingroup
           \DefaultCutFileName \def\ProcessCutFile{}%
           \def\ThisComment####1{}\ProcessComment{#1}}%
    \csarg\def{After#1Comment}{\CloseAndInputCutFile \endgroup}
    \CommentEndDef{#1}}
% ...
% line 292
\excludecomment{comment}
0
5

You can via \let save both the \comment-macro which underlies the comment-environment of the comment package and the \comment-macro which comes with the changes-package.

Then you can define your own \comment-macro which "looks" at the definition of \@currenvir.

If \@currenvir = comment, then executing \comment imples calling the macro which underlies the comment-environment.
Otherwise executing \comment implies calling the macro which comes from the changes-package.

Be aware that with the following example I said \includecomment{comment} so that the content of comment-environments results in visual output.

\documentclass{article}

\makeatletter
\newcommand*\UD@CommentName{comment}%
\newcommand\UDsavedcommentenvironment{}%
\newcommand\UDsavedcommentmacro{}%
\usepackage{changes}[2019/01/26 v3.1.2]
\let\UDsavedcommentmacro=\comment
\let\comment=\relax
\usepackage{comment}%[2016/07/16 v3.8]
\includecomment{comment}%
%\excludecomment{comment}%
\let\UDsavedcommentenvironment=\comment
\let\comment=\relax
\newcommand\comment{%
  \ifx\@currenvir\UD@CommentName
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\UDsavedcommentenvironment}{\UDsavedcommentmacro}%
}%
\makeatother

\begin{document}
\null
\comment{A pdf comment using `changes.sty'.}%
\begin{comment}
A code comment using `comment.sty'.
\end{comment}
\comment{Another pdf comment using `changes.sty'.}%
\begin{comment}
Another code comment using `comment.sty'.
\end{comment}
Some text.
\end{document}

enter image description here

2
  • This has all the basic elements I was looking for. Just one question: why the first 3 \newcommands? Is it to ensure you're not clobbering previously-defined commands, a stylistic choice, or something deeper? – wfsch Apr 11 '19 at 19:11
  • You are right: The \newcommand for \UD@CommentName just defines the macro as it is needed.The second and the third \newcommand are to ensure that an error is raised in case the macros \UDsavedcommentenvironment and \UDsavedcommentmacro are already defined. As the likelihood for a macro whose name starts with \UD... already being defined is low and as one could as well use \@ifdefinable for testing, you can take this for a "stylistic" thing. ;-) – Ulrich Diez Apr 11 '19 at 20:23
2

Here's my solution based on @Ulrich Diez's answer, the main differences being the use of \@undefined instead of \relax and a simpler if-then-else statement:

\documentclass{article}

\makeatletter

\usepackage{comment}
\let\wfs@comment@comment\comment
\let\comment\@undefined

\usepackage{changes}
\let\wfs@changes@comment\comment
\let\comment\@undefined

\newcommand\comment{%
    \ifthenelse{\equal{\@currenvir}{comment}}
    {\wfs@comment@comment}
    {\wfs@changes@comment}%
}

\makeatother

\begin{document}
\comment{pdf comment 1}
\begin{comment}
code comment 1
\end{comment}
\comment{pdf comment 2}
\begin{comment}
code comment 2
\end{comment}
\end{document}

Then I copied the preamble into my package, removed \makeatletter and \makeatother, and replaced \usepackage -> \RequirePackage.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.