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
+500
\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. – user121799 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
1

Another Option that occurs to me off the top of my head, depending on the diagnostic purposes of your question... it may be of interest to know not just which commands were used or not, but rather how often they were used. To this end, consider following:

\documentclass[12pt]{article}
\usepackage{etoolbox}
\newcommand{\displayTracked}{}
\makeatletter

\newcommand{\trackedCommand}[2]{% This will define a tracked command.
    % Define the command as it was original intended.
    \expandafter\newcommand\csname#1\endcsname{#2 \refstepcounter{#1Count}}

    % Define a counter to track that specific command.
    \newcounter{#1Count}
    \setcounter{#1Count}{0}% Initialize it to zero as the command hasn't been used yet.

    % Update the display command to include the new command counter.
    \csappto{displayTracked}{The command #1 has been used \arabic{#1Count} times \\}
    }

\makeatother
\trackedCommand{titi}{Hemixos castanonotus}
\trackedCommand{eag}{Haliaeetus leucocephalus}
\trackedCommand{anothercommand}{This command won't be used at all, but still tracked.}
\begin{document}
I my travels, I have seen many birds of type \titi. What about \titi or \eag or just \titi ?

\displayTracked
\end{document}

enter image description here

Someone better at LaTeX than I might be able to get the command trackedCommand to take in a csname rather than the text name (ie allow you to define a command identically to the \newcommand syntax using \titi rather than titi), but I couldn't get a nice solution working in the time frame I was willing to work on this. It's worth a note that the \trackedCommand command will take in nonstandard command names (eg those with spaces, or arabic numerals); moreover you can decide if you want to track each command individually, rather than always tracking every command (in case there are commands you already know are heavily used or rarely used, and don't need to display the stats).

Moreover the \displayTracked is what gives you the output, so simply commenting out (or not including) that command will allow you to only get tracking info when desired. You could also use the command and pipe it out to an aux file or latex warning or whatever else you might want it for.

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.