20

I want LaTeX to throw an error message if I use a command more than once in a file.

This is allowed

\documentclass{article}

\newcommand{\mycommand}{Test}

\begin{document}

\mycommand

\end{document}

This is should throw an error message

\documentclass{article}

\newcommand{\mycommand}{Test}

\begin{document}

\mycommand

\mycommand

\end{document}
22

Let the command redefine itself:

\documentclass{article}

\newcommand\myCommandOnce{%
  Test%
  \renewcommand\myCommandOnce{\GenericError{}
    {Error: \string\myCommandOnce\space used twice!}
    {Command was setup to be usable only once}{}}%
}
\newcommand{\mycommand}{Test}

\begin{document}

\myCommandOnce
\myCommandOnce

\mycommand
\mycommand

\end{document}

If you intend to create many of those commands, you can use the following. I created a small/stupid wrapper around \newcommand which inserts the redefining part after the rest of the specified definition. My code might not be well looking and I guess that more experienced LaTeX users would create it differently.

The name of the wrapper macro is \newonetimecommand and it accepts the same arguments like \newcommand plus an ! as its first optional argument. If the exclamation mark is given, the command is globally usable only once.

EDIT: The below code is changed from the original version, because the optional processor didn't work. As a result, only macros with arguments were possible. Now I use O{\use:c{c_novalue_tl}} instead of o. The result is just something which is very unlikely to be inserted and checked with a \str_if_eq:nnTF.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\cs_set_protected:Nn \my_optional_processor:n
  {
    \str_if_eq:nnTF { #1 } { \use:c { c_novalue_tl } }
      { \def \ProcessedArgument {} }
      { \def \ProcessedArgument { [#1] } }
  }
\ExplSyntaxOff
\newcommand*\MyStarredProcessor[1]{%
  \IfBooleanTF{#1}
    {\def\ProcessedArgument{*}}
    {\def\ProcessedArgument{}}}
\ExplSyntaxOn
\NewDocumentCommand{\newonetimecommand}
  { t!
    >{\MyStarredProcessor}s
    m
    >{\my_optional_processor:n}O{ \use:c { c_novalue_tl } }
    >{\my_optional_processor:n}+O{ \use:c { c_novalue_tl } }
    +m }{%
  \newcommand#2#3#4#5{%
    #6%
    \IfBooleanTF{#1}{\gdef}{\def}#3{%
      \GenericError{}
        {Error:~\string#3~used~twice!}
        {Command~was~setup~to~be~usable~only~once}{}%
    }%
  }}
\ExplSyntaxOff

\newonetimecommand*\myCommandOnce[1][]{Test%
  \if\relax\detokenize{#1}\relax\else\ #1\fi}
\newonetimecommand!*\myCommandReallyOnce[1][]{Test%
  \if\relax\detokenize{#1}\relax\else\ #1\fi}
\newonetimecommand\foo{Test}
\newcommand{\mycommand}{Test}

\begin{document}

{\myCommandOnce}
\myCommandOnce

{\myCommandReallyOnce}
%\myCommandReallyOnce

\mycommand
\mycommand

\foo


\end{document}
  • 1
    Yes, I do intend to create many of those commands. Great edit! – Sr. Schneider Jan 17 '18 at 19:58
  • 2
    @Sr.Schneider I made a very important edit to the code I provided in my edit. It is just one additional character (+) but is really important for the macro. If the + is not present, you can't specify macros which include a \par (or two consecutive newlines) in their definition. – Skillmon Jan 17 '18 at 22:28
16

You can use

\newcommand{\mycommand}{%
  \renewcommand{\mycommand}{\PackageError{mypkg}{two mycommands}{read the documentation}}%
  Test}

If you need the redefinition to be global, so that you may not have two \newcommand even in separate environments then

\newcommand{\mycommand}{%
   \gdef\mycommand{\PackageError{mypkg}{two mycommands}{read the documentation}}%
  Test}

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.