% \iffalse meta-comment
%
% File: zref-check.tex
%
% This file is part of the LaTeX package "zref-check".
%
% Copyright (C) 2021-2022  Gustavo Barros
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file:
%
%    https://www.latex-project.org/lppl.txt
%
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
%
% This work is "maintained" (as per LPPL maintenance status) by
% Gustavo Barros.
%
% This work consists of the files zref-check.dtx,
%                                 zref-check.ins,
%                                 zref-check-doc.tex,
%                                 zref-check-code.tex,
%                   and the files generated from them.
%
% The released version of this package is available from CTAN.
%
% -----------------------------------------------------------------------
%
% The development version of the package can be found at
%
%    https://github.com/gusbrs/zref-check
%
% for those people who are interested.
%
% -----------------------------------------------------------------------
%
% \fi

\documentclass{l3doc}

% Have \GetFileInfo pick up date and version data
\usepackage{zref-check}

\setlength{\marginparsep}{2\labelsep}

\NewDocumentCommand\opt{m}{\texttt{#1}}

\makeatletter
\newcommand{\zcrequiredkernel}{\zrefcheck@required@kernel}
\makeatother

\begin{document}

\GetFileInfo{zref-check.sty}

\title{%
  The \pkg{zref-check} package%
  \thanks{This file describes \fileversion, released \filedate.}%
}

\author{%
  Gustavo Barros%
  \thanks{\url{https://github.com/gusbrs/zref-check}}%
}

\date{\filedate}

\maketitle

\begin{abstract}
  \pkg{zref-check} provides an user interface for making \LaTeX{}
  cross-references flexibly, while allowing to have them checked for
  consistency with the document structure as typeset.  Statements such as
  ``above'', ``on the next page'', ``previously'', ``as will be discussed'',
  ``on the previous chapter'' and so on can be given to \cs{zcheck} in
  free-form, and a set of ``checks'' can be specified to be run against a
  given \texttt{label}, which will result in a warning at compilation time if
  any of these checks fail.  \cs{zctarget} and the \texttt{zcregion}
  environment are also defined as a means to easily set label targets to
  arbitrary places in the text which can be referred to by \cs{zcheck}.
\end{abstract}

\tableofcontents


\section{Introduction}

The \pkg{zref-check} package provides an user interface for making \LaTeX{}
cross-references exploiting document contextual information to enrich the way
the reference can be rendered, but at the same time ensuring the means that
these cross-references can be done consistently with the document structure.

The usual \LaTeX{} cross-reference is done by referring to a \texttt{label},
associated with one or another document structural element, and this reference
will typeset for you some content based on the information which is stored in
that label.  \cs{zcheck}, the main user command of \pkg{zref-check}, has a
somewhat different concept.  Instead of trying to provide the text to be
typeset based on the contextual information, \cs{zcheck} lets the user supply
an arbitrary text and specify one or more checks to be done on the label(s)
being referred to.  If any of the checks fails, a warning is issued upon
compilation, so that the user can go back to that cross-reference and correct
it as needed, without having to rely on burdensome and error prone manual
proof-reading.

This grants a much increased flexibility for the cross-reference text, which
means in practice that the writing style, the variety of expressions you may
use for similar situations, does not need to be sacrificed for the
convenience.  \cs{zcheck}'s cross-references do not need to ``feel'' automated
to be consistently checked.  Localization is also not an issue, since the
cross-reference text is provided directly by the user.  Separating
``typesetting'' from ``checking'' also means there is a lot of document
context we can leverage for this purpose (see Section~\ref{sec:checks}).

A standard \LaTeX{} cross-reference is made to refer to specific numbered
document elements -- chapters, sections, figures, tables, equations, etc.  The
cross-reference will normally produce that number (which is the element's
``id'') and, eventually, its ``type'' (the counter).  We may also refer to the
page that element occurs and even its ``title'' (in which case, atypically, we
may even get to refer to an unnumbered section, provided we also implicitly
supply by some means the ``id'').

For references to these usual specific document elements, \pkg{zref-check}
caters for a particular kind of cross-reference which is common:
\emph{relational} statements based on them.  \cs{zcheck} can typeset and
meaningfully check cross-references such as ``above'', ``on the next page'',
``on the facing page'', ``on the previous section'', ``later on this chapter''
and so on.  After all, if your reference is being made on page 2 and refers to
something on the same page, ``on this page'' reads much better than ``on
page~2''.  If you are writing chapter~4, ``on the previous chapter'' sounds
nicer than ``on chapter~3''.

However, there is yet another kind of ``looser'' cross-reference we routinely
do in our documents.  Expressions such as ``previously'', ``as mentioned
before'', ``as will be discussed'', and so on, are a powerful discursive
instrument, which enriches the text, by offering hints to the arguments'
threads, without necessarily pressing them too hard onto the reader.  So, we
might not want to say ``on footnote 57, pag.~34'', but prefer ``previously'',
not ``on Section 3.4'', but rather ``below'', or ``later on''.  Besides, we
also may refer to certain passages in the text in this way, rather than to
numbered document elements.  And this kind of reference is not only hard to
check and find, but also to fix.  After all, if you are making one such
reference, you are taking that statement as a premisse at the current point in
the text.  So, if that reference is missing, or relocated, you may need to
bring in the support to the premisse for your argument to close, rather than
just ``adjust the reference text''.  \pkg{zref-check} also provides support
for this kind of cross-reference, allowing for them to be consistently
verified.


\section{Loading the package}
\label{sec:loading-package}

\pkg{zref-check} can be loaded with the usual:

\begin{syntax}
  \cs{usepackage}|{zref-check}|
\end{syntax}

The package does not accept load-time options, package options must be set
using \cs{zrefchecksetup} (see Section~\ref{sec:user-interface}).


\section{Dependencies}

\pkg{zref} is required, of course, but in particular, its modules
\pkg{zref-user} and \pkg{zref-abspage} are loaded by default.  \pkg{ifdraft}
(from the \pkg{oberdiek} bundle) is also loaded by default.  A \LaTeX{} kernel
later than \zcrequiredkernel{} is required as well.  If \pkg{hyperref} is
loaded and option \pkg{hyperref} is given, \pkg{zref-check} makes use of it,
but it does not load the package for you.


\section{User interface}
\label{sec:user-interface}

\begin{function}{\zcheck}
  \begin{syntax}
    \cs{zcheck}\oarg{checks/options}\marg{labels}\marg{text}
  \end{syntax}
  Typesets \meta{text}, as given, while performing a list of \meta{checks} on
  each of the \meta{labels}.  When \pkg{hyperref} support is enabled,
  \meta{text} will be made a hyperlink to \emph{the first} \meta{label} in
  \meta{labels}.  The starred version of the command does the same as the
  plain one, just does not form a link.  The \meta{options} are (mostly) the
  same as those of the package, and can be given to local effect.
  \meta{checks} and \meta{options} can be given side by side as a comma
  separated list in the optional argument.  \meta{labels} is also a comma
  separated list.
\end{function}

\begin{function}{\zctarget}
  \begin{syntax}
    \cs{zctarget}\marg{label}\marg{text}
  \end{syntax}
  Typesets \meta{text}, as given, and places a pair of \texttt{zlabel}s, one
  at the start of \meta{text}, using \meta{label} as label name, another one
  (internal) at the end of \meta{text}.
\end{function}


\begin{function}{zcregion}
  \begin{syntax}
    |\begin{zcregion}|\marg{label}
      |  ...|
    |\end{zcregion}|
  \end{syntax}
  An environment that does the same as \cs{zctarget}, for cases of longer
  stretches of text.
\end{function}


\begin{function}{\zrefchecksetup}
  \begin{syntax}
    \cs{zrefchecksetup}\marg{options}
  \end{syntax}
  Sets \pkg{zref-check}'s options (see Section~\ref{sec:options}).
\end{function}

\bigskip{}

All user commands of \pkg{zref-check} have their \marg{label} arguments
protected for \pkg{babel} active characters using \pkg{zref}'s
\cs{zref@wrapper@babel}, so that we should have equivalent support in that
regard, as \pkg{zref} itself does.  \pkg{zref-check} depends on \pkg{zref}, as
the name entails, which means it is able to work with \pkg{zref} labels, in
general created by \cs{zlabel}, but also with \cs{zctarget} and the
\texttt{zcregion} environment provided by this package.


\section{Checks}
\label{sec:checks}

\pkg{zref-check} provides several ``checks'' to be used with \cs{zcheck}.  The
checks may be combined in a \cs{zcheck} call, e.g.\ \opt{[close, after]}, or
\opt{[thischap, before]}.  In this case, each check in \meta{checks} is
performed against each of the \meta{labels}.  This is done independently for
each check, which means, in practice, that the checks bear a logical
\texttt{AND} relation to the others.  Whether the combination is meaningful,
is up to the user.  As is the correspondence between the \meta{checks} and the
\meta{text} in \cs{zcheck}.

The use of checks which perform ``within the page'' comparisons -- namely
\opt{above} and \opt{below} and, through them, \opt{before} and \opt{after} --
comes with some caveats you should be acquainted with.
Section~\ref{sec:within-page-checks} discusses their limitations and expands
on the expected workflow for their use to ensure reliable results.

Note that the naming convention of the checks adopts the perspective of
\cs{zcheck}.  That is, the name of the check describes the position of the
label being referred to, relative to the \cs{zcheck} call being made.  For
example, the \opt{before} check should issue no message if
\cs{ztarget}|{mylabel}{...}| occurs before
\cs{zcheck}|[before]{mylabel}{...}|.

The available checks are the following:

\begin{description}[leftmargin=0pt, itemindent=0pt, align=right, labelsep=1em,
    font=\MacroFont]

\item[thispage] \meta{label} occurs on the same page as \cs{zcheck}.

\item[prevpage] \meta{label} occurs on the previous page relative to
  \cs{zcheck}.

\item[nextpage] \meta{label} occurs on the next page relative to \cs{zcheck}.

\item[otherpage] \meta{label} occurs on a page different from that of
  \cs{zcheck}, that is, it does \emph{not} occur on \opt{thispage}.

\item[pagegap] There is a page gap between \meta{label} and \cs{zcheck}, in
  other words, \meta{label} does \emph{not} occur on \opt{thispage},
  \opt{prevpage} or \opt{nextpage}.

\item[facing] On a \texttt{twoside} document, both \meta{label} and
  \cs{zcheck} fall onto a double spread, each on one of the two facing pages.

\item[above] \meta{label} and \cs{zcheck} are both on the same page, and
  \meta{label} occurs ``above'' \cs{zcheck}.

\item[below] \meta{label} and \cs{zcheck} are both on the same page, and
  \meta{label} occurs ``below'' \cs{zcheck}.

\item[pagesbefore] \meta{label} occurs on any page before the one of
  \cs{zcheck}.

\item[ppbefore] Convenience alias for \opt{pagesbefore}.

\item[pagesafter] \meta{label} occurs on any page after the one of
  \cs{zcheck}.

\item[ppafter] Convenience alias for \opt{pagesafter}.

\item[before] Either \opt{above} or \opt{pagesbefore}.

\item[after]  Either \opt{below} or \opt{pagesafter}.

\item[thischap] \meta{label} occurs on the same chapter as \cs{zcheck}.

\item[prevchap] \meta{label} occurs on the previous chapter relative to the
  one of \cs{zcheck}.

\item[nextchap] \meta{label} occurs on the next chapter relative to the one of
  \cs{zcheck}.

\item[chapsbefore] \meta{label} occurs on any chapter before the one of
  \cs{zcheck}.

\item[chapsafter] \meta{label} occurs on any chapter after the one of
  \cs{zcheck}.

\item[thissec] \meta{label} occurs on the same section as \cs{zcheck}.

\item[prevsec] \meta{label} occurs on the previous section (of the same
  chapter) relative to the one of \cs{zcheck}.

\item[nextsec] \meta{label} occurs on the next section (of the same chapter)
  relative to the one of \cs{zcheck}.

\item[secsbefore] \meta{label} occurs on any section (of the same chapter)
  before the one of \cs{zcheck}.

\item[secsafter] \meta{label} occurs on any section (of the same chapter)
  after the one of \cs{zcheck}.

\item[close] \meta{label} occurs within a page range from \opt{closerange}
  pages before the one of \cs{zcheck} to \opt{closerange} pages after it
  (about the \opt{closerange} option, see Section~\ref{sec:options}).

\item[far] Not \opt{close}.

\item[manual] A check which always fails.  Can be used to keep track of
  relations not covered by the other regular checks.

\end{description}


\section{Options}
\label{sec:options}

Options are a standard \texttt{key=value} comma separated list, and can be set
globally either as \cs{usepackage}\oarg{options} at load-time (see
Section~\ref{sec:loading-package}), or by means of \cs{zrefchecksetup} (see
Section~\ref{sec:user-interface}) in the preamble.  Most options can also be
used with local effects, through the optional argument of \cs{zcheck}.

\DescribeOption{hyperref} %
Controls the use of \pkg{hyperref} by \pkg{zref-check} and takes values
\opt{auto}, \opt{true}, \opt{false}.  The default value, \opt{auto}, makes
\pkg{zref-check} use \pkg{hyperref} if it is loaded, meaning \cs{zcheck} can
be hyperlinked to the \emph{first label} in \meta{labels}.  \opt{true} does
the same thing, but warns if \pkg{hyperref} is not loaded (\pkg{hyperref} is
never loaded for you).  In either of these cases, if \pkg{hyperref} is loaded,
module \pkg{zref-hyperref} is also loaded by \pkg{zref-check}.  \opt{false}
means not to use \pkg{hyperref} regardless of its availability.  This is a
preamble only option, but \cs{zcheck} provides granular control of
hyperlinking by means of its starred version.


\DescribeOption{msglevel} %
Sets the level of messages issued by \cs{zcheck} failed checks and takes
values \opt{warn}, \opt{info}, \opt{none}, \opt{infoifdraft},
\opt{warniffinal}.  The default value, \opt{warn}, issues messages both to the
terminal and to the log file, \opt{info} issues messages to the log file only,
\opt{none} suppresses all messages.  \opt{infoifdraft} corresponds to
\opt{info} if option \opt{draft} is passed to \cs{documentclass}, and to
\opt{warn} otherwise.  \opt{warniffinal} corresponds to \opt{warn} if option
\opt{final} is (explicitly) passed to \cs{documentclass} and \opt{info}
otherwise.  \opt{ignore} and \opt{ok} are provided as convenience aliases for
\opt{msglevel=none} for local use only.  This option only affects the messages
related to the checks in \cs{zcheck}, not other messages or warnings of the
package.  In particular, it does not affect warnings issued for undefined
labels, which just use \cs{zref@refused} and thus are the same as standard
\LaTeX{} ones for this purpose.


\DescribeOption{onpage} %
Allows to control the messaging style for ``within page checks'', and takes
values \opt{labelseq}, \opt{msg}, \opt{labelseqifdraft}, \opt{msgiffinal}.
The default, \opt{labelseq}, uses the labels' shipout sequence, as retrieved
from the \file{.aux} file, to infer relative position within the page.
\opt{msg} also uses the same method for checking relative position, but issues
a (different) message \emph{even if the check passes}, to provide a simple
workflow for robust checking of ``false negatives'', considering the label
sequence is not fool proof (for details and workflow recommendations, see
Section~\ref{sec:within-page-checks}).  \opt{msg} also issues its messages at
the same level defined in \opt{msglevel}.  \opt{labelseqifdraft} corresponds
to \opt{labelseq} if option \opt{draft} is passed to \cs{documentclass} and to
\opt{msg} otherwise.  \opt{msgiffinal} corresponds to \opt{msg} if option
\opt{final} is (explicitly) passed to \cs{documentclass}, and to
\opt{labelseq} otherwise.


\DescribeOption{closerange} %
Defines the width of the range of pages, relative to the reference, that are
considered ``close'' by the \opt{close} check.  Takes a positive integer as
value, with default 5.


\section{Limitations}

There are three qualitatively different kinds of checks being used by
\cs{zcheck}, according to the source and reliability of the information they
mobilize: page number checks, within page checks, and sectioning checks.

\subsection{Page number checks}

Page number checks -- \opt{thispage}, \opt{prevpage}, \opt{nextpage},
\opt{pagesbefore}, \opt{pagesafter}, \opt{facing} -- use the \texttt{abspage}
property provided by the \pkg{zref-abspage} module.  This is a solid piece of
information, on which we can rely upon.  However, despite that, page number
checks may still become ill-defined, if the \meta{text} argument in
\cs{zcheck}, when typeset, crosses page boundaries, starting in one page, and
finishing in another.  The same can happen with the text in \cs{zctarget} and
the \texttt{zcregion} environment.

This is why the user commands of this package set a pair or labels around
\meta{text}.  So, when checking \cs{zcheck} against a regular \texttt{zlabel}
both the start and the end of the \meta{text} are checked against the label,
and the check fails if either of them fails.  When checking \cs{zcheck}
against a \cs{zctarget} or a \texttt{zcregion}, both beginnings and ends are
checked against each other two by two, and if any of them fails, the check
fails.  In other words, if a page number checks passes, we know that the
entire \meta{text} arguments pass it.

This is a corner case (albeit relevant) which must be taken care of, and it is
possible to do so robustly.  Hence, we can expect reliable results in these
tests.


\subsection{Within page checks}
\label{sec:within-page-checks}

When both label and reference fall on the same page things become much
trickier.  This is basically the case of the checks \opt{above} and
\opt{below} (and, through them, \opt{before} and \opt{after}).  There is no
equally reliable information (that I know of) as we have for the page number
checks for this, especially when floats come into play.  Which, of course, is
the interesting case to handle.

To infer relative position of label and reference on the same page,
\pkg{zref-check} uses the labels' shipout sequence, which is retrieved at
load-time from the order in which the labels occur in the \file{.aux} file.
Indeed, \pkg{zref} writes labels to the \file{.aux} file at shipout (and,
hence, in shipout order), and needs to do so, because a number of its
properties are only available at that point.

However, even if this method will buy us a correct check for a regular float
on a regular page (which, to be fair, is a good result), it is not difficult
do conceive situations in which this sequence may not be meaningful, or even
correct, for the case.  A number of cases which may do so are: two column
documents, text wrapping, scaling, overlays, etc.  (I don't know if those make
the method fail, I just don't know if they don't).  Therefore, the
\texttt{labelseq} should be taken as a \emph{proxy} and not fully reliable,
meaning that the user should be watchful of its results.

For this reason, \pkg{zref-check} provides an easy way to do so, by allowing
specific control of the messaging style of the checks which do within page
comparisons though the option \opt{onpage}.  The concern is not really with
false positives (getting a warning when it was not due), but with false
negatives (not getting a warning when it was due).  Hence, setting
\opt{onpage} to \opt{msg} at a final typesetting stage (or just set it to
\opt{labelseqifdraft} or \opt{msgiffinal} if that's part of your workflow)
provides a way to easily identify all cases of such checks (failing or
passing), and double-check them.  In case the test is passing though, the
message is different from that of a failing check, to quickly convey why you
are getting the message.  This option can also be set at the local level, if
the page in question is known to be problematic, or just atypical.


\subsection{Sectioning checks}

The information used by sectioning checks is provided by means of dedicated
counters for chapters and sections, similarly as standard counters for them,
but which are stepped and reset regardless of whether these sectioning
commands are numbered or not (that is, starred or not).  And this for two
reasons.  First, we don't need the absolute counter value to be able to make
the kind of relative statement we want to do here.  Second, this allows us to
have these checks work for numbered and unnumbered sectioning commands without
having to worry about how those are used within the document.

The caveat is that the package does this by hooking into \cs{chapter} and
\cs{section}, which poses two restrictions for the proper working of these
checks.  First, we are using the new hook system for this, as provided by
\pkg{ltcmdhooks}, which means a \LaTeX{} kernel later than 2021-06-01 is
required.  Second, since we are hooking into \cs{chapter} and \cs{section},
these checks presume these commands are being used by the document class for
this purpose (either directly, or internally as, for example, KOMA-Script's
\cs{addchap} and \cs{addsec} do).  If that's not the case, additional setup
may be needed for these checks to work as expected.


\section{Change history}

A change log with relevant changes for each version, eventual upgrade
instructions, and upcoming changes, is maintained in the package's repository,
at \url{https://github.com/gusbrs/zref-check/blob/main/CHANGELOG.md}.  The
change log is also distributed with the package's documentation through CTAN
upon release so, most likely, \texttt{texdoc zref-check/changelog} should
provide easy local access to it.  An archive of historical versions of the
package is also kept at \url{https://github.com/gusbrs/zref-check/releases}.


\end{document}
