crossrefenum/doc/crossrefenum.md

33 KiB
Raw Permalink Blame History

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.
  • print prefix? indicates whether the prefix (like “p. ”) should be printed or not: true if set to withprefix or yes;
  • 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 with note and pagenote 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 to page)
  • \crossrefenum[note]{{lblone}{lbltwo}{lblthree}} (print prefix? defaults to withprefix)
  • \crossrefenum{{lblone}{lbltwo}{lblthree}} (type defaults to page and print prefix? defaults to withprefix)
  • \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. 35.

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. 57, l. 344”). 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 \crfnmDefaultNumberingContinuousAcrossDocument1 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

  1. In this case, you could set more specifically \crfnmLineNumberingContinuousAcrossDocument or \crfnmEdlineNumberingContinuousAcrossDocument: see the following subsection. ↩︎