# What precautions must I take when using custom index commands with memoir?

I'm trying to write my own indexing front-end commands to do things such as highlighting the primary reference, but something seems to be wrong with the sorting. Here's my MWE:

\documentclass[a4paper,12pt]{memoir}
\usepackage[x11names]{xcolor}
\colorlet{indexmain}{Red3}
\newcommand{\ixxmain}[1]{{\bfseries\color{indexmain}#1}}
\newcommand{\ixmain}[1]{\index{#1|ixxmain}}
\newcommand{\id}{\textsc{id}}
\makeindex
\begin{document}
Hallo! I need this to get some output on pass 1.
\ixmain{session id@session \id{}}
\index{session id@session \id{}!structure}
\ixmain{session id@session \id{}!uniqueness}
\backmatter
\printindex
\end{document}


which produces this:

and on inspecting the .idx file the thot plickens:

\indexentry{session id@session \textsc  {id}{}|ixxmain}{1}
\indexentry{session id@session \id{}!structure}{1}
\indexentry{session id@session \textsc  {id}{}!uniqueness|ixxmain}{1}


My questions are:

1. How do I stop \id{} from being expanded here?
2. Given that, in any case, the first-level keys are the same (I think), what is makeindex doing (the .ind file reflects the output, of course)?

Clarification: I've tried running makeindex both with and without the -c parameter.

-
You may find \string helpful here. I don't have time to test, but it will help with how the index commands add 'space' between font commands/declarations and their argument. Try using it before the \id in the \ixmain commands ... and not in the \id command as I previously (stupidly) suggested. – jon Aug 5 '12 at 21:38
@jon: Thanks, but that seems to interfere with plain \index entries – Brent.Longborough Aug 5 '12 at 21:47
@jon: Followed your new suggestion, but it still appears to be getting expanded early – Brent.Longborough Aug 5 '12 at 21:56
I should also mention: the spacing alone in the .idx will cause different entries: session \textsc{id} will be indexed separately from session \textsc {id}. – jon Aug 5 '12 at 23:02

\index reads its argument semi-verbatim, which is why the basic \index prevents \id expanding, but within a macro the catcode changes have no effect.

These days you can simplify the expansion control using \detokenize something like

\documentclass[a4paper,12pt]{memoir}
\usepackage[x11names]{xcolor}
\colorlet{indexmain}{Red3}
\newcommand{\ixxmain}[1]{{\bfseries\color{indexmain}#1}}
\newcommand{\ixmain}[1]{\index{#1|ixxmain}}
\newcommand{\id}{\textsc{id}}
\AtBeginDocument{%
\let\oldindex\index
\def\index#1{\oldindex{\detokenize{#1}}}%
}
\makeindex
\begin{document}
Hallo! I need this to get some output on pass 1.
\ixmain{session id@session \id{}}
\index{session id@session \id{}!structure}
\ixmain{session id@session \id{}!uniqueness}
\backmatter
\printindex
\end{document}


which produces

-
Well that is a much more global solution. Is there anything that \detokenize might cause makeindex to choke on or screw up? – jon Aug 5 '12 at 23:11
It's probably OK, \index uses a "classic tex" verbatim mechanism so basically doesn't work if the argument contains macros and is used within the argument of another command, the e-tex detokenize is designed to make things safe without the restrictions in catcode changes. Of course someone somewhere wil have a document that relies on \index not working as designed, and having macros expand, but in general \detokenize is I think closer to the original intent. – David Carlisle Aug 5 '12 at 23:18
Ah, OK, thanks. This will certainly simplify the construction of my indices, which tend to have a lot of italic entries and so forth (which makes indexing even more annoying to do than it already is). – jon Aug 5 '12 at 23:23
Thanks a lot, David, that works beautifully (though I would hardly have expected less :)). One supplementary question: why does one need the \AtBeginDocument, rather than putting it in-line? Is that just in case it turns into a package, or is there some deeper TeXZeN involved? – Brent.Longborough Aug 5 '12 at 23:32
it didn't work inline (visibly \index definition hadn't changed) so I just guessed memoir or something else loaded was delaying the definition so I delayed the redefinition:-) – David Carlisle Aug 6 '12 at 0:03

(This was too long for a comment.)

If I write the your index commands in the following way:

\ixmain{session id@session \string\id{}}
\index{session id@session \id{}!structure}
\ixmain{session id@session \string\id{}!uniquenes}


then the .idx file looks like this:

\indexentry{session id@session \id{}|ixxmain}{1}
\indexentry{session id@session \id{}!structure}{1}
\indexentry{session id@session \id{}!uniqueness|ixxmain}{1}


I'm not sure if that's what you're hoping for, however.

\documentclass[a4paper,12pt]{memoir}
\usepackage[x11names]{xcolor}
\colorlet{indexmain{Red3}
\newcommand{\ixxmain}[1]{{\bfseries\color{indexmain}#1}}
\newcommand{\ixmain}[1]{\index{#1|ixxmain}}
\newcommand{\id}{\textsc{id}}
\newcommand{\sessionid}[1][]{session \id\ixmain{session id@session \string\id{}#1}}%

%% to compare the difference between using \string or not
%% independent of \ixxmain's fontifying effects:
\newcommand{\sessionidd}[1][]{session \id\index{session id@session \string\id{}#1}}%
%% uncomment this one to see the difference:
% \renewcommand{\sessionidd}[1][]{session \id\index{session id@session \id{}#1}}%
\makeindex
\begin{document}
Hallo! I need this to get some output on pass1.
What about the \sessionid[!not unique]
More about the \sessionid?!
\newpage
\ixmain{session id@session \string\id{}}
\index{session id@session \id{}!structure}
\ixmain{session id@session \string\id{}!uniqueness}
\backmatter
\printindex
\end{document}

-
Yes, not quite what I was looking for - writing \string is about the same amount of work as writing |ixxmain (and the latter can be shortened. Thanks anyway. – Brent.Longborough Aug 5 '12 at 22:02
No, the index is much more diversified than that - those are all the "session ID" entries; I stripped out a zillion others to make the MWE. – Brent.Longborough Aug 5 '12 at 22:06
Yes. Many thanks for your effort and thoughts. – Brent.Longborough Aug 5 '12 at 22:17
No, if I use \index{...|ixxmain}, everything's fine, and the .idx file is unexpanded. – Brent.Longborough Aug 5 '12 at 22:44
OK, when you mean in q. 1 (stop being expanded here), you mean in \ixmain? That is only stopped by \string; and therefore the best solution is to wrap \ixmain into yet another indexing command (which is hard here without seeing how you're using \ixmain in relation to the words of the document body). There is nothing as far as I know that you can do to \ixxmain that will help. – jon Aug 5 '12 at 22:58

David Carlisle's answer works nicely, until I add hyperref back in. (I took this out for the MWE.) With hyperref in place, the solution generates malformed .idx entries:

-->                                  ?       ?
\indexentry{session id@session \id {}|ixxmain|hyperpage}{8}


So, with hyperref, the solution I'm using is to replace my \index items with my own ixnorm, which operates in a similar manner to ixmain and effectively does the same as David's \detokenize:

\newcommand*{\ixxnorm}[1]{{\hyperpage{#1}}}
\newcommand{\ixnorm}[1]{\index{#1|ixxnorm}}


This appears to be an effective solution, though if I need additional function (such as see also) it may shoot me in the foot later.

-