\NeedsTeXFormat{LaTeX2e} \ProvidesPackage{terms}[2005/10/18 LaTeX package aiding the creation of indices] % % LaTeX package "terms" for short declaration of terms in a text, which then can be % collected more easily in an index or may be emphasized in the running text. % Beisdes the package provides support for similiar treatment of symbols, which is mainly % aimed at a glossary of symbols or list of symbols at the end of a document. % % Author: Thomas Eckert, eckert(@)mathematik.uni-marburg.de % % Version 5: 1. Implementing a glossary of symbols mechanism with \Symbol and % \symbol commands like the \Term and \term commands. % 2. Besides the "!"-syntax is treated as the "+*/"-syntax. % 3. Added \Headword mechanism for wildcards in subentries replacing the headword. % % % Wishlist and ideas % % 1. What about the idea in version 2 of saving the index entry for a term that it can % be reused by \term? Also labeling for complicated expressions? This is now imple- % mented in the \Symbol command. % 2. Perhaps automatically apply "+*/"-syntax for composed expressions (multiple words or % at least words with "-" inside? Which order then, i.e. "+" or "/"? % 3. English glossary? Or at least international expression in index behind the main % entry? The last is only possible with topic "1." here? % 4. Use standard LateX documentation (dtx-mechanism) for development of this package! % 5. Perhaps link a symbol to a term and list all terms's occurences also for the symbol. % Is it too dangerous? If so, at least give the option for this mechanism? % 6. The eqref meachnism of package `nomencl' is undermined (to admit multiple entries). % If it should be necessary, perhaps shift it behind the `|' sign in the index syntax. % Seems to be a bad solution in the nomencl-package anyway? % 7. With the "~" perhaps enhance syntax for double "*/" to end the main entry and % continue the side entry (e.g. "white *honey* milk" for "white ~ milk" under "honey"). % 8. Similarly, admit multiple "+" signs for multiple additional entries? % % % Known bugs % % 1. \Term{symmetric *matrix} (and similarly with "/") leads to an index entry with % misplaced space: under "matrix" there is a line "symmetric , 11" if occurence is on % page 11 for example. There is space too much in front of the comma. % Workaround: Maybe simply make the index processor not print a comma - as makeindex % does by default. Then the two spaces become one space and all is fine. % 2. If there is a \term{x} and a \Term{x} on the same page, then the second is omitted % in the index and not the first one, which though is less important. Use with care. % 3. The mechanism for follow-up \symbol of course doesn't work, if the \symbol command % comes earlier than the defining \Symbol call. Perhaps save all these calls in a list % and perform writing to the job.nlo only at the end? % 4. The sorting isn't good: T, t, T_i are sorted in exactly this order -- independent of % \NonLetterSub. But often or always one would prefer T, T_i, t or even the t in the % beginning. % % % Usage % % In a LateX document the preamble should contain % \usepackage[noindex,symbols,myindex]{terms} % where [noindex,symbols,myindex] are optional, if one doesn't like terms being collected in % an index or wants a list of symbols or these indices somewhere else then at the end of the % document. In the latter case use \printindex (from package makeidx loaded by this package % unless option "noindex" is given) and \printnomenclature (for list of symbols whence % enabled and then taken from package nomencl required by this package). % % For the documentation of the provided commands see the corresponding section below. % % The main thing in using the "terms" package is to call makeindex for the job's idx-file % after first processing the tex-file and then rerun tex on the file to include the newly % generated ind-file. This is done via the \printindex command, best positioned at the end % of the document (standard unless option "myindex" is set). (See the documentation of the % makeindex program or makeidx.sty.) The same holds for a second index, a list of symbols, % which can be created by the option `symbols'. In this case you have to run makeindex (or % an analogous index processor) also as % makeindex -s nomencl.ist -o job.nls job.nlo % whence the nomenclature package `nomencl' is available with its style file `nomencl.ist'. % Here `job' has to be replaced by the name of your tex file. % % To avoid the described bug "1." you should try to instruct your index processor (by some % style file or ini-file) to format page numbers either as right aligned or simply to omit % the comma. For the standard index processor "makeindex" this is done by adding the % following three lines to a (local) style file (e.g. "terms.ist", see also next paragraph): % delim_0 " " % delim_1 " " % delim_2 " " % Then makeindex is to be called as "makeindex -s terms.ist job.idx". % % Besides it is recommended to make single subitems appearing in the same line as their % top items (but only if it is really "single", which means that the top item does not % ocurr on it's own somewhere, i.e. has no page specification). For makeindex again, this % is done with the two lines % item_x2 ", " % item_x1 ", " % in the style file. Such a file "terms.ist" comes with this LaTeX package "terms.sty", % including also a redefined preamble to get an entry for the index in the table of contents: % preamble "\\begin{theindex}\n\\addcontentsline{toc}{section}{Index}\n" % % A little memo: Try to replace the "!"-syntax in ":entry"-arguments of a \Term command (see % below). Often the "*"-form is possible and also better processed (e.g. for the linked for- % matting by means of \@Main). And observe that for the moment the "!" syntax is not at all % processed in the main argument of \Term and therefore will be printed in the text itself. % % % % Package Options and Dependencies % \newif\ifindex\indextrue \newif\ifsymbols\symbolsfalse \newif\ifstandard\standardtrue % \DeclareOption{noindex}{\indexfalse} \DeclareOption{symbols}{\symbolstrue} \DeclareOption{myindex}{\standardfalse} \ProcessOptions % \ifsymbols% \RequirePackage[refpage,noprefix]{nomencl}[2005/03/31]% At least version 4.1! % Some redefinition for the package following its sample04.cfg (expansion) or what is % described under section "I want it expanded!" in its documentation. \def\makenomenclature{% \newwrite\@nomenclaturefile \immediate\openout\@nomenclaturefile=\jobname\@outputfileextension \def\@nomenclature{% \@ifnextchar[% {\@@@@nomenclature}{\@@@@nomenclature[\nomprefix]}}% \typeout{Writing nomenclature file \jobname\@outputfileextension}% \let\makenomenclature\@empty} \def\@@@@nomenclature[#1]#2#3{% \protected@write\@nomenclaturefile{}% {\string\nomenclatureentry{#1@[{#2}]% Deleted "#2" between "#1" and "@"! #3% Deleted "\begingroup" in front (see \nompageref below) and the \nomeqref stuff behind. |nompageref{\@ThisType}}{\thepage}}}% Inserted "{\@ThisType}" and the following! \PackageInfo{terms}{Disabled the `eqref' mechanism of package `nomencl' % (for multiple page references)}% \def\@ThisType{main}% In case \nomenclature is still called manually. \def\nompageref#1#2{\if@printpageref\pagedeclaration{\csname#1\endcsname{#2}}\fi\nomentryend}% % Deleted "\endgroup" (see above) and added a new parameter #1 \for `\main' % And some adjustments \def\nomname{List of Symbols}% \def\nompreamble{\labelsep.25in}% \nomitemsep-.5\parsep% \def\nomlabel#1{\hfil#1}% For left aligned symbols in the list. \def\pagedeclaration#1{\nobreakspace#1}% No comma. It should be placed in nomencl.ist anyway. % Now, initialize a glossary of symbols \makenomenclature% \ifstandard\AtEndDocument{\printnomenclature[.8in]}\fi% % At last define a macro for the creation of a single entry: \def\@HandleMainSymbolEntry{% \def\@ThisType{main}% % Extract from \@SymbolCode a \csname'ble string \@SymbolEntryName: \let\@SymbolEntryName\@SymbolCode\@onelevel@sanitize\@SymbolEntryName% % Now, prepare the \@SymbolCode: convert to string, but replace "!" and "|": \let\@@SymbolCode\@SymbolCode% This will be the new and `cleaned' one. \@onelevel@sanitize\@@SymbolCode% \@ReplaceEach\!\@In\@@SymbolCode\@By\Backstep% Necessary at least for the following. \@ReplaceEach!\@In\@@SymbolCode\@By\ExclamationMark% \@ReplaceEach\|\@In\@@SymbolCode\@By\Vert% Again respect order for these two! \@ReplaceEach|\@In\@@SymbolCode\@By\vert% \if@Found @\@In\@@SymbolCode{\PackageWarning{terms}% {@-signs in symbol code `\@@SymbolCode' cannot be processed.}} % Finally save the call for the entry in the symbol list for \symbol and execute it: \expandafter\expandafter\expandafter\xdef\expandafter% \csname\@SymbolEntryName-@@Symbol\endcsname{% \noexpand\nomenclature[\@SymbolEntry]{$\@@SymbolCode$}{\@Description}% }% \expandafter\csname\@SymbolEntryName-@@Symbol\endcsname% }% \else% \let\@HandleMainSymbolEntry\relax% \fi% % \ifindex% \RequirePackage{makeidx}% \makeindex% \ifstandard\AtEndDocument{\printindex}\fi% \def\@Index#1{\index{#1|\@Type}}% Use \@Type from \@Term for consequent formatting. \else% \def\@Index#1{}% \fi% % % % % Provided commands % \newcommand\Term[2][]{\@Term{#2}{main}{#1}} \newcommand\term[2][]{\@Term{#2}{side}{#1}} % Use as \Term[international]{term} and compare documentation of \@Term for the % special syntax of . (Here parameter is optional.) \newcommand\HandleInternational[1]{ (\textit{#1})\@Index{#1 (\@Main)}} % Compare \@Term's documentation below. % \let\textmain\emph% In \@Term{term}{#2}{...} the formatting of is done via \let\textside\relax% "\csname text#2\endcsname" resulting in \textmain for #2 as "main". % \let\entrymain\textbf% Also, parameter of \@Term is transferred to \index{...|type}, \let\entryside\textrm% aliased \@Index{...}, for formatted page numbers (makeidx package). % \let\linked\textit% In the index a link to a main entry is marked \linked. This takes one % argument for only partial expressions. But ignoring this, \linked may also be an \uparrow. % Observe: Directly after "!" or at the very beginning \linked{X} must be preceeded by "X@" % for proper ordering (compare the internal command "\@Convert#1!#2!#3~" below). % \def\Headword{\ensuremath{\sim}}% The wildcard for the headword in a subentry. \let\HeadwordFirst\Headword% Wild card for a missing headword in front of all stuff. % \newcommand\Symbol[1]{% % Use as \Symbol{code:entry:description} where is optional and, if there is % no colon given at all, is taken from last \Term's . % % At first extract all the components from the one-parameter-syntax. \@DecomposeSymbol#1:::~% % Now print out the extracted symbol, which has been extracted into \@SymbolCode. \@SymbolCode% % If a list of symbols is enabled (package option) the following creates the entry. \@HandleMainSymbolEntry% } \let\symbolLaTeX\symbol% Unfortunately LaTeX has already defined a command \symbol (for % accessing symbols in a font). But after saving this, we may overwrite it: \PackageInfo{terms}{Redefining macro \protect\symbol\space and saved LaTeX's\MessageBreak% (only compatibility reasoned) one as macro \protect\symbolLaTeX} \renewcommand\symbol[2][]{% % This is for follow-up entries. Use as \symbol[entry]{symbol} where is % printed and taken as if this optional argument is omitted. Now, % specifies the related entry, i.e. the related \Symbol's parameter. #2% \ifsymbols% \def\@ThisType{side}% \if\blank{#1}\def\@SymbolEntryName{#2}\else\def\@SymbolEntryName{#1}\fi% \@onelevel@sanitize\@SymbolEntryName% \expandafter\@ifundefined\expandafter{\@SymbolEntryName-@@Symbol}{% then \PackageWarning{terms}% {Symbol "\@SymbolEntryName" unknown. No follow-up entry is created.}% }{% else \expandafter\csname\@SymbolEntryName-@@Symbol\endcsname% }% fi \fi% } \newtoks\NonLetterSub \NonLetterSub={ }% This defines what is substituted for non-letters for sorting of % symbols. To preserve the original sequence from the first letter onwards: % \let\NonLetterSub\relax % But be careful: All the \index-related symbols @, !, and | will cause problems then. % % Implementation % % The main macro \@Term % % Use as \@Term{term}{type}{international}, where may be of the syntax % term = text[:entry][;additional] % with set to if omitted. Then an of the form % entry = head@tail, @={+,*,/} % will be interpreted as the following index entries (more or less): % +: \@Index{}\@Index{!\linked{}} % *: \@Index{!} % /: \@Index{!}\@Index{\linked{}}. % Thus "+" leads to an additional entry, "*" to an entry under a part of the term which % is not the beginning, and "/" is the combination of both. The main part ist saved in % a new variable
. Additional entries are marked by italics with the meaning of % "see mainly under this topic" for possible further occurences of the term. % % More exactly each \@Index call is a usual \index completed by a "|" at it's end % to get proper formatting. Here the parameter is expected to be "main" or % "side", generated by \Term or \term respectively. % % A non-empty leads to an additional entry with a link formatting as % described above. Here a linked main entry can be referred to by a "**"-syntax: % A "*"-bracketed phrase is set \linked. If the phrase itself is empty, i.e. there is a % double "**", then it will be replaced by the actual \@Main entry. % % After the index entries are performed the term's text is printed, cleared of the % syntax elements "+*/". % % Finally, the parameter is meant to be an expression of the term in a % second language and is typeset as "\HandleInternational{...}" if not empty. Redefine % this command for appropriate behavior and add some language glossary for example. % \newcommand\@Term[3]{% \@DecomposeTerm#1::~% This extracts \@Text, \@Entry, and \@Additional from #1. \gdef\@Type{#2}% Export #2 to be used in \@Index for formatting the index entry. \if\blank{\@Entry}\else\expandafter\@SplitPlus\@Entry++~\fi% Create index entries and \ifindex% \if\blank{\@Additional}\else\expandafter\@AddIndex\@Additional***~\fi% ";"-additionals. \fi% \csname text#2\endcsname{\@Text}% Print the text formatted by \textmain or \textside. \if\blank{#3}\else\HandleInternational{#3}\fi% Handle the -argument #3. } % % Macros for decomposing \@Term's parameter into \@Text, \@Entry, and \@Additional \def\@DecomposeTerm#1:#2:#3~{% \if\blank{#2}\@SplitEntries#1;;~\gdef\@Text{\@Main}% (\let\linked\relax here?) \else\@SplitEntries#2;;~\gdef\@Text{#1}\fi% } \def\@SplitEntries#1;#2;#3~{\gdef\@Entry{#1}\gdef\@Additional{#2}} % % Macros creating \@Main and the index entries \def\@SplitPlus#1+#2+#3~{\if\blank{#3}\@SplitStar#1**~\else% \gdef\@Main{#1#2}\@Index{#1#2}\@Index{#2!#1@\linked{#1}\Headword}\fi} \def\@SplitStar#1*#2*#3~{\if\blank{#3}\@SplitSlash#1//~\else% \gdef\@Main{#1\linked{#2}}\@Index{#2!#1\Headword}\fi} \def\@SplitSlash#1/#2/#3~{\if\blank{#3}\@SplitExclm#1!!~\else% \gdef\@Main{#1\linked{#2}}\@Index{#2!#1\Headword}\@Index{#1\linked{#2}}\fi} \def\@SplitExclm#1!#2!#3~{\if\blank{#3}\gdef\@Main{#1}\@Index{#1}\else% \gdef\@Main{#1#2}\@Index{#1!#2@\HeadwordFirst#2}\fi}% % % Macros for additional entries from a (";"-given) argument containing "*"-syntax \def\@AddIndex#1*#2*#3*#4~{% \if\blank{#4}% no star given \ifindex\index{#1|see{\@Main}}\fi% \else% at least one star given \if\blank{#2}% A double "**" refers to the actual main entry. \@Index{\@Convert#1!!~\linked{\@Main}#3}% \else% A "*"-bracketed phrase is set \linked. \@Index{\@Convert#1!!~\linked{#2}#3}% \fi% \fi% } \def\@Convert#1!#2!#3~{% \if\blank{#3}\if\blank{#1}\@Main @\fi% The argument was completely empty. \else#1!\if\blank{#2}\@Main @\else#2\fi\fi% The argument finished with a "!". } % % % Macros for the \Symbol commands % % Macros for decomposing \Symbol's parameter into \@SymbolCode, \@SymbolEntry, and \@Description \def\@DecomposeSymbol#1:#2:#3:#4~{% \gdef\@SymbolCode{#1}% % Try to sort automatically: \if\blank{#3}\ExtractLetters{#1}{\@SymbolEntry}\else\xdef\@SymbolEntry{#2}\fi% % If description is omitted take it from last \@Term command's \@Main (entry text): \if\blank{#2}\let\@Description\@Main\else\gdef\@Description{#2}\fi% \@onelevel@sanitize\@Description% for proper writing into file } % To extract letters from a string #1 into a sequence saved in #2 use the following macro. % But be careful: #1 is taken as a \string (token by token); in particular it is not expanded. % Thus, \ExtractLetters{\a}{\b} results in a string value of "\a" for \b whatever \a has been. \def\ExtractLetters#1#2{% \@ExtractedLetters{}% \Call@ExtractLetters#1~!~% \xdef#2{\the\@ExtractedLetters}% } \newtoks\@ExtractedLetters \def\Call@ExtractLetters#1#2~!~{\expandafter\@ExtractLetters\string#1#2~!~} % This removes curly brackets around #1, which wouldn't be processed correctly by the % \string command in the call of the actual extracting procedure. \def\@ExtractLetters#1#2~!~{% % Only letters have nontrivial \lccode (lowercase code). Normally this could be read off % more directly from \catcode 11 (category code `letter'); but here the obligatory \string % command in the call of this macro levels each \catcode down to 12 (`other'). \ifnum\lccode`#1=0\if\blank{\the\@ExtractedLetters}\else\@ifundefined{NonLetterSub}{% \@ExtractedLetters\expandafter{\the\@ExtractedLetters#1}% }{% \@ExtractedLetters\expandafter{\the\@ExtractedLetters\the\NonLetterSub}% }\fi\else% \@ExtractedLetters\expandafter{\the\@ExtractedLetters#1}% \fi% \if\blank{#2}\else\Call@ExtractLetters#2~!~\fi% } % The following macro replaces all occurences of #1 by #3 in the string with name #2. Thus, % #2 is expanded, whereas #1 and #3 are taken directly but being then converted to strings % internally (for proper comparisons). Observe that in order to work, #2 really has to be a % string. It can be produced by \@onelevel@sanitize#2, if #2 is a macro already. % The number of replacings is saved in counter @Recplacings. \def\@ReplaceEach#1\@In#2\@By#3{% % We want to get #1 as a string and therefore call a help macro \@@ReplaceEach doing the % actual work and getting a "stringed" parameter #1. \def\@@Pattern{#1}\@onelevel@sanitize\@@Pattern% \expandafter\@@ReplaceEach\@@Pattern\@In#2\@By{#3}% } \def\@@ReplaceEach#1\@In#2\@By#3{% \def\@@@Sub{#3}\@onelevel@sanitize\@@@Sub% Turns #3 into the string \@@@Sub. \def\@@@Cut##1#1\*@@@Cut{##1}% Cuts off last #1. \def\@@@Replace##1#1##2\*@@@Replace{##1% This is okay. \if\blank{##2}\else% Something left to proceed. But ##2 has a #1 too much at its end. \@@@Sub\expandafter\@@@Replace\@@@Cut##2\*@@@Cut#1\*@@@Replace\fi% }% Now perform this and save back to #2. The \expandafter is to get the meaning of #2. \xdef#2{\expandafter\@@@Replace#2#1\*@@@Replace}% } % The following macro tests if #1 is found in #2, where #2 is assumed to expand % to a string and #1 is taken as a string directly. \def\if@Found#1\@In#2#3{% \def\@Pattern{#1}\@onelevel@sanitize\@Pattern% \expandafter\@if@Found\@Pattern\@In{#2}{#3}% } \def\@if@Found#1\@In#2#3{% \def\@Pattern{#1}\@onelevel@sanitize\@Pattern% \def\if@@Found##1#1##2\*if@@Found{\if\blank{##2}\else#3\fi}% \expandafter\if@@Found#2#1\*if@@Found% } % The following two definitions are used as replacements in the \Symbol command. \let\Backstep\!% \let\ExclamationMark!% % % % General aiding macros % % Macros for (hyperlinked) proper page formatting in the index entries \def\hyperpage#1{#1} % Because of the this definition the package "hyperref" has to be loaded after "terms" that % it may overwrite this empty definition. But it is necessary for the following two commands % used in \@Index as for example \index{...|main}. \def\main#1{\entrymain{\hyperpage{#1}}} \def\side#1{\entryside{\hyperpage{#1}}} % % A test for empty arguments: \if\blank{...} % (from www.ctan.org/tex-archive/info/aro-bend/answer.002) \long\def\blank#1{\expandafter\bl@nk#1@@..\bl@nk}% \long\def\bl@nk#1#2@#3#4\bl@nk{#3#4} % \endinput