5

While further working on code for my answer to Different approach to literate programming for LaTeX, I am encountering a problem to which I am sure there is a very simple solution, but it completely escapes me.

The issue is: I want to be able to automatically index macro names, some of which will contain the @ character; hence, I need to preprocess them and substitute @ with "@ for makeindex to accept them. I have some code that works while in a listings environment but not when used in a normal environment or command (and I need them too). What's more, if I try to replace any normal letter, it works everywhere – it's only the @ that doesn't work.

So, I suspect the answer has got something to do with listings doing some wizardry on the catcodes, but I would like to find out what it is and how to reproduce it.

Here is the minimal (in which I am reproducing the actual structure of my code, in case the problem lies somewhere there):

\documentclass{article}

\usepackage{listings,etoolbox,xstring}

\makeatletter
\newcommand{\set@macro@type}[1]{\StrSubstitute{#1}{@}{"@}[\entryname]}
\newcommand{\processtexcs}[1]{\set@macro@type{#1}}
\newcommand{\maketexcs}[1]{\forcsvlist{\par\processtexcs{#1}}\entryname}
\makeatother

\lstnewenvironment{code}[1]
    {\maketexcs{#1}}
    {}
\newenvironment{notcode}[1]
    {\maketexcs{#1}}
    {}
\newcommand{\command}[1]{\maketexcs{#1}}

\begin{document}

\begin{code}{my@first@macro}
\end{code}

\begin{notcode}{my@second@macro}
\end{notcode}

\command{my@third@macro}

\end{document}

(Note that it all works if you replace the @ with y in \StrSubstitute.)

ienissei
  • 6,223

1 Answers1

3

It's your wizardry on the category codes. :)

You're defining the main macro in a context where @ has category code 11; but when you use it, \StrSubstitute can't find a category code 11 @. Use

\newcommand{\setmacrotype}[1]{\StrSubstitute{#1}{@}{"@}[\entryname]}
\newcommand{\processtexcs}[1]{\setmacrotype{#1}}
\newcommand{\maketexcs}[1]{\forcsvlist{\par\processtexcs{#1}}\entryname}

without any \makeatletter.

If you're in a .cls or .sty file and want to keep the internal name \set@macro@type, then

\begingroup\lccode`?=`@ \lowercase{\endgroup
  \newcommand{\set@macro@type}[1]{\StrSubstitute{#1}{?}{"?}[\entryname]}
}

will do. The \lowercase operation will transform ? (which has category code 12) into a category code 12 @ before processing \endgroup and \newcommand. Only character tokens are affected by \lowercase, so the list of possibly changed tokens is {[1]#}?" and only ? (under the default setting) will be "lowercased" according to the previous assignment.

egreg
  • 1,121,712
  • Thanks a million :) Since I am in a class file, the \makeatletter of the MWE wasn't technically wrong, but I altered the catcodes manually in \maketexcs and it all works fine now. Thanks. – ienissei Jun 28 '12 at 08:27
  • @ienissei I've added a way to do it without too many somersaults. – egreg Jun 28 '12 at 08:37