Archive for July, 1999

LaTeX indexing macros

Wednesday, July 21st, 1999

I have written some macros to help me index my writings in a consistent way. They are not polished or in the form of a proper distribution, but I have used them with succes myself.

I have not, however, used these macros for several years, so I cannot necessarily help much with problems.

There is just one file: indexing.sty.

The actual index is generated with makeindex.

The idea

The goal is consistency in the index without cluttering the source document completely with indexing commands.

To achieve this, I define all terms to be indexed separately, according to their type (personal names, companies, important phrases, …). It is practically an associative array, indexed by the text to be used in the running text, that decides how each term is indexed. The indexing commands are them simply put around the text to be indexed, and the array provides the actual index entries.

I keep these definitions in a separate file which I include at the beginning of the document. Each indexable term has two forms: one for the text (the array index) and one for the index entry (the array value).

In the LaTeX text there is a I{term} macro. It inserts one form of the term in the running text and uses the other for the index entry.

Lets look at the nitty gritty details.

Usage

Formalities

To use these macros put the file indexing.sty in your LaTeX search path and then put the line:

usepackage{indexing}

in the preamble of your document.

Second, it is necessary to tell LaTeX that you want to generate an index:

makeindex

As an aid in consistency, it is possible to have the macros place a mark after each indexed term in the text, so it is easy to see what has been indexed. This is specified with the doindexmark{mark} macro, for example:

doindexmark{${}^{dagger}$}

Then input the definitions. I usually have them in a file named xrefs.tex, so I put in the preample:

input{xrefs}

To specify what parts of the document to index, I use the environment indexing, i.e., I put this around the main part of the document:

egin{indexing}
.
.
.
end{indexing}

Normally, I don’t want to index the preface, the table of contents, the bibliography and the index itself.

The actual index is produced by the genindex macro. The index is printed in two columns, using the multicol environment. Often I add a leading explanation to the index with the indexcomment{} macro. That is:

indexcomment{The index covers all personal names, important locations
etc. Entries in bold mean ...}

genindex

These were all the formalities. Now we’ll have a look at the definitions of the terms to be indexed.

Definitions

There are some different variant of definition and it is easy to add others if needed.

Simple terms
Example: idxname{Giulio Andreotti}{Andreotti, Giulio}This is for normal entries, such as person names. In the running text the name should be written normally, but in the index with the surname first.

The indexed text can have several parts, divided by “; ” (semicolon space). Each part will be indexed separately.

Emphasised terms
Example: idxspec{PSI}{PSI (Italian Socialist Party)}{textsl}This is for special entries, abbreviations, foreign organisations or whatever. In the running text the first argument will be typeset through the macro given as the third argument. The second argument is the index entry. The index entry will appear normally in the index.

To have the index entries typeset differently, a wrapper macro can be used. To have makeindex sort the index properly while emphasising the index entry, I use:

defidxsl#1{#1@	extsl{#1}}
defidxemph#1#2{idxspec{#1}{idxsl{#2}}{textsl}}
idxemph{PSI}{PSI (Italian Socialist Party)}
Aliased terms
Example: idxalias{Andreotti}{Giulio Andreotti}This establishes the first term as an alias for the second. Whenever the first term is used, it will index the index part of the second term. I.e., when used the above example will typeset `Andreotti’, but index `Andreotti, Giulio’ (the index defition of `Giulio Andreotti’ from before).

A more complete example, where both `Ignazio and Nino Salvo’ and `Salvo cousins’ will index both names:

idxname{Ignazio and Nino Salvo}{Salvo, Ignazio; Salvo, Nino}
idxalias{Salvo cousins}{Ignazio and Nino Salvo}
`See also’ terms
Example: idxalso{Socialist Party}{PSI}This makes the first term and alias for the second, and at the same time it makes sure that a `See also’ index entry is made from the first term to the second.

WARNING: I don’t use this command, so I am not sure if it actually works.

Abbreviations
idxabbrev{WPPI}{Witness Protection Programme}{ ext, Italian}This defines an abbreviated term, expanding to the second argument in the text, while indexing the third.

The use of ext is general for all index definitions. It expands to the running text form of the term.

A somewhat abbreviated file of index definitions can be seen here: xrefs.tex. It demonstrates some of the shorthands and trick that can be used within this framework.

Indexing in the document

In the running text, indexed terms are used with the macro I.

Normal indexing: I{term}
This will insert the text part of the term and issue an index{} call for the index part.
Hidden indexing: I-{term}
This issue an index{} call for the index part, without adding anything to the running text.
Emphasised indexing: I*{term}
This will insert the text part of the term and issue an index{} call for the index part in a way to boldface the page number in the index.

The I command is robust.

Tips and tricks

To reduce the visual weight of the indexing command further in the LaTeX source files, I started using active characters. I settled for < and >, because they weren’t used much in my texts.

The following code-snippet can be copied to a .sty file to use these shorthands. They implement <term>, <*term> and <-term>, which are quite analogous to the versions of I{} described above.

catcode`<=active

def<{protectI@ltone}
defI@ltone{@ifnextchar -{I@ltindexonly}{I@lttwo}}
defI@lttwo{@ifstar{I@ltemph}{I@ltnormal}}

defI@ltindexonly-#1>{I@indexonly-{#1}}
defI@ltemph#1>{I@emph{#1}}
defI@ltnormal#1>{I@normal{#1}}

GNU Emacs

I have the following elisp code in my latex-mode-hook. It marks < and > as parentheses, it binds < to a function that inserts <> and leaves point in between, and it binds > to move out of a pair of <>. Pressing < with the point on top of a > will also move past the >.

(local-set-key "C-c " 'latex-index-words)
(local-set-key "<" 'latex-insert-ltgt)
(local-set-key ">" 'up-list)

(modify-syntax-entry ?< "(>")
(modify-syntax-entry ?> ")<")

The definition of the used functions are:

(defun latex-insert-ltgt (arg)
  (interactive "p")
  (undo-boundary)
  (if mark-active
      (let ((beg (region-beginning)))
	(goto-char (region-end))
	(insert ">")
	(save-excursion
	  (goto-char beg)
	  (insert "<")))
    (if (looking-at ">")
	(up-list 1)
      (insert "<")
      (save-excursion
	(insert ">"))))
  )

(defun latex-index-words (arg)
  (interactive "p")
  (undo-boundary)
  (if mark-active
      (let ((beg (region-beginning)))
	(goto-char (region-end))
	(insert ">")
	(save-excursion
	  (goto-char beg)
	  (insert "<")))
    (insert ">")
    (save-excursion
      (backward-word arg)
      (insert "<")))
  )