chiark / gitweb /
fe386b09f46da204a585cc41600c2d0fc1c8c534
[mdwtools] / mdwref.dtx
1 % \begin{meta-comment} <general public licence>
2 %%
3 %% mdwref package -- slightly fancy cross-referencing stuff
4 %% Copyright (c) 2007, 2019 Mark Wooding
5 %%
6 %% This file is part of the `mdwtools' LaTeX package collection.
7 %%
8 %% `mdwtools' is free software: you can redistribute it and/or modify it
9 %% under the terms of the GNU General Public License as published by the
10 %% Free Software Foundation; either version 2 of the License, or (at your
11 %% option) any later version.
12 %%
13 %% `mdwtools' is distributed in the hope that it will be useful, but
14 %% WITHOUT ANY WARRANTY; without even the implied warranty of
15 %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 %% General Public License for more details.
17 %%
18 %% You should have received a copy of the GNU General Public License
19 %% along with `mdwtools'.  If not, write to the Free Software Foundation,
20 %% Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 %%
22 % \end{meta-comment}
23 %
24 % \begin{meta-comment} <Package preambles>
25 %<+package>\NeedsTeXFormat{LaTeX2e}
26 %<+package>\ProvidesPackage{mdwref}
27 %<+package>                [2020/09/06 1.14.0 Cross-referencing]
28 % \end{meta-comment}
29 %
30 % ^^A\CheckSum{96}
31 %% \CharacterTable
32 %%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
33 %%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
34 %%   Digits        \0\1\2\3\4\5\6\7\8\9
35 %%   Exclamation   \!     Double quote  \"     Hash (number) \#
36 %%   Dollar        \$     Percent       \%     Ampersand     \&
37 %%   Acute accent  \'     Left paren    \(     Right paren   \)
38 %%   Asterisk      \*     Plus          \+     Comma         \,
39 %%   Minus         \-     Point         \.     Solidus       \/
40 %%   Colon         \:     Semicolon     \;     Less than     \<
41 %%   Equals        \=     Greater than  \>     Question mark \?
42 %%   Commercial at \@     Left bracket  \[     Backslash     \\
43 %%   Right bracket \]     Circumflex    \^     Underscore    \_
44 %%   Grave accent  \`     Left brace    \{     Vertical bar  \|
45 %%   Right brace   \}     Tilde         \~}
46 %%
47 %
48 % \begin{meta-comment}
49 %
50 %<*driver>
51 \input{mdwtools}
52 \describespackage{mdwref}
53 \usepackage{mdwtab}
54 \mdwdoc
55 %</driver>
56 %
57 % \end{meta-comment}
58 %
59 %^^A-------------------------------------------------------------------------
60 %
61 % \section{User guide}
62 %
63 % I always name my cross-reference labels with a prefix telling me what kind
64 % of thing they are.  A figure might be |fig:foo| or a table |tab:bar|.  When
65 % I refer to the thing, then, I basically have to repeat myself:
66 % `|see table~\ref{tab:bar}|'.  Kinda silly.
67 %
68 % \DescribeMacro\xref
69 % The |\xref| command understands my prefixing system.  I can say
70 % `|\xref{tab:bar}|' and it inserts a reference to `table~4', for example.
71 % This is, of course, useless if you want to put the reference at the
72 % beginning of a sentence: `Table~4 shows\dots'.
73 % \DescribeMacro\Xref
74 % The |\Xref| command (note the initial capital) handles this properly, so
75 % you just type `|\Xref{tab:bar} shows|\dots'.
76 %
77 % The full syntax of the |\xref| command is like this.
78 % \begin{grammar}
79 % <xref-command> ::= \[[
80 % "\\xref"
81 % \[ "[" <mangle> "]" \]
82 % "{" <reference> "}"
83 % \]]
84 % \end{grammar}
85 % The optional \<mangle> argument is a command to be applied to the generated
86 % text: it \emph{must} be a single token.  Rather than printing `table', or
87 % whatever, it prints \syntax{<mangle>"{table}"}.
88 % The most obvious application of this is the |\Xref| command, which uses a
89 % helper |\toupper|.
90 % \DescribeMacro\toupper
91 % The call \syntax{"\\toupper{"<stuff>"}"} typesets \<stuff> with the first
92 % character in uppercase.  So |\Xref| is defined simply as\footnote{Modulo
93 %   the fact that the author is a dreadful \TeX\ hacker.}
94 % \begin{listing}
95 %\newcommand{\Xref}[1]{\xref[\toupper]{#1}}
96 % \end{listing}
97 %
98 % \DescribeMacro\formatxref
99 % The reference itself is typeset by calling
100 % \syntax{"\\formatxref{"<mangle>"}{"<string>"}{"<label>"}"}, which can do as
101 % it pleases: the \<mangle> token is from the |\xref| invocation; the
102 % \<string> is category of thing being referred to (as established by
103 % |\defxref| below); and \<label> is the label, again from |\xref| .  The
104 % default behaviour is to print
105 % \syntax{<mangle>"{"<string>"}~\\ref{"<label>"}"}, but this can be
106 % overridden.
107 % (Not quite true: in fact, the default does something better if
108 % \package{hyperref} is detected, but the idea is basically the same.)
109 %
110 % All that remains is to define the strings to be typeset for various kinds
111 % of labels.
112 % \DescribeMacro\defxref
113 % For this, we use the |\defxref| command:
114 % \begin{grammar}
115 % <definition> ::= \[[
116 % "\\defxref"
117 % "{" <prefix> "}"
118 % "{" <string> "}"
119 % \]]
120 % \end{grammar}
121 % The \<prefix> is what you put on the front of your labels; the \<string> is
122 % the string to be typeset by |\xref|.
123 %
124 % A number of useful prefixes are already defined, following my usual
125 % preferences; they're shown in \xref{tab:defs}.
126 % \begin{table}
127 %   \begin{tabular}[C]{ll} \hlx*{hv}
128 %   \textbf{Prefix} & \textbf{Text} \\ \hlx{vhv}
129 %     \texttt{ch}       & chapter $n$                                   \\
130 %     \texttt{app}      & appendix $n$                                  \\
131 %     \texttt{sec}      & section $n$                                   \\
132 %     \texttt{def}      & definition $n$                                \\
133 %     \texttt{th}       & theorem $n$                                   \\
134 %     \texttt{lem}      & lemma $n$                                     \\
135 %     \texttt{prop}     & proposition $n$                               \\
136 %     \texttt{cor}      & corollary $n$                                 \\
137 %     \texttt{fig}      & figure $n$                                    \\
138 %     \texttt{tab}      & table $n$                                     \\
139 %     \texttt{eq}       & equation $n$                                  \\
140 %     \texttt{i}        & item $n$                                      \\
141 %     \texttt{ex}       & exercise $n$                                  \\
142 %   \hlx*{vh}\end{tabular}
143 %   \caption{Predefined reference prefixes}
144 %   \label{tab:defs}
145 % \end{table}
146 %
147 % \implementation
148 % \section{Implementation}
149 %
150 %    \begin{macrocode}
151 %<*package>
152 %    \end{macrocode}
153 %
154 % The following quark will be useful.
155 %    \begin{macrocode}
156 \def\q@delim{\q@delim}
157 %    \end{macrocode}
158 %
159 % \begin{macro}{\defxref}
160 % Defining prefixes is easy.  We store the text for each prefix in a macro
161 % called \syntax{"\\xref$"<prefix>}.
162 %    \begin{macrocode}
163 \def\defxref#1#2{%
164   \expandafter\def\csname xref$#1\endcsname{#2}%
165 }
166 %    \end{macrocode}
167 % \end{macro}
168 %
169 % \begin{macro}{\formatxref}
170 % Output a cross-reference in the right way.
171 %    \begin{macrocode}
172 \def\formatxref#1#2#3{%
173   \ifx\hyperref\@@undefined #1{#2}~\ref{#3}%
174   \else \hyperref[#3]{#1{#2}~\ref*{#3}}\fi%
175 }
176 \def\xref@fallback#1{\formatxref\relax{?\texttt{#1}}{#1}}
177 %    \end{macrocode}
178 % \end{macro}
179 %
180 % \begin{macro}{\xref}
181 % We're meant to typeset a reference.  The first job is to see whether
182 % there's an optional argument.  If so, grab it; otherwise |\relax| will do.
183 %    \begin{macrocode}
184 \def\xref{\@ifnextchar[\xref@{\xref@[\relax]}}
185 \def\xref@[#1]#2{\xref@@{#1}#2:\q@delim:\q@delim:\q@delim\q@delim}
186 %    \end{macrocode}
187 % Right; now we abuse \TeX's argument parser to pick apart the reference
188 % label, which ought to have the form \syntax{<prefix>":"<suffix>}.
189 %    \begin{macrocode}
190 \def\xref@@#1#2:#3:\q@delim#4\q@delim\q@delim{%
191 %    \end{macrocode}
192 % So, |#1| is the optional command, or |\relax|.  |#2| should be the
193 % prefix, and |#3| the suffix.  However, if the string doesn't have any
194 % colons in, then |#3| will be |\q@delim|.  This is easy to check for using
195 % |\ifx|.
196 %    \begin{macrocode}
197   \def\@tempa{#2}\def\@tempb{#3}%
198   \ifx\@tempb\q@delim%
199     \PackageError{xref}{Bad ref syntax}%
200       {A reference name doesn't contain a `:'-delimited prefix.  Did you %
201        mean to use plain \string\ref here?}%
202      \xref@fallback{#2}%
203   \else%
204     \expandafter\let\expandafter\@tempa\csname xref$#2\endcsname%
205     \ifx\@tempa\relax%
206       \PackageError{xref}{Unknown ref kind `#2'}%
207         {The ref name's prefix `#2' is unknown: either it's been mistyped %
208          or there's a missing \string\defxref somewhere.}%
209      \xref@fallback{#2:#3}%
210     \else%
211       \toks@\expandafter{\@tempa}%
212       \edef\next@##1{##1{\the\toks@}}%
213       \next@{\formatxref{#1}}{#2:#3}%
214     \fi%
215   \fi%
216 }
217 %    \end{macrocode}
218 % \end{macro}
219 %
220 % \begin{macro}{\toupper}
221 % That's the difficult stuff done.  Uppercasing is a matter of picking out
222 % the first letter and passing it to \TeX's |\uppercase| primitive.
223 %    \begin{macrocode}
224 \def\toupper#1{\toupper@#1}
225 \def\toupper@#1{\uppercase{#1}}
226 %    \end{macrocode}
227 % \end{macro}
228 %
229 % \begin{macro}{\Xref}
230 % As promised, |\Xref| is very easy.
231 %    \begin{macrocode}
232 \def\Xref{\xref[\toupper]}
233 %    \end{macrocode}
234 % \end{macro}
235 %
236 % Now all that remains is to initialize the table of prefix strings.
237 %    \begin{macrocode}
238 \defxref{ch}{chapter}
239 \defxref{app}{appendix}
240 \defxref{sec}{section}
241 \defxref{def}{definition}
242 \defxref{th}{theorem}
243 \defxref{lem}{lemma}
244 \defxref{prop}{proposition}
245 \defxref{cor}{corollary}
246 \defxref{fig}{figure}
247 \defxref{tab}{table}
248 \defxref{eq}{equation}
249 \defxref{i}{item}
250 \defxref{ex}{exercise}
251 %    \end{macrocode}
252 % And we're done!
253 %    \begin{macrocode}
254 %</package>
255 %    \end{macrocode}
256 % \nopagebreak
257 %
258 % \hfill Mark Wooding, \today
259 %
260 % \Finale
261 %
262 \endinput