4

I have large files that I am inputing the beginning of my texts that contain all my \newcommands. They are quite a few. Most of them will not be used in a given document. But which ones are used ?

Is it possible to write something to an auxiliary file saying if the \newcommand that was defined was used or not in the text.

Although not very useful, I am including a MWE

\documentclass[12pt]{article}
\newcommand{\titi}{Hemixos castanonotus}
\newcommand{\eag}{Haliaeetus leucocephalus}
\begin{document}
I my travels, I have seen many birds of type \titi.
\end{document}

An auxiliary file should then list the commands that were defined

Defined commands

\titi
\eag

Used commands

\titi

Unused commands

\eag

I am aware that packages define many \newcommands. But I would be interested by user-defined \newcommands only.

  • just delete all your definitions, and add the ones back if you get an undefined command error. – David Carlisle May 2 at 15:32
  • @DavidCarlisle OK. Will work for sure. Painful though. I was expecting a magic tracking macro. – Denis May 2 at 15:34
  • 1
    TeXnicCenter's Find in Files option can be used to list every occurrence of a macro name in a separate window frame. – John Kormylo May 2 at 16:33
10
\documentclass[12pt]{article}

\usepackage{etoolbox}

\makeatletter
 % This macro will contain all the tracked commands:
 \def\@mycommands{}
 % These macros enable and disable tracking the commands:
 \def\starttrackingnewcommands{%
     \let\old@@newcommand\@newcommand
     \def\@newcommand##1{%
         \expandafter\def\expandafter\@mycommands\expandafter{\@mycommands\oneof@mycommands##1}%
         \old@@newcommand##1%
     }%
 }
 \def\stoptrackingnewcommands{%
     \let\@newcommand\old@@newcommand
 }
 % These macros are used to write to the log file:
 \def\mycommand@used#1{\typeout{My command `\string #1' was used.}}
 \def\mycommand@unused#1{%
     \GenericWarning{(mycommands)}{LaTeX Warning:
         My command `\string #1' was not used!%
     }%
 }
 % These macros mark a command as used or unused:
 \def\mycommand@markunused#1{%
     \expandafter\gdef\csname mycommand@status@\expandafter\@gobble\string #1\endcsname{\mycommand@unused #1}%
     \pretocmd #1{\mycommand@markused #1}{}{\GenericWarning{(mycommands)}{Could not patch `\string #1' as unused!}}%
     \aftergroup\mycommand@markunused\aftergroup #1%
 }
 \def\mycommand@markused#1{%
     \expandafter\gdef\csname mycommand@status@\expandafter\@gobble\string #1\endcsname{\mycommand@used #1}%
     \patchcmd #1{\mycommand@markused #1}{}{}{\GenericWarning{(mycommands)}{Could not patch `\string #1' as used!}}%
     \aftergroup\mycommand@markused\aftergroup #1%
 }
 % This macro calls the appropriate logging macro for a command:
 \def\mycommand@evaluateuse#1{%
     \csname mycommand@status@\expandafter\@gobble\string#1\endcsname
 }
 % Mark all commands as unused at \begin{document}:
 \AtBeginDocument{%
     \let\oneof@mycommands\mycommand@markunused
     \@mycommands
 }
 % Evaluate the use of the commands at \end{document}:
 \AtEndDocument{%
     \let\oneof@mycommands\mycommand@evaluateuse
     {\let\mycommand@unused\@gobble% first, only the used commands
         \@mycommands
     }{\let\mycommand@used\@gobble% then, only the unused commands
         \@mycommands
     }%
 }
\makeatother

\starttrackingnewcommands
 \newcommand{\foo}{foo}
 \newcommand{\baz}{bar}
 \newcommand{\titi}{Hemixos castanonotus}
 \newcommand{\eag}{Haliaeetus leucocephalus}
\stoptrackingnewcommands

\begin{document}

I my travels, I have seen many birds of type \titi.

\end{document}

Towards the end of the log file you will find

My command `\titi' was used.

LaTeX Warning: My command `\foo' was not used! on input line 68.


LaTeX Warning: My command `\baz' was not used! on input line 68.


LaTeX Warning: My command `\eag' was not used! on input line 68.

Some Notes

This will break something if the first usage of one of your commands is used in a context like this:

\def\somethingwithargument#1{expansion}
\expandafter\somethingwithargument\oneofyourcommands

That is, if some command (\somethingwithargument) consumes the start of the expansion of one of your commands, the fact that you inserted something at the start of that command to keep track of its usage will break this code. I do not know of any safer way to do this, though.


I chose to format the message for unused commands as a warning and the message for a used command as just that. You can of course choose to do this differently (or even write to an entirely different file if you prefer this).


Since this is a rather invasive process (modifying all your commands temporarily), there may well be side effects i cannot think of right now. If you spot any, feel free to add them here.

In any case, you should not use this as a permanent addition to your preamble, only as a technique to get a quick overview over which commands you use.

  • Thanks indeed. Works fine here. Will wait a bit before I accept to see if anything new happens. Thanks for the detailed warnings: useful!! – Denis May 2 at 15:37
  • 1
    This is a really nice answer and I was not aware that this is possible. Do you think you could add an analogous recorder to \tikzset such that one can keep track of which pgf keys have been set? This might be useful for those who want to safely nest tikzpictures. – marmot May 3 at 3:15
  • 1
    @Denis: I just noticed that commands were not marked as used when used inside of groups. I added a fix you in the definitions of the marking macros. – schtandard May 3 at 8:43
  • @marmot: It should be possible, I think. What would be the requirements for such a tracking macro? What information should be tracked and how would you want to be able to retrieve it? – schtandard May 3 at 8:45
  • @schtandard Thanks. I have tested the new version. Works fine. – Denis May 3 at 9:41
1

Here is a way to display used commands, for unused commands I did not find a solution. Search and replace your commands adding a \display i.e replace \titi with \display\titi

         \documentclass[12pt]{article}
\newcount\commandnum
\commandnum=0
\newwrite\displayed
\immediate\openout\displayed=\jobname.dis
\def\displayedcommands#1{\vfill \section{#1} \vskip\baselineskip \immediate\closeout\displayed \input\jobname.dis}
\def\display#1{\advance\commandnum by 1 #1\textsuperscript{(\the\commandnum)\ }\immediate\write\displayed{\noindent #1 P.\thepage\ called by (\the\commandnum)\  \noexpand\string\noexpand#1'' \vskip0.2\baselineskip}}
\newcommand{\titi}{``Hemixos castanonotus''}
\newcommand{\eag}{``Haliaeetus leucocephalus''}
\begin{document}
\section{Test}
In my travels, I have seen many birds of type \display\titi
    In my travels, I have seen many birds of type \display\eag

In my travels, I have seen many birds of type \display\eag
\displayedcommands{Used Commands}
\end{document}
  • It is very much better to add a comment in the \newcommands instead of tracking them afterwards. – Matthias Borck-Elsner May 4 at 2:53

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.