summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/saferef/saferef.dtx
blob: f09502d608a644df6de9f2dcfb4bc6cd05f15ef0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
% \changes{v1.0}{1997/2/2}{First Release}
% 
% \iffalse   % this is a METACOMMENT !
% 
% Package `indxcite' for use with LaTeX2e
% Copyright (C) 1997 James Ashton (email `James.Ashton@anu.edu.au').
% All rights reserved.  You may not alter the contents of this file
% unless you also change its name.
% 
% \fi
% 
% \MakeShortVerb{\+}
% 
% \title{Safer cross-referencing with \texttt{saferef}}
% \author{James Ashton}
% \maketitle
% \begin{abstract}
% The \texttt{saferef} package replaces +\ref+ with +\figureref+,
% +\sectionref+, +\eqref+, etc.\ so that you're forced to specify the
% kind of label you're using.  Each reference command also generates
% appropriate text automatically so that instead of typing
% `+See Figure~\ref{figure:key}+' only `+See \figureref{key}+' is necessary.
% The +\label+ command is redefined so that it records the type of label
% with the key.  In this way each type of label has its own name-space.
% \end{abstract}
% 
% \section{Introduction}
% 
% This package is designed to help avoid cross-referencing errors.
% In a large work it can be difficult to keep track of the keys used
% with \LaTeX's automatic cross-referencing.  It's possible for the output
% to say `as in Corollary 3' when in fact there is no `Corollary 3' but
% instead `Lemma 3'.  Also it can be taxing to come up with
% different keys when the keys used for every label share the same
% name-space.  The \texttt{saferef} package gives every type of label its
% own key name-space and defines a separate variant of +\ref+ to access each
% type of label.  Use of +\ref+ is an error.
% 
% \section{Compatibility with other packages}
% 
% The +saferef+ package takes care to be compatible with other packages
% as much as possible.  Where commands are redefined, the new definition
% is in terms of the existing definition where possible so that new
% features can be added without disrupting existing ones.  For this
% strategy to work, +saferef+ must be read \emph{after} other packages
% which may interact with the features it provides.  In particular
% +saferef+ works with AMS-\LaTeX{} 1.1 and~1.2 or with the +theorem+
% package when read after them in the preamble.
% 
% \pagebreak
% \section{User interface}
% 
% \DescribeMacro{\label}
% \noindent
% The +\label+ command is used exactly as in plain \LaTeX, i.e.,\ a single
% key is supplied as the only argument.
% Its definition has been changed so that the key is modified by prepending
% the name of the type of label followed by a colon. 
% If the label follows a +\chapter+ command then +\label{key}+ will
% behave as +\label{chapter:key}+ does in plain \LaTeX.
% 
% The types of things that can be labelled each have their own counter
% and, in general, the name of the counter is used as the name of the
% label type, i.e.,\ chapters have the label type +chapter+ because that
% is the name of the \LaTeX{} counter used to number them.
% There are exceptions to this rule however:
% 
% \begin{itemize}
% 
% \item
% Subsections and subsubsections are both of type +section+ since their numbers
% usually include the section number so that it's possible to tell what
% level of section is being referenced by the number itself.
% 
% \item
% Subparagraphs are of type +paragraph+.
% 
% \item
% Every level of list item is of type +item+, i.e.,\ items numbered using
% any of the counters +enumi+, +enumii+, +enumiii+ or +enumiv+, are all
% of type +item+.
% 
% \item
% Minipage footnotes use the +mpfootnote+ counter but are of type +footnote+.
%
% \item
% Of course appendices use the +chapter+ counter but (after the +\appendix+
% command is executed) they are of type +appendix+.
% \end{itemize}
%
% \DescribeMacro{\pageref}
% \noindent
% The +\pageref+ command is not modified by \texttt{saferef} but the key
% used must be modified to match the new definition of +\label+ described
% above.
%
% \DescribeMacro{\ref}
% \noindent
% The +\ref+ command is withdrawn so that using it will cause an error.
% It is replaced by the commands described below.
% 
% \DescribeMacro{\appendixref}
% \DescribeMacro{\chapterref}
% \DescribeMacro{\figureref}
% \DescribeMacro{\footnoteref}
% \DescribeMacro{\itemref}
% \DescribeMacro{\partref}
% \DescribeMacro{\sectionref}
% \DescribeMacro{\tableref}
% \noindent
% Each of these commands is used to make a cross-reference to a particular
% kind of label.  In each case exactly one argument is required which
% should be a comma separated list of the label keys to be referenced.
% These keys are modified by prepending the label type followed by a colon
% so that they will work with the modified +\label+ command.
%
% These commands also provide the text describing the
% type of label being referenced.  The input:
% \begin{verbatim}
% See \chapterref{first}.
% See \chapterref{first,second}.
% See \chapterref{first,second,third}.
% \end{verbatim}
% is equivalent to the following plain \LaTeX{} input:
% \begin{verbatim}
% See Chapter~\chapterref{chapter:first}.
% See Chapters \ref{chapter:first} and~\ref{chapter:second}.
% See Chapters \ref{chapter:first}, \ref{chapter:second} and~\ref{chapter:third}.
% \end{verbatim}
%
% \DescribeMacro{\eqref}
% \noindent
% +\eqref+ is based on the command of the same name provided by
% AMS-\LaTeX{}\@.  It is used to reference labels of the +equation+ type
% and it produces the equation numbers as displayed with the referenced
% equation(s).  It does not generate the word `Equation' since this is
% not usually required.
% 
% Note that all of the environments that share the
% equation numbering should be referenced with +\eqref+.  Apart from
% +equation+ and +eqnarray+, this includes the +align+, +gather+,
% +multline+, etc.\ environments from AMS-\LaTeX{} and possibly other similar
% enviroments from other packages.
% 
% \DescribeMacro{\refname}
% \noindent
% This command will (re)define a referencing command for a label type.
% The three arguments required are the label type name, the singular
% form used to refer to it and the plural form,
% e.g.,\ +\refname{chapter}{Chapter}{Chapters}+.
%
% \DescribeMacro{\itemname}
% \noindent
% Sometimes it may be desirable to be more descriptive about items in lists.
% The +\itemname+ command can be used to cause items to be of aribrary type,
% e.g.,\ if you were using an +enumerate+ environment to list problems, then
% then +\itemname{problem}+ would require them to be referenced like
% +\problemref{key}+.  Of course, it would also be necessary to
% specify
% \begin{verbatim}
% \refname{problem}{Problem}{Problems}
% \end{verbatim}
% for this to work.
%
% \DescribeMacro{\newtheorem}
% \noindent
% The +\newtheorem+ is redefined so that an extra
% argument is required.  Specify the plural form of the environment's
% name as an argument immediately following the singular form, e.g.:
% \begin{verbatim}
% \newtheorem{theorem}{Theorem}{Theorems}[section]
% \newtheorem{lemma}[theorem]{Lemma}{Lemmas}
% \end{verbatim}
% The above would define +\theoremref+ and +\lemmaref+ and cause labels
% in the new `theorem-like' environments to have label types identical
% to their environment names (+theorem+ and +lemma+ in this case).
% 
% \pagebreak
% \section{An example}
% 
% The following is a small example which illustrates a few of the
% features of the package.
% Just run it through \LaTeX{} twice, then use +makeindex+ (with the
% arguments noted in the comment in the file, and finally run \LaTeX{} again.
%    \begin{macrocode}
%<*example>
\documentclass{article}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{saferef}
\newtheorem{theorem}{Theorem}{Theorems}
\newtheorem{lemma}[theorem]{Lemma}{Lemmas}
\begin{document}
\section{The first section}
\label{zero}
We'll use the following in \theoremref{one}.
\begin{equation}
a = b\label{two}
\end{equation}
\begin{theorem}
\label{one}
Equation \eqref{two} has nothing to do with \eqref{three} or \eqref{four}.
See also \lemmaref{six}.
\begin{align}
a^2&=b^2+c^2\label{three}\\
a&=\sqrt{b^2+c^2-2bc\cos A}\label{four}
\end{align}
\end{theorem}
Having had this pointless theorem, why not try for a lemma of similar
class.
\section{Another section}
\label{five}
\begin{lemma}
\label{six}
\theoremref{one} (in \sectionref{zero}) contains two equations.
While both are simple, \eqref{four} is more complex than \eqref{three}.
\end{lemma}
\section{The final section}
\label{seven}
This document includes \sectionref{zero,five,seven}.
\lemmaref{six} is on page \pageref{lemma:six}.
\end{document}
%</example>
%    \end{macrocode}
%
% \StopEventually{}
%
% \pagebreak
% \section{The code}
% This package is titled \texttt{saferef} and it requires \LaTeX2e{} to run.
%    \begin{macrocode}
%<*package>
\def\fileversion{1.0}
\def\filedate{1997/2/2}
\def\docdate{1997/2/2}
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{saferef}[\filedate\space\fileversion\space A Safer Cross-referencing package]
\typeout{Package `saferef' \fileversion\space<\filedate>}
%    \end{macrocode}
%
% The +\refstepcounter+ command is used by \LaTeX to increment counters that
% may be referenced.  First we remember its existing definition.
%    \begin{macrocode}
\let\sr@refstepcounter=\refstepcounter
%    \end{macrocode}
% Now we redefine it to remember the name of the counter (in +\sr@name+).
%    \begin{macrocode}
\def\refstepcounter#1{%
  \xdef\sr@name{#1}
%    \end{macrocode}
% We also call +\sr@nm@counter-name+ if it's defined.  This is the
% mechanism used to allow special behaviour for some counters.
%    \begin{macrocode}
  \csname sr@nm@#1\endcsname
%    \end{macrocode}
% Finally we call the remembered original definition of +\refstepcounter+.
%    \begin{macrocode}
  \sr@refstepcounter{#1}}
%    \end{macrocode}
% 
% +\eqnarray+ doesn't use +\refstepcounter+ directly so we have to
% modify it as well.
%    \begin{macrocode}
\let\sr@eqnarray=\eqnarray
\def\eqnarray{\def\sr@name{equation}\sr@eqnarray}
%    \end{macrocode}
%
% Our redefinition of +\label+ involves just the obvious prepending of the
% label type (as saved in +\sr@label+) to the key.
%    \begin{macrocode}
\let\sr@label=\label
\def\label#1{\sr@label{\sr@name:#1}}
%    \end{macrocode}
%
% AMS-\LaTeX\ uses +\ltx@label+ internally instead of +\label+ so we
% need to make these identical in case we're using AMS-\LaTeX.
%    \begin{macrocode}
\let\ltx@label=\label
%    \end{macrocode}
%
% It wouldn't be safe if we could just use the old +\ref+ command so
% we remember its definition and then define it to generate an error message.
%    \begin{macrocode}
\let\sr@ref=\ref
\def\ref{\@latex@error{\string\ref\space disallowed with the saferef package.}}
%    \end{macrocode}
%
% \pagebreak
% The command +\sr@refs+ is called by the various +\ref+ variants to do
% the hard work.  It determines whether there's more than one key and
% generates the singular or plural form of the label type name as
% appropriate.  It also handles the first key by prepending the label type
% and a colon and passing the result to the original definition of +\ref+.
% Finally, it calls +\sr@rest+ if there are more keys to handle.
%    \begin{macrocode}
\def\sr@refs<#1,#2>#3#4#5{%
  \ifx\relax#2\relax
    #4~\sr@ref{#3:#1}%
  \else%
    #5 \sr@ref{#3:#1}%
    \sr@rest<#2>{#3}%
  \fi%
}
%    \end{macrocode}
% +\sr@rest+ handles every key but the first; prepending the label type
% and a colon to each one and passing each result to the original
% definition of +\ref+.  It also generates any required commas and the
% word `and' between the last two references.
%    \begin{macrocode}
\def\sr@rest<#1,#2>#3{%
  \ifx\relax#2\relax
    \ and~\sr@ref{#3:#1}%
  \else%
    , \sr@ref{#3:#1}%
    \sr@rest<#2>{#3}%
  \fi%
}
%    \end{macrocode}
%
% Some base definition of +\eqref+ is required since the later
% redefinition will depend on an existing one.  If there isn't an
% existing one we provide one based on the AMS-\LaTeX 1.2 version.
%    \begin{macrocode}
\ifx\eqref\@undefined
  \def\eqref#1{\textup{\hbox{\m@th\normalfont(\ignorespaces\ref{#1}\unskip\@@italiccorr)}}}
\fi
%    \end{macrocode}
% Now we modify +\eqref+ to avoid the use of the forbidden +\ref+ command
%    \begin{macrocode}
\let\sr@eqref=\eqref
\def\eqref#1{{\let\ref=\sr@ref\sr@eqref{equation:#1}}}
%    \end{macrocode}
%
% The following provides the command which maps label type names to the text
% to appear in references.  Both a singular and plural version must be provided.
%    \begin{macrocode}
\def\refname#1#2#3{%
  \expandafter\def\csname#1ref\endcsname##1{\sr@refs<##1,>{#1}{#2}{#3}}}
%    \end{macrocode}
% We use the above command to provide names for the standard LaTeX counters.
%    \begin{macrocode}
\refname{appendix}{Appendix}{Appendices}
\refname{chapter}{Chapter}{Chapters}
\refname{figure}{Figure}{Figures}
\refname{footnote}{Footnote}{Footnotes}
\refname{item}{Item}{Items}
\refname{paragraph}{Paragraph}{Paragraphs}
\refname{part}{Part}{Parts}
\refname{section}{Section}{Sections}
\refname{table}{Table}{Tables}
%    \end{macrocode}
% 
% We now arrange for some label types to have different names from their
% counters.  This is done by defining a command +\sr@nm@counter-name+
% which is called by +\label+ and which will redefine +\sr@name+ as required.
%
% `subsection' and `subsubsection' are renamed `section'.
%    \begin{macrocode}
\def\sr@nm@subsection{\xdef\sr@name{section}}
\def\sr@nm@subsubsection{\xdef\sr@name{section}}
%    \end{macrocode}
%
% `subparagraph' is renamed `paragraph'.
%    \begin{macrocode}
\def\sr@nm@subparagraph{\xdef\sr@name{paragraph}}
%    \end{macrocode}
%
% `mpfootnote' is renamed `footnote'.
%    \begin{macrocode}
\def\sr@nm@mpfootnote{\xdef\sr@name{footnote}}
%    \end{macrocode}
%
% Add to the definition of +\appendix+ so that it causes the +chapter+
% label type to be renamed +appendix+.
%    \begin{macrocode}
\let\sr@appendix=\appendix
\def\appendix{\sr@appendix\def\sr@nm@chapter{\xdef\sr@name{appendix}}}
%    \end{macrocode}
% 
% We want to be able to have list items called something other than just
% `item' so we'll arrange for the command +\sr@item+ to be used to
% specify the label type of items.
%    \begin{macrocode}
\def\sr@nm@enumi{\xdef\sr@name{\sr@item}}
\def\sr@nm@enumii{\xdef\sr@name{\sr@item}}
\def\sr@nm@enumiii{\xdef\sr@name{\sr@item}}
\def\sr@nm@enumiv{\xdef\sr@name{\sr@item}}
%    \end{macrocode}
% Now we define a command to set +\sr@item+ and use it to set the initial value.
%    \begin{macrocode}
\def\itemname#1{\def\sr@item{#1}}
\itemname{item}
%    \end{macrocode}
% 
% We need to redefine +\newtheorem+ for two reasons.  Firstly we need to
% know the plural form of the name for use in multiple references.
% Secondly, where several `theorem-like' environments are numbered alike,
% they all use the same counter.  We need to hack the generated
% environment so that it tells us which environment it is even though it
% increments a different counter.
% 
% The redefinition of +\newtheorem+ uses the existing definition so it
% will work with any existing definition that's compatible with the
% standard \LaTeX{} +\newtheorem+.  In particular, it will work with the
% `theorem' or `amsthm' packages---provided, of course, that these are
% loaded first.
%    \begin{macrocode}
\let\sr@newtheorem=\newtheorem
%    \end{macrocode}
%
% The following is based on the +amsthm+ package.  The routines just
% parse the various forms of +\newtheorem+ with two possible optional
% argument forms and a starred form (+amsthm+ only).  Having gathered
% up the arguments, they call the remembered original +\newtheorem+ and
% then add a call to +\refname+ to the newly defined environment.
%    \begin{macrocode}
\def\newtheorem{\@ifstar{\sr@xnthm*}{\sr@xnthm\relax}}
%
\def\sr@oparg#1[#2]{\@ifnextchar[{#1}{#1[#2]}}
%
\def\sr@unthm#1#2{\sr@newtheorem*{#1}{#2}}
%
\def\sr@xnthm#1#2{%
  \let\sr@t\relax
  \ifx *#1% Handle the amsthm starred form of \newtheorem
    \def\sr@t{\sr@unthm{#2}}%
  \else
    \def\sr@t{\sr@oparg{\sr@ynthm{#2}}[]}%
  \fi
  \sr@t
}
%
\def\sr@ynthm#1[#2]#3#4{%
  \ifx\relax#2\relax
    \def\sr@t{\sr@oparg{\sr@xthm{#1}{#3}{#4}}[]}%
  \else
    \let\sr@t=\relax
    \sr@newtheorem{#1}[#2]{#3}
    \refname{#1}{#3}{#4}
    \expandafter\let\expandafter\sr@th\csname #1\endcsname
    \expandafter\let\csname sr@th@#1\endcsname\sr@th
    \let\sr@th\relax
    \expandafter\def\csname #1\endcsname{
      \expandafter\def\csname sr@nm@#2\endcsname{\xdef\sr@name{#1}}
      \csname sr@th@#1\endcsname
    }
  \fi
  \sr@t
}
%
\def\sr@xthm#1#2#3[#4]{
  \ifx\relax#4\relax
    \sr@newtheorem{#1}{#2}
    \refname{#1}{#2}{#3}
  \else
    \sr@newtheorem{#1}{#2}[#4]
    \refname{#1}{#2}{#3}
  \fi
}
%</package>
%    \end{macrocode}
%
% \pagebreak
%\section{The documentation driver}
% This will generate the documentation root file.
%    \begin{macrocode}
%<*driver>
\documentclass{article}
\usepackage{doc}
\OnlyDescription
\setlength{\parindent}{0pt}
\begin{document}
\DocInput{saferef.dtx}
\PrintIndex
\PrintChanges
\end{document}
%</driver>
%    \end{macrocode}