Automatic deletion of unused macros
Ok, so this is a first attempt. It has some problems with commands with arguments which can be circumvented, although not provided here. The below will work for most cases.
Gurus, I encourage you to outline where it could be improved if you feel!
Ok, so basically you want to save every time you call the command. This lead me to require that you need to call a \savecommand
when the command is first encountered. This can be achieved several ways. I have chosen to make you require it to be in the declaration of the command. It could also be added afterwards.
This means something like the following on all commands you define:
\newcommand\bfA{\savecommand\bfA%
\mathbf{A}%
}
Then you need to define your \savecommand
. One way to make this very easy for you is to save the command definition in a file. This means something like this:
\makeatletter
% Creta fID for writing the commands
\newwrite\command@file
% Save the commands in `mycommands.tex` (change to your liking)
\immediate\openout\command@file=mycommands.tex
% Define the actual saving command:
\def\savecommand#1{%
% This defines \tmp@ to the contents of the command by gobbling:
% \savecommand#1
\edef\tmp@{\expandafter\expandafter\expandafter\unexpanded\expandafter\expandafter\expandafter{\expandafter\@gobbletwo#1}}
% Check whether the command has been written
\expandafter\ifx\csname command@write\string#1\endcsname\relax\relax%
% Define variable which ensures that the command does not get written upon subsequent calls.
\expandafter\gdef\csname command@write\string#1\endcsname{Written}%
% Write the definition to the file, by the use of detokenize and zap space
\immediate\write\command@file{\string\def\string#1\string{\expandafter\expandafter\expandafter\zap@space\expandafter\detokenize\expandafter{\tmp@} \@empty\string}}%
\fi%
}
\makeatother
Ok, so this will actually save the command in the file mycommands.tex
. As well as check whether it is already written.
There is one problem in the above. And that is the use of \detokenize
(which is required if multiple macros are contained in the macro). It inserts a space after each macro. Thus
\newcommand\bfA{\mathbf{A}}
\expandafter\detokenize\expandafter{\bfA} == \mathbf {A}
Thus zap space is inserted which removes all space up until \@empty
. This means that if you define commands with spaces you have to use the macro \space
instead.
Ok, so a minimal full example:
\documentclass{article}
\usepackage{amsmath}
\begin{document}
\makeatletter
\newwrite\command@file
\immediate\openout\command@file=mycommands.tex
\def\savecommand#1{%
\edef\tmp@{\expandafter\expandafter\expandafter\unexpanded\expandafter\expandafter\expandafter{\expandafter\@gobbletwo#1}}
\expandafter\ifx\csname command@write\string#1\endcsname\relax\relax%
\expandafter\gdef\csname command@write\string#1\endcsname{Written}%
\immediate\write\command@file{\string\newcommand\string#1\string{\expandafter\expandafter\expandafter\zap@space\expandafter\detokenize\expandafter{\tmp@} \@empty\string}}%
\fi%
}
\makeatother
\newcommand\bfE{\savecommand\bfE%
\mathbf{E}%
}
\newcommand\bfA{\savecommand\bfA%
\mathbf{A}
}
\newcommand\with{\savecommand\with%
\mathbf{A}\text{\space}\mathbf{B}%
}
Use bfE:
$\bfE$
Use bfE again:
$\bfE$
Test with space:
$\with$
\makeatletter
% Close the file
\immediate\closeout\command@file
\makeatother
\end{document}
This will create an output file mycommands.tex
with the contents:
\newcommand\bfE{\mathbf{E}}
\newcommand\with{\mathbf{A}\text{\space}\mathbf{B}}
It should be noted that this does not work for commands with arguments. I am not too sure how to do this without adding loads of code. But this is at least a starting ground for the majority of single contained commands.
Note that \bfA
is not added to the file as it was never called, neither is the command \bfE
defined twice as it was caught.
Edit
If you wish to do the commands by other means you can do like the following:
\newcommand\mynewcommand[2]{%
\newcommand#1{\savecommand#1#2}%
}
% Or fully independent on the \savecommand:
\newcommand\mynewcommand[2]{%
\expandafter\gdef\csname command@write\string#1\endcsname{%
\immediate\write\command@file{%
\string\newcommand\string#1\string{\expandafter\expandafter\expandafter\zap@space\expandafter\detokenize\expandafter{#2} \@empty\string}%
}%
\expandafter\gdef\csname command@write\string#1\endcsname{\relax}%
}%
\newcommand#1{\csname command@write\string#1\endcsname#2}%
}
This will let you do:
\mynewcommand\bfE{\mathbf{E}}
and do exactly the same. Still cannot handle several arguments. :(