% \begin{meta-comment} <general public licence>
%%
%% mdwref package -- slightly fancy cross-referencing stuff
%% Copyright (c) 2007, 2019 Mark Wooding
%%
%% This program is free software; you can redistribute it and/or modify
%% it under the terms of the GNU General Public License as published by
%% the Free Software Foundation; either version 2 of the License, or
%% (at your option) any later version.
%%
%% This program is distributed in the hope that it will be useful,
%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%% GNU General Public License for more details.
%%
%% You should have received a copy of the GNU General Public License
%% along with this program; if not, write to the Free Software
%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
%%
% \end{meta-comment}
%
% \begin{meta-comment} <Package preambles>
%<+package>\NeedsTeXFormat{LaTeX2e}
%<+package>\ProvidesPackage{mdwref}
%<+package>                [2020/09/06 1.14.0 Cross-referencing]
% \end{meta-comment}
%
% ^^A\CheckSum{96}
%% \CharacterTable
%%  {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
%%   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
%%   Digits        \0\1\2\3\4\5\6\7\8\9
%%   Exclamation   \!     Double quote  \"     Hash (number) \#
%%   Dollar        \$     Percent       \%     Ampersand     \&
%%   Acute accent  \'     Left paren    \(     Right paren   \)
%%   Asterisk      \*     Plus          \+     Comma         \,
%%   Minus         \-     Point         \.     Solidus       \/
%%   Colon         \:     Semicolon     \;     Less than     \<
%%   Equals        \=     Greater than  \>     Question mark \?
%%   Commercial at \@     Left bracket  \[     Backslash     \\
%%   Right bracket \]     Circumflex    \^     Underscore    \_
%%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%%   Right brace   \}     Tilde         \~}
%%
%
% \begin{meta-comment}
%
%<*driver>
\input{mdwtools}
\describespackage{mdwref}
\usepackage{mdwtab}
\mdwdoc
%</driver>
%
% \end{meta-comment}
%
%^^A-------------------------------------------------------------------------
%
% \section{User guide}
%
% I always name my cross-reference labels with a prefix telling me what kind
% of thing they are.  A figure might be |fig:foo| or a table |tab:bar|.  When
% I refer to the thing, then, I basically have to repeat myself:
% `|see table~\ref{tab:bar}|'.  Kinda silly.
%
% \DescribeMacro\xref
% The |\xref| command understands my prefixing system.  I can say
% `|\xref{tab:bar}|' and it inserts a reference to `table~4', for example.
% This is, of course, useless if you want to put the reference at the
% beginning of a sentence: `Table~4 shows\dots'.
% \DescribeMacro\Xref
% The |\Xref| command (note the initial capital) handles this properly, so
% you just type `|\Xref{tab:bar} shows|\dots'.
%
% The full syntax of the |\xref| command is like this.
% \begin{grammar}
% <xref-command> ::= \[[
% "\\xref"
% \[ "[" <mangle> "]" \]
% "{" <reference> "}"
% \]]
% \end{grammar}
% The optional \<mangle> argument is a command to be applied to the generated
% text: it \emph{must} be a single token.  Rather than printing `table', or
% whatever, it prints \syntax{<mangle>"{table}"}.
% The most obvious application of this is the |\Xref| command, which uses a
% helper |\toupper|.
% \DescribeMacro\toupper
% The call \syntax{"\\toupper{"<stuff>"}"} typesets \<stuff> with the first
% character in uppercase.  So |\Xref| is defined simply as\footnote{Modulo
%   the fact that the author is a dreadful \TeX\ hacker.}
% \begin{listing}
%\newcommand{\Xref}[1]{\xref[\toupper]{#1}}
% \end{listing}
%
% \DescribeMacro\formatxref
% The reference itself is typeset by calling
% \syntax{"\\formatxref{"<mangle>"}{"<string>"}{"<label>"}"}, which can do as
% it pleases: the \<mangle> token is from the |\xref| invocation; the
% \<string> is category of thing being referred to (as established by
% |\defxref| below); and \<label> is the label, again from |\xref| .  The
% default behaviour is to print
% \syntax{<mangle>"{"<string>"}~\\ref{"<label>"}"}, but this can be
% overridden.
% (Not quite true: in fact, the default does something better if
% \package{hyperref} is detected, but the idea is basically the same.)
%
% All that remains is to define the strings to be typeset for various kinds
% of labels.
% \DescribeMacro\defxref
% For this, we use the |\defxref| command:
% \begin{grammar}
% <definition> ::= \[[
% "\\defxref"
% "{" <prefix> "}"
% "{" <string> "}"
% \]]
% \end{grammar}
% The \<prefix> is what you put on the front of your labels; the \<string> is
% the string to be typeset by |\xref|.
%
% A number of useful prefixes are already defined, following my usual
% preferences; they're shown in \xref{tab:defs}.
% \begin{table}
%   \def\i#1#2{\texttt{#1}&\texttt{#2}\\}
%   \begin{tabular}[C]{ll} \hlx*{hv}
%   \textbf{Prefix} & \textbf{Text} \\ \hlx{vhv}
%   \csname xref@defs\endcsname
%   \hlx*{vh}\end{tabular}
%   \caption{Predefined reference prefixes}
%   \label{tab:defs}
% \end{table}
%
% \implementation
% \section{Implementation}
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
% The following quark will be useful.
%    \begin{macrocode}
\def\q@delim{\q@delim}
%    \end{macrocode}
%
% \begin{macro}{\defxref}
% Defining prefixes is easy.  We store the text for each prefix in a macro
% called \syntax{"\\xref$"<prefix>}.  The only catch is that, for the
% purposes of generating \xref{tab:defs}, we maintain a list of the prefixes
% which have been defined so far, but this is fairly easy.
%    \begin{macrocode}
\def\defxref#1#2{%
  \toks@\expandafter{\xref@defs\i{#1}{#2}}\xdef\xref@defs{\the\toks@}%
  \expandafter\def\csname xref$#1\endcsname{#2}%
}
%    \end{macrocode}
% The list is obviously empty initially.
%    \begin{macrocode}
\gdef\xref@defs{}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\formatxref}
% Output a cross-reference in the right way.
%    \begin{macrocode}
\def\formatxref#1#2#3{%
  \ifx\hyperref\@@undefined #1{#2}~\ref{#3}%
  \else \hyperref[#3]{#1{#2}~\ref*{#3}}\fi%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xref}
% We're meant to typeset a reference.  The first job is to see whether
% there's an optional argument.  If so, grab it; otherwise |\relax| will do.
%    \begin{macrocode}
\def\xref{\@ifnextchar[\xref@{\xref@[\relax]}}
\def\xref@[#1]#2{\xref@@{#1}#2:\q@delim:\q@delim:\q@delim\q@delim}
%    \end{macrocode}
% Right; now we abuse \TeX's argument parser to pick apart the reference
% label, which ought to have the form \syntax{<prefix>":"<suffix>}.
%    \begin{macrocode}
\def\xref@@#1#2:#3:\q@delim#4\q@delim\q@delim{%
%    \end{macrocode}
% So, |#1| is the optional command, or |\relax|.  |#2| should be the
% prefix, and |#3| the suffix.  However, if the string doesn't have any
% colons in, then |#3| will be |\q@delim|.  This is easy to check for using
% |\ifx|.
%    \begin{macrocode}
  \def\@tempa{#2}\def\@tempb{#3}%
  \ifx\@tempb\q@delim%
    \PackageError{xref}{Bad ref syntax}%
  \else%
    \expandafter\let\expandafter\@tempa\csname xref$#2\endcsname%
    \ifx\@tempa\relax%
      \PackageError{xref}{Unknown ref kind `#2'}%
    \else%
      \toks@\expandafter{\@tempa}%
      \edef\next@##1{##1{\the\toks@}}%
      \next@{\formatxref{#1}}{#2:#3}%
    \fi%
  \fi%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\toupper}
% That's the difficult stuff done.  Uppercasing is a matter of picking out
% the first letter and passing it to \TeX's |\uppercase| primitive.
%    \begin{macrocode}
\def\toupper#1{\toupper@#1}
\def\toupper@#1{\uppercase{#1}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\Xref}
% As promised, |\Xref| is very easy.
%    \begin{macrocode}
\def\Xref{\xref[\toupper]}
%    \end{macrocode}
% \end{macro}
%
% Now all that remains is to initialize the table of prefix strings.
%    \begin{macrocode}
\defxref{ch}{chapter}
\defxref{app}{appendix}
\defxref{sec}{section}
\defxref{def}{definition}
\defxref{th}{theorem}
\defxref{lem}{lemma}
\defxref{prop}{proposition}
\defxref{cor}{corollary}
\defxref{fig}{figure}
\defxref{tab}{table}
\defxref{eq}{equation}
\defxref{i}{item}
\defxref{ex}{exercise}
%    \end{macrocode}
% And we're done!
%    \begin{macrocode}
%</package>
%    \end{macrocode}
% \nopagebreak
%
% \hfill Mark Wooding, \today
%
% \Finale
%
\endinput
