% \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} % % \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 } % % \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} % % \end{macrocode}