2

I have the following minimal(ish) example. This is for a technical book with lots of code samples and lots of code-keywords-appearing-in-running-text. So I have the following goals:

  • A macro \code{foo} for typesetting code-keywords-in-running-text. I use the listings package for typesetting code throughout. I also use the underscore package so I don't have to escape underscores in code.
  • I use the hyperref package for cross-references, plus plenty of code keywords appearing in section titles; so I use \texorpdfstring in the definition of \code.
  • Two indices: a main "Index" for English words and concepts, and a second "Index of code samples". I have heard that the imakeidx package is the most standard choice for this, so I'm using it. I'm open to alternatives if they can fix my problem.
  • Many, complicated, index terms. Some terms must be typeset with \code{foo}. Some must be secondary entries, as in, "iterator, std::vector::: see vector::iterator."

mce.tex

\documentclass[ebook,10pt,oneside,final]{memoir}

\usepackage{imakeidx}
\makeindex[name=mce,intoc,columns=2]
\makeindex[name=code,intoc,columns=2,name=code,title=Index of code samples]

\usepackage[final]{listings}
\usepackage{hyperref}
\usepackage{underscore}

\newcommand{\code}[1]{\texorpdfstring{\mbox{\lstinline[basicstyle=\ttfamily]`#1`}}{#1}}

\newcommand{\codeblockdefines}[1]{\index[code]{#1@\code{#1}}}  % for example, \codeblockdefines{list_of_int}
\newcommand{\codeindex}[1]{\index{#1@\code{#1}}}  % for example, \codeindex{const_iterator}
\newcommand{\codeindexstd}[1]{\index{namespace std@\code{namespace std}!#1@\code{#1}}}  % for example, \codeindexstd{vector}

\begin{document}

\tableofcontents

Here's an example of using \code{std::vector}.
\codeindexstd{vector}
\codeindex{std::vector}
\codeblockdefines{vector}

\index{std@\code{std}|see {namespace std@\code{namespace std}}}

\printindex[mce]
\printindex[code]

\end{document}

The problem I'm seeing is that \code and maybe some other macros are getting expanded in the .idx files. When I cat these files I see this:

mce.idx

\indexentry{namespace std@\unhbox \voidb@x \hbox {\lstinline [basicstyle=\ttfamily  ]`namespace std`}!vector@\unhbox \voidb@x \hbox {\lstinline [basicstyle=\ttfamily  ]`vector`}|hyperpage}{1}
\indexentry{std::vector@\unhbox \voidb@x \hbox {\lstinline [basicstyle=\ttfamily  ]`std::vector`}|hyperpage}{1}
\indexentry{std@\code{std}|hyperindexformat{\see {namespace std@\code{namespace std}}}}{1}

code.idx

\indexentry{vector@\unhbox \voidb@x \hbox {\lstinline [basicstyle=\ttfamily  ]`vector`}|hyperpage}{1}

How can I make \index and the rest of my convenience macros (\codeblockdefines, \codeindex, \codeindexstd) do what I want?

  • First move the call to imakeidx before loading hyperref. – egreg Oct 9 '17 at 22:37
  • @egreg: Okay, done. The output doesn't change, though. (EDIT: ok, the .idx files change a bit, but not significantly enough to not-be-rejected.) – Quuxplusone Oct 9 '17 at 22:42
  • I should add that I also see only one "Index" in my final .pdf file, but I think that's just a side-effect of having had all the entries in the "Index of code samples" be rejected. I think TeX refuses to create a page for an index if it'd have zero entries in it. – Quuxplusone Oct 9 '17 at 22:50
  • Your commands \codeindex and \codeindexstd point to a non existent index. – egreg Oct 9 '17 at 22:53
3

imakeidx should be loaded before hyperref. However, your \code command is very fragile as it uses \lstinline and should be “robusted”.

\documentclass[ebook,10pt,oneside,final]{memoir}

\usepackage[final]{listings}
\usepackage{imakeidx}
\usepackage{underscore}
\usepackage{etoolbox}
\usepackage{hyperref}

\makeindex[name=mce,intoc,columns=2]
\makeindex[name=code,intoc,columns=2,name=code,title=Index of code samples]

\newrobustcmd{\code}[1]{\texorpdfstring{\mbox{\lstinline[basicstyle=\ttfamily]{#1}}}{#1}}

\newcommand{\codeblockdefines}[1]{\index[code]{#1@\code{#1}}}  % for example, \codeblockdefines{list_of_int}
\newcommand{\codeindex}[1]{\index[mce]{#1@\code{#1}}}  % for example, \codeindex{const_iterator}
\newcommand{\codeindexstd}[1]{\index[mce]{namespace std@\code{namespace std}!#1@\code{#1}}}  % for example, \codeindexstd{vector}

\begin{document}

\tableofcontents

Here's an example of using \code{std::vector}.
\codeindexstd{vector}
\codeindex{std::vector}
\codeblockdefines{vector}

\index{std@\code{std}|see {namespace std@\code{namespace std}}}

\printindex[mce]
\printindex[code]

\end{document}

I changed the \codeindex and \codeindexstd commands to point to a defined index.

The code.idx file will contain

\indexentry{vector@\code {vector}|hyperpage}{1}

whereas mce.idx contains

\indexentry{namespace std@\code {namespace std}!vector@\code {vector}|hyperpage}{1}
\indexentry{std::vector@\code {std::vector}|hyperpage}{1}

These entries are not rejected.

  • Re "to point to a defined index" — My understanding was that "mce" would be the name of the main index for "mce.tex", so I didn't need to specify that name explicitly; i.e. I could write \index{foo} instead of \index[mce]{foo}. Is this wrong and/or too clever? Should I just define a convenience macro \newcommand{\idx}[1]{\index[mce]{#1}} and avoid using raw \index? – Quuxplusone Oct 9 '17 at 22:52
  • @Quuxplusone No, the unadorned \index command only refers to one not passed the name option. Just remove name=mce, if you want to use \index{...} for pointing to it. – egreg Oct 9 '17 at 22:54
  • I'll look into the etoolbox package. Does it require the change you made to use curly braces instead of backticks? My code samples use a lot of curly braces... – Quuxplusone Oct 9 '17 at 22:55
  • @Quuxplusone You can use backquotes, but they do nothing more than braces, because the argument is already tokenized. \newrobustcmd is just more efficient than \DeclareRobustCommand. – egreg Oct 9 '17 at 22:56
  • Awesome, it seems to work! (Although robustifying the whole \code macro broke \texorpdfstring, so what I did was I pulled out \newrobustcmd{\codeinternal}[1]{\mbox{\lstinline[basicstyle=\ttfamily]`#1`}} and then \newcommand{\code}[1]{\texorpdfstring{\codeinternal{#1}}{#1}}.) I'm still getting "Improper alphabetic constant" for the index entry \indexentry{list_of_ints!::iterator@\code {list_of_ints!::iterator}}{13}, and none of my "X, see Y" entries are showing up; but I'm sure those are unrelated issues and I'll ask new questions if I can't figure them out. – Quuxplusone Oct 9 '17 at 23:19

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.