33 KiB
title | subtitle | author | date | lang | toc | license |
---|---|---|---|---|---|---|
crossrefenum | Smart typesetting of enumerated cross-references for various TeX formats | Bastien Dumont | 2024/04/13 | en-US | true | true |
crossrefenum lets TeX manage the formatting of bunches of cross-references for you. It features:
- Automatic collapsing of references;
- Support for references by various criteria, including page and note number, line number in ConTeXt and edpage and edline when used in conjunction with reledmac;
- Handling of references combining two criteria (e.g. by page and note number);
- Extension mechanisms to add support to other types of references without modifying the internal macros.
Note that sorting is not supported. I assume that users know in what order the labels they refer to appear in their document.
It is written in Plain TeX as much as possible in order to make it compatible with a wide array of formats. For the moment, it works out of the box with ConTeXt and LaTeX.
The file main-test.pdf
provides a showcase of the abilities of crossrefenum.
Loading
To load crossrefenum, provided that
crossrefenum.tex
, crossrefenum.sty
and t-crossrefenum.tex
are installed in a directory where TeX will find them
(presumably under the tex/generic/crossrefenum
directory of one of your texmf trees),
you can do:
\input{crossrefenum}
(generic);\usepackage{crossrefenum}
(LaTeX; must be called after nameref if you use hyperref\kern1.5pt
{=context});\usemodule[crossrefenum]
(ConTeXt).
Basic invocation
The macro \crossrefenum
has the following syntax:
\crossrefenum[type][print prefix?]{enumeration}
- type is the type of reference. Built-in possible values are:
- For LaTeX and ConTeXt:
page
,note
,pagenote
; - For ConTeXt only:
line
,pageline
; - For LaTeX with reledmac:
edpage
,edline
,edpageline
.
- For LaTeX and ConTeXt:
- print prefix? indicates whether the prefix (like “p. ”) should be printed or not: true if set to
withprefix
oryes
; - enumeration is a group containing one or more single labels (e.g.
{mylabel}
) or ranges (e.g.{lbl-begin to lbl-end}
) included in groups. Ranges cannot be used withnote
andpagenote
types.
type and print prefix? are optional. type defaults to page
and print prefix to withprefix
.
Here are some valid invocations:
\crossrefenum[note][withprefix]{{lblone}{lbltwo}{lblthree}}
\crossrefenum[edline][noprefix]{{lblone}{lbltwo}{lblthree}}
\crossrefenum[noprefix]{{lblone}{lbltwo}{lblthree}}
(type defaults topage
)\crossrefenum[note]{{lblone}{lbltwo}{lblthree}}
(print prefix? defaults towithprefix
)\crossrefenum{{lblone}{lbltwo}{lblthree}}
(type defaults topage
and print prefix? defaults towithprefix
)\crossrefenum{{only-one}}
(even if the enumeration is limited to one item, it must be inside its own group)
Customization
Customizing is done by redefining configuration macros. We describe the general mechanism first. Macros for double types are introduced at the end of this section.
Prefixes, delimiters and separators
Every simple type has two macros corresponding to the singular and plural prefixes printed before the value of the reference. By default, they are set to:
\def\crfnmPage{p.~}
\def\crfnmPages{pp.~}
\def\crfnmNote{n.~}
\def\crfnmNotes{nn.~}
\let\crfnmEdpage\crfnmPage
\let\crfnmEdpages\crfnmPages
\def\crfnmEdline{l.~}
\def\crfnmEdlines{ll.~}
Between successive items in an enumeration, \crossrefenum
calls \crfnmDefaultEnumDelim
or \crfnmDefaultBeforeLastInEnum
. By default, they are set to:
\def\crfnmDefaultEnumDelim{, }
\def\crfnmDefaultBeforeLastInEnum{ and }
The beginning and the end of a range are separated by \crfnmDefaultRangeSep
. By default:
\def\crfnmDefaultRangeSep{–}
Collapsable and non-collapsable types
The macro \crfnmDefaultCollapsable
defines if ranges are allowed.
The default configuration is:
\def\crfnmDefaultCollapsable{yes}
\def\crfnmNoteCollapsable{no}
Thus, a reference to consecutive notes is formatted like nn. 3, 4 and 5, not like nn. 3–5.
Ranges are not accepted in the argument of \crossrefenum
for non-collapsable types.
This extends to double types that include a non-collapsable type
(such as pagenote
in the default configuration).
Double types
Two subtypes in a double type (e.g. page and note number for pagenote
)
are separated by \crfnmDefaultSubtypesSep
. Default:
\def\crfnmDefaultSubtypesSep{, }
When more than one reference is cited in an enumeration,
you may not want the first prefix to be repeated every time
(e.g. you could prefer “pp. 5, n. 2; 7, n. 4” over “p. 5, n. 2; p. 7, n. 4”).
In that case, set \crfnmDefaultPrintFirstPrefix
to once
.
Default is:
\def\crfnmDefaultPrintFirstPrefix{always}
If you want to format the second part of the reference in a special way (e.g. in superscript),
use \crfnmDefaultFormatInSecond
,
which takes one argument which corresponds to the reference number and all its affixes.
Default is:
\def\crfnmDefaultFormatInSecond#1{#1}
If you don't want any prefix to be printed in the second term of a double reference,
set \crfnmDefaultPrintPrefixInSecond
to no
(default is yes).
For instance:
\def\crfnmEdlineFormatInSecond#1{\textsuperscript{#1}}
\def\crfnmEdlinePrintPrefixInSecond{no}
\crossrefenum[edpageline]{{mylabel}}
\noindentation
{=context} may return “p. 5^10^”, while \crossrefenum[edline]{{mylabel}}
would return “l. 10”.
For the second part of such an enumeration (e.g. “l. 10” in “p. 5, l. 10”),
you can specify a specific delimiter
and a specific string to be printed before the last reference:
for instance, you may want to use the word “and”
before the last note number if the reference type is a simple one (note
),
and a comma if it is comes in second in a double reference (e.g. in pagenote
).
To achieve this, you should redefine \crfnmDefaultEnumDelimInSecond
and \crfnmDefaultBeforeLastInSecond
.
By default, these macros fall back respectively
on \crfnmDefaultEnumDelim
and \crfnmDefaultBeforeLastInEnum
.
When citing a range, the two parts of the reference can
either be split (e.g. “p. 5, l. 3 – p. 7, l. 44”)
or grouped (“p. 5–7, l. 3–44”).
This is controlled via \crfnmDefaultGroupSubtypes
, which can be set to yes
or no
.
This works only with collapsable types.
Default is:
\def\crfnmDefaultGroupSubtypes{no}
To know if a reference to “p. 6, l. 34” should be merged with “p. 7, l. 35”,
crossrefenum needs to know if the lineation is
continuous (in this case, these lines are consecutive)
or per page (they are not, so they should not be merged).
You can set accordingly
\crfnmDefaultNumberingContinuousAcrossDocument
1 to yes
(default) or no
.
Note that crossrefenum cannot merge a reference
to the last line of a page and the first line of the following page
if the lineation is not continuous.
By default, the number of the first subtype in the name of the double type
(e.g. “page” in “pagenote”) is always displayed first.
If you want to change this, set \crfnmDefaultOrder
to inverted
(defaults to normal
).
Specific values for given types
If you want to override some of these macros for a specific type,
simply replace Default
in its name with the (capitalized) name of the type
(e.g. \def\crfnmPageEnumDelim{; }
).
Setting one of these macros to \relax
will cause \crossrefenum
to use the corresponding default macro instead.
If you want a specific macro to be set to nothing,
use an empty group (e.g. \def\crfnmPageEnumDelim{}
).
How to extend crossrefenum with other types and formats
Adding support for new types consists in defining the related macros in your preamble.
Here is a commented example that would add support for references to lines in ConTeXt
if this feature were not already included in crossrefenum.
We suppose that the labels are inserted in the document using the standard ConTeXt macros,
i.e. \someline
for line references and \pagereference
for page references.
% Register the types. Take care about capitalization!
%% Set the names of the types and their corresponding macros:
%% the control sequence should always be lowercase
%% and the name of the type capitalized.
\def\crfnm@line{Line}
\def\crfnm@pageline{Pageline}
%% Add them to the lists of known types.
\crfnm@declareType[simple][\crfnm@line]
\crfnm@declareType[double][\crfnm@pageline]
%% For the double types, set the primary and the secondary type.
%% The primary type corresponds to the widest typographic unit
%% (“page” for “pagenote”, “section” for “sectionpage”...).
\let\crfnm@PagelinePrimary\crfnm@page
\let\crfnm@PagelineSecondary\crfnm@line
% Define the macro used to typeset the reference number.
\def\crfnm@LineRef#1{\in[lr:b:#1]}
% Define the macro used by \crossrefenum internally
% to retrieve the raw reference number without typesetting it.
% This macro must be purely expandable.
% If you want to support multiple formats,
% see how the macro \crfnm@case is used in crossrefenum.tex.
% Note: the Lua function get_raw_ref_number is defined
% in crossrefenum.tex for ConTeXt.
\def\crfnm@getLineNumber#1{\directlua{get_raw_ref_number('lr:b:#1', 'linenumber')}}
% Define all specific configuration options in the regular way.
%% Required
\def\crfnmLine{l.~}
\def\crfnmLines{ll.~}
%% If it differs from the defaults.
\def\crfnmCollapsable{yes}
\def\crfnmLineBeforeLastInSecond{, }
\def\crfnmPagelineSubtypesSep{}
\def\crfnmPagelinePrintFirstPrefix{once}
\def\crfnmLineFormatInSecond#1{\crfnmSuperscript{#1}}
\def\crfnmLinePrintPrefixInSecond{no}
Adding support for additional formats is far less trivial, not least because most of them do not provide a straightforward way to get reference numbers via purely expandable macros, which is required for crossrefenum to perform its calculations. If you have wishes or hints about this, please contact me.
Compatibility issues
With LaTeX, the nameref package (required by hyperref\kern1.5pt
{=context})
must be loaded explicitely before crossrefenum.
However, if the links in the output of \crossrefenum
(not the numbers)
point to a wrong location, you may wish to patch the macro
to disable hyperref locally:
\makeatletter
\let\oldcrfnm@enum\crfnm@enum
\def\crfnm@enum[#1][#2]#3{\begin{NoHyper}\oldcrfnm@enum[#1][#2]{#3}\end{NoHyper}}
\makeatother
-
In this case, you could set more specifically
\crfnmLineNumberingContinuousAcrossDocument
or\crfnmEdlineNumberingContinuousAcrossDocument
: see the following subsection. ↩︎