# listings and keywords in the index

The listings package allows to index the appearance of keywords in a listing, for example similar to the following MWE:

\documentclass{article}
\usepackage[T1]{fontenc}

\usepackage{imakeidx}
\makeindex
\usepackage{listings}
\lstset{
language   = [LaTeX]TeX,
basicstyle = \ttfamily,
moretexcs  = [2]{LaTeX},
index      = [2][texcs2],
indexstyle = [2]\cmdidx
}
\newcommand*\cmdappearance[1]{\texttt{\textbackslash#1}}
\newcommand*\cmdidx[1]{\index{#1@\cmdappearance{#1}}}
\newcommand*\cmd[1]{\cmdappearance{#1}\cmdidx{#1}}

\begin{document}

\begin{lstlisting}
\LaTeX{} and \LaTeX-code
\end{lstlisting}

\printindex
\end{document}


The PDF of this example looks as expected but it is not, really, as a look in \jobname.ilg and \jobname.idx shows:

\jobname.ilg:

This is makeindex, version 2.15 [TeX Live 2012] (kpathsea + Thai support).
Scanning input file test.idx....
!! Input index error (file = test.idx, line = 2):
-- Extra @' at position 31 of first argument.
done (1 entries accepted, 1 rejected).
Sorting entries...done (0 comparisons).
Generating output file test.ind....done (5 lines written, 0 warnings).
Output written in test.ind.
Transcript written in test.ilg.


\jobname.idx:

\indexentry{LaTeX@\texttt  {\textbackslash LaTeX}}{1}
\indexentry{LaTeX\unhbox \voidb@x \kern \z@ @\texttt  {\textbackslash LaTeX\unhbox \voidb@x \kern \z@ }}{1}


This is no problem for the MWE but the second entry would be lost if it were on a different page. The \LaTeX- part of the listing seems to have an expanded version of \textcompwordmark inserted after the keyword as opposed to the \LaTeX{} part which got the expected entry. The inserted command apparently is

\@namedef{\@lst @um@}{\leavevmode\kern\z@}


(line 990 of listings.sty) which a redefinition of this command into

\@namedef{\@lst @um@}{\textcompwordmark}


shows. The \jobname.idx file then is

\indexentry{LaTeX@\texttt  {\textbackslash LaTeX}}{1}
\indexentry{LaTeX\textcompwordmark @\texttt  {\textbackslash LaTeX\textcompwordmark }}{1}


which is correctly parsed by makeindex but gives two distinct entries for \LaTeX in the index. (IMHO a worse case than the first.)

Providing an empty definition

\@namedef{\@lst @um@}{}


gives the correct \jobname.idx

\indexentry{LaTeX@\texttt  {\textbackslash LaTeX}}{1}
\indexentry{LaTeX@\texttt  {\textbackslash LaTeX}}{1}


and no apparent issues seem to arise. I wonder, though, how safe it is. I traced the \@lst @um@ to the command \lst@CCECUse@ (line 1021 of listings.sty) which seems to have to do with listings extendedchars option (it is finally used in \lst@DefEC, line 998) but I'm lost there and don't really understand what the commands are for. My guess is that

\@namedef{\@lst @um@}{\leavevmode\kern\z@}


is some kind of precaution/safety net (but against what?) and since I'm getting apparently no issues in my real use case with currently about 150 listings the question is more out of curiosity: can something (and what) go wrong if I define

\@namedef{\@lst @um@}{}

-
\leavevmode is a precaution against finding \hbox when in vertical mode. Suppose - does \hbox{-} in order to avoid line breaks; then a line starting - will do damage. –  egreg May 16 '13 at 10:36

I find \textcompwordmark a good idea, since it will enter horizontal mode exactly as \leavevmode does.

However, you can trick \index into not seeing the offending token:

\makeatletter
\newcommand*\cmdidx[1]{%
\begingroup\let\lst@nolig\@empty
\index{#1@\cmdappearance{#1}}\endgroup}
\makeatother
\newcommand*\cmdappearance[1]{\texttt{\textbackslash#1}}
\newcommand*\cmd[1]{\cmdappearance{#1}\cmdidx{#1}}


This produces the following .idx file:

\indexentry{LaTeX@\texttt  {\textbackslash LaTeX}}{1}
\indexentry{LaTeX@\texttt  {\textbackslash LaTeX}}{1}
`
-
That seems like a good solution. The precaution you mentioned in the comment also makes sense - I guess I have been lucky –  cgnieder May 16 '13 at 10:56