6

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@}{}
1
  • 2
    \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
3

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}
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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.