Creating removable comment command without extra space

I'm trying to create a command we can use for comments in our document. During development, we want the comments to appear; for production, we want them to disappear. This is a common enough problem with many solutions.

I'm having an issue with LaTeX's tokenizer, though; if the command is surrounded by spaces, two spaces are emitted. I understand why that's happening, but none of the workarounds that I can find are any good for me. Here's a representative example.

\documentclass[letterpaper]{article}

\newif\ifnotes
\newcommand{\note}[1]{\ifnotes{#1}\fi}
\notesfalse
\newcommand{\nonotes}{\notesfalse}

\begin{document}
\pagestyle{empty}

Testing \note{X} testing testing.

\end{document}


Because \notesfalse has been invoked, the note should not (and does not) appear. But the spaces to the left and right of the command do appear, which is a problem for me.

I could modify the command to eat all of the spaces after it, but this isn't really the correct behavior either; if the command only has spaces following (as in the\note{...} text), there should still be an emitted space. While I know that one can use things like \unskip to delete preceding space, I'm at a loss to detect the preceding (and following) space so I can make an intelligent decision about whether it should stick around.

Does anyone have any suggestions for accomplishing this task?

• you could redefine \note to be {\unskip\ \ignorespaces} but you might also need to test whether you're in horizontal mode. (i don't remember whether the space-eating commands complain if the command is launched in vertical mode, and don't have time to experiment.) – barbara beeton Feb 16 '16 at 19:12

Here is a solution

\documentclass[letterpaper]{article}

\newif\ifnotes
\makeatletter
\newcommand{\note}[1]{\@bsphack\ifnotes{#1}\fi\@esphack}
\makeatother
\notesfalse
\newcommand{\nonotes}{\notesfalse}

\begin{document}
\pagestyle{empty}

Testing \note{X} testing testing.

Testing\note{X} testing testing.

Testing \note{X}testing testing.

Testing\note{X}testing testing.

\notestrue

Testing \note{X} testing testing.

Testing\note{X} testing testing.

Testing \note{X}testing testing.

Testing\note{X}testing testing.

\end{document}


• Not only a solution, the solution provided by LaTeX. – Manuel Feb 16 '16 at 19:20
• @Manuel yes you're right. – touhami Feb 16 '16 at 19:25
• Mmm… in fact \@bsphack\@esphack only should be in case \notesfalse. – Manuel Feb 16 '16 at 19:49
• @Manuel I am not sure I undestand why? – touhami Feb 16 '16 at 20:16
• I agree with @Manuel on this one; there's a subtlety that requires the hack to be avoided when notes are enabled. The reason is actually in your output: on the fifth line, the X should have spaces both before and after it. That said, \newcommand{\note}[1]{\ifnotes{#1}\else\@bsphack\@esphack\fi} is exactly what I wanted! Thanks! – tvynr Feb 16 '16 at 21:25