5

I am trying to create links from \index commands to corresponding index entries. When hyperref package is loaded, page numbers in index are, by default, linked to the page on which \index command for that entry appears. But it does not work another way around (forward-linking).

When checking correctness of index, it would be useful if I could click on indexed word in PDF (#2 in ati macro in MWE below) and it would take me to the place in the index in which corresponding entry appears. Actual index has many pages, so it is not sufficient to just determine page number where index starts, because given entry can actually appear few pages later.

My first idea was to add label to index entry and then create hyperlink from indexed word. Attempt in doing so is reflected in commented atiwl macro below. Unfortunately, this didn't compile. (Even if it did, there would be a problem with adding unique labels to each entry). Second idea to test if using label could work was to add one label directly to .ind file, like this:

\item Index entry 1, \hyperpage{1}\label{linkedentry}

Altought it compiled, resulting link did not work in PDF.

MWE:

\documentclass{book}
\usepackage{blindtext}
\usepackage{makeidx}
\makeindex
\def \ati#1#2{#2\index{#1}} % "Add to index" macro
% \def \atiwl#1#2{\hyperlink{linkedentry}{#2}\index{#1\label{linkedentry}}} % "Add to index with label" macro
\usepackage{hyperref}
\begin{document}
\blindtext

Some text and \ati{Index entry 1}{indexed term}.

\blindtext

Some text and \ati{Index entry 2}{another indexed term}.

% \blindtext

% Some text and \atiwl{Entry with label}{some indexed text}.

\printindex

\end{document}

I am not sure if this is relevant to the solution, but I use texindy as index processor. And actually, I use splitidx package and accompanying splitindex command line tool, because I need many indexes. In MWE, though, I used makeidx to make it more universal for other people with the same problem.

Is there any way to create link from #2 in ati macro to corresponding index entry?

  • 1
    The reason why it doesn't compile: \hyperlink and \hypertarget must be protected! – user31729 Oct 29 '15 at 13:19
4

This is perhaps what is requested: a \ati - macro which allows forward-backward linking with an automatically generated label depending on a special counter.

As long this counter is only changed by \ati and not manipulated otherwise, the label is unique.

Use the starred command to prevent hyperlinking to the index and use the optional argument (in conjunction with imakeidx) for the special features of \index - macro from imakeidx.

\documentclass{book}
\usepackage{blindtext}
\usepackage{imakeidx}
\usepackage{xparse}
\newcounter{indcntr}
\makeindex


\NewDocumentCommand{\ati}{somm}{%
  \IfBooleanTF{#1}{%
    \IfValueTF{#2}{%
      #4\index[#2]{#3}%
    }{%
      #4\index{#3}%
    }%
  }{%
    \stepcounter{indcntr}%
    \protect\hyperlink{ind::\number\value{indcntr}}{#4}%
    \IfValueTF{#2}{%
      \index[#2]{\protect\hypertarget{ind::\number\value{indcntr}}{#3}}%
    }{%
      \index{\protect\hypertarget{ind::\number\value{indcntr}}{#3}}%
    }%
  }%
}

\usepackage{hyperref}
\begin{document}
\blindtext

Some text and \ati{Index entry 1}{indexed term}

\blindtext

Some text and \ati*{Index entry 2}{another indexed term}.

\blindtext[4]

 Some text and \ati{Entry with label}{some indexed text}.

\printindex

\end{document}
  • 1
    While this answer seems to work when compiled, there is one huge problem with it. Usually, each index entry, for example "Index entry 1" will appear many times in the text. In usual usage of \index, this entry will have all corresponding page numbers listed next to it. However, with your solution, index processor (either makeindex or texindy) will sort entries based on label, not actual index term. So, if you change first argument of all those ati commands to "Entry", what you get is 3 separate index entries, each with one page number, instead of one with 3 (or 2) page numbers. – Rafal Oct 30 '15 at 7:40
  • This 'request' wasn't in your question right from the start – user31729 Oct 30 '15 at 11:21
  • 2
    I thought it was implied. I wanted this index to work just like regular index with added functionality of forward-linking. And regular index only adds page numbers to repeated entry: it does not create new entries for each occurence. Should I ask separate question or just edit this one? – Rafal Oct 30 '15 at 11:54
1

Is this more what you had in mind?

\documentclass{book}
\usepackage{blindtext}
\usepackage{makeidx}
\makeindex
\usepackage{hyperref}

\newcounter{indexlink}

\newcommand{\Index}[1]{\stepcounter{indexlink}%
  \index{#1\string\raisebox{\baselineskip}[0pt]{\string\hypertarget{indexfrom\theindexlink}{}}}%
  \hyperlink{indexfrom\theindexlink}{#1}}

\makeatletter
\def\@wrindex#1{%
  \raisebox{\baselineskip}[0pt]{\hypertarget{indexto\theindexlink}{}}%
  \protected@write\@indexfile{}%
     {\string\indexentry{#1|hyperlink{indexto\theindexlink}}{\thepage}}%
\endgroup\@esphack}% started by \index
\makeatother

\begin{document}
\blindtext

Some text and \Index{indexed term}.

\blindtext

Some text and \Index{another indexed term}.

% \blindtext

% Some text and \atiwl{Entry with label}{some indexed text}.

\printindex

\end{document}
1

I need similar functionality as @Rafal, including the desire that multiple occurences of the same index entry should be listed in a single line in the index. I realized this can be achieved by slightly mofiying the solution offered by @Christian Hupfer: instead of defining an index counter, one can use the index entry itself to generate hyperlinks. Below is a code that implements this, using a home-made command \xindex. For my own purposes I added some additional functionality: the * version, \xindex*, generates boldface for the words added to the main text and the corresponding page number in the index. An optional argument allows additional information to be written to the index (I use this for offering translations for some index entries). And further arguments can be used for creating subentries in the index, or for cross-referencing.

\documentclass{book}
\usepackage{xparse}
\usepackage{color}
\definecolor{darkred}{rgb}{0.7,0,0}
\usepackage{imakeidx}
\makeindex[columns=1]

\NewDocumentCommand{\xindex}{sommmmm}{% 
    %  s: star = \xindex*: generates boldface entries in text and for page number in index
    %  o: optional argument  
    %  mmmmm: five main arguments 
    %  #2 = 'optional' : optional information, formatted as 'index' ('optional') in index,
    %  #3 = 'text'  : 'text' is printed in the main text
    %  #4 = 'sort'  : 'sort' is used for sorting the index, and generating hyperlinks
    %  #5 = 'index' : 'index' is printed in the index
    %  #6 = 'parent!' : 'index' is printed as subindex of 'parent'
    %  #7 = '|see{crossref}' : produces 'index' see 'crossref', or 
    %       '|seealso{crossref}' : produces 'index' see also 'crossref'
  \IfBooleanTF{#1}%
  {%   with *, us boldface for 'text' in main text and page number in index:
    \protect\hyperlink{ind:#4}{\textbf{#3}}% write hyperlinked #3 'text' into main text
    \IfValueTF{#2}{%  if optional info is present:  
      \index{#6#4@\protect\hypertarget{ind:#4}{#5 \textit{(#2)}}|textbf}% 
                                           %write #5 #2 'index' ('optional') to index
    }{%  if no optional info is present: 
      \index{#6#4@\protect\hypertarget{ind:#4}{#5}|textbf}% write #5 'index' to index
    }%
  }%
  {%  without *, use nonboldface for 'text' in main text and page number in index:
    \protect\hyperlink{ind:#4}{#3}% write hyperlinked #3 'text' into main text
    \IfValueTF{#2}{%  if optional info is present:  
      \index{#6#4@\protect\hypertarget{ind:#4}{#5 \textit{(#2)}}#7}% 
                                     % write #5 #2 'index' ('optional') to index
    }{%  if no optional info is present: 
      \index{#6#4@\protect\hypertarget{ind:#4}{#5}#7}% write #5 'index' to index
    }%
  }%
} 


%Format of arguments of \xindex:
%[optional]{text}{sort}{index}{parent!}{|see{crossref} or |seealso{crossref}}
% use * to generate boldface, e.g. \xSet*\
% omit * to generate nonboldface, e.g. \xSet\

\NewDocumentCommand{\xSet}{s}{\IfBooleanTF{#1}{\xindex*}{\xindex}%
[Menge]{set}{set}{set}{set!}{}}

\NewDocumentCommand{\xSubset}{s}{\IfBooleanTF{#1}{\xindex*}{\xindex}%
[Teilmenge]{subset}{subset}{subset}{set!}{}}

\NewDocumentCommand{\xUnion}{s}{\IfBooleanTF{#1}{\xindex*}{\xindex}%
[Vereinigungsmenge]{union}{union}{union}{set!}{}}

\NewDocumentCommand{\xUnionSeeSet}{s}{\IfBooleanTF{#1}{\xindex*}{\xindex}%
{}{unionseeset}{union}{}{|see{set}}}

\NewDocumentCommand{\xIntersection}{s}{\IfBooleanTF{#1}{\xindex*}{\xindex}%
[Schnittmenge]{intersection}{intersection}{intersection}{set!}{}}

\NewDocumentCommand{\xIntersectionSeeSet}{s}{\IfBooleanTF{#1}{\xindex*}{\xindex}%
{}{intersectionseeset}{intersection}{}{|see{set}}}

\NewDocumentCommand{\xCardinality}{s}{\IfBooleanTF{#1}{\xindex*}{\xindex}%
{cardinality}{cardinality}{cardinality}{}{}}

\NewDocumentCommand{\xCountable}{s}{\IfBooleanTF{#1}{\xindex*}{\xindex}%
{countable}{countable}{countable}{}{}}

\NewDocumentCommand{\xEquivalenceClasses}{s}{\IfBooleanTF{#1}{\xindex*}{\xindex}%
[Equivalenzklassen]{equivalence classes}{equivalence classes}{equivalence classes (of sets)}{}{}}

\usepackage[hyperindex]{hyperref}
\hypersetup{linktocpage=true,colorlinks,linkcolor=darkred,urlcolor=darkred,citecolor=darkred}

\begin{document}
A \xSet*\ is a collection of objects. A \xSubset*\ of a set contains
some of its elements. The \xUnion*\xUnionSeeSet\ of two sets contains
all elements of both. Their \xIntersection*\xIntersectionSeeSet\ contains
only the elements contained in both. A set is \xCountable*\ if you can 
count its elements. The number of
elements of a set is called its \xCardinality*. Sometimes
it is useful to organize sets in terms of \xEquivalenceClasses*.

\bigskip 

Please turn the page!
\newpage

Let the \xSet\ $C$ be the \xUnion\ of sets $A$ and $B$,
written as $C = A \cup B$, and $D$ be the \xIntersection\
of $A$ and $B$, written as $D = A \cap B$.

\printindex

\end{document}

My code indeed achieves the stated goal that different calls of the same index entry should be listed in the same line in the index, but a strict prerequisite for this to work is that for all of these calls, ALL arguments of \xindex must be identical. Since there are 5 arguments (and an optional 6th), I have found it convenient to define a \NewDocumentCommand for each index entry, e.g. \NewDocumentCommand{\xSet}{....}, and then use \xSet\ or \xSet* (for boldface) in the main text. Maybe a bit cumbersome, but it does generate the desired output, e.g.:

sample output

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.