How to make @ a letter within a macro
The key is to have the \makeatletter
invoked before an argument hits the macro. Thus, here, I move the argument absorption to \whatisaux
, after the \makeatletter
is invoked by \whatis
.
\documentclass{article}
\makeatletter
\def\whatis{\makeatletter\whatisaux}
\def\whatisaux#1{{\ttfamily\string#1: \meaning#1}\makeatother}
\makeatother
\begin{document}
\whatis\MacroNameWith@InIt
\end{document}
A much simpler way to avoid the problem for the specific use case is to change the input syntax not to require the \
\def\whatis#1{\texttt{#1: \expandafter\meaning\csname #1\endcsname}}
\whatis{MacroNameWith@InIt}
Comments on the original approach:
Steven shows how to do what you ask but note that the resulting command is like \verb
and can not be used in the argument of any other macro.
catcode changes like \makeatletter
(which is \catcode``\@=11
) affect the catcode table which is only used to convert input characters into tokens. By the time you are in the replacement text of a macro the argument passed as #1
has already been tokenized so the catcode change has no effect (unless you use \scantokens
which is the same as writing it out to a file and then reading the characters back in, but uses an internal buffer for efficiency).
\def\whatis#1{{\tt % use \ttfamily in LaTeX
\string#1:
\begingroup\escapechar=-1 \expandafter\endgroup
\expandafter\meaning\csname\string#1\endcsname
}}
\catcode`@=11 % \makeatletter in LaTeX
\def\MacroNameWith@InIt#1{whatever}
\catcode`@=12 % \makeatother in LaTeX
\whatis{\sqrt}
\whatis{\MacroNameWith@InIt}% <-- braces are necessary!
\bye
You can easily turn this into LaTeX, if you prefer.
If you are sure the \whatis
macro is never the argument to another command, you can do (LaTeX assumed)
\newcommand\whatis{\begingroup\makeatletter\whatisaux}
\newcommand\whatisaux[1]{\ttfamily\string#1: \meaning#1\endgroup}