From f7934ca125925655f6f228eb017ed474623acb80 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Mon, 14 Nov 2022 20:17:23 +0000 Subject: crossrefenum (14nov22) git-svn-id: svn://tug.org/texlive/trunk@65016 c570f23f-e606-0410-a88d-b1316a301751 --- .../tex/generic/crossrefenum/crossrefenum.sty | 3 + .../tex/generic/crossrefenum/crossrefenum.tex | 1497 ++++++++++++++++++++ .../tex/generic/crossrefenum/t-crossrefenum.tex | 18 + 3 files changed, 1518 insertions(+) create mode 100644 Master/texmf-dist/tex/generic/crossrefenum/crossrefenum.sty create mode 100644 Master/texmf-dist/tex/generic/crossrefenum/crossrefenum.tex create mode 100644 Master/texmf-dist/tex/generic/crossrefenum/t-crossrefenum.tex (limited to 'Master/texmf-dist/tex') diff --git a/Master/texmf-dist/tex/generic/crossrefenum/crossrefenum.sty b/Master/texmf-dist/tex/generic/crossrefenum/crossrefenum.sty new file mode 100644 index 00000000000..3d6ca15ae01 --- /dev/null +++ b/Master/texmf-dist/tex/generic/crossrefenum/crossrefenum.sty @@ -0,0 +1,3 @@ +\input crossrefenum.tex +\ProvidesPackage{crossrefenum}[\crfnmDate{} v\crfnmVersion{} Enumeration of cross-references] +\endinput \ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/crossrefenum/crossrefenum.tex b/Master/texmf-dist/tex/generic/crossrefenum/crossrefenum.tex new file mode 100644 index 00000000000..2b8d424a675 --- /dev/null +++ b/Master/texmf-dist/tex/generic/crossrefenum/crossrefenum.tex @@ -0,0 +1,1497 @@ +%*********************************************************************** +\def\crfnmName{crossrefenum} +\def\crfnmShortDesc{Smart typesetting of enumerated cross-references for various TeX formats} +\def\crfnmAuthor{Bastien Dumont} +\def\crfnmDate{2022/11/11} +\def\crfnmVersion{0.1} +% +% Copyright 2022 by Bastien Dumont (bastien.dumont@posteo.net) +% +% crossrefenum.tex 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 3 of the License, or +% (at your option) any later version. +% +% crossrefenum.tex 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 crossrefenum.tex. If not, see https://www.gnu.org/licenses/. +% +%*********************************************************************** + + + +% Terminology: +% – A simple reference is a reference by only one criterion (e.g. “page” or “note”). +% A double reference is a reference by two criteria (e.g. “page and note”), +% so has two subtypes: the primary and the secondary subtypes. +% Their labelling as primary and secondary is independant from their printed order : +% the primary subtype corresponds to the wider typographical unit, +% in which the secondary subtype is contained (so for “page and note”, +% the primary subtype is “page” and the secondary is “note”). +% – A single reference is a reference to one location (e.g. “p. 1”) +% A range is a reference to a span of text delimited by two single references (e.g. “pp. 1–5”). +% – An enumeration is a group containing a sequence of one or more references enclosed in groups. + +% Format-specific implementation notes: +% – In ConTeXt, the argument of \expanded cannot contain parameters: +% hence the ugly bridges of \expandafter that unfortunately cannot be +% replaced with a combination of \expanded and \noexpand. + +% How to add support for a new format: +% – Add a macro expanding to the name of the format at the beginning +% of the section “Initialization: Format-specific”; +% – Add a case in all blocks beginning with \crfnm@case[\fmtname] +% to setup the macros defined there with the required format-specific code. + + +% OUTLINE +% +% Initialization +% Catcodes +% Programming macros +% Format-specific +% Auxiliary file +% Constants +% Conditionals +% Auxiliary macros related to the data structure of \crossrefenum +% Default configuration +% +% \crossrefenum +% Public macro with optional arguments +% Main private macro +% Processing the individual references in the enumeration + +%%% Initialization: Catcodes %%% + +\newcount\crfnmOriginalCatcodeAt +% We can't write "crfnm@" here since the catcode +% of @ has not been redefined yet. +\crfnmOriginalCatcodeAt=\catcode`\@ +\catcode`\@=11 + +%%% Initialization: Programming macros %%% + +% \crfnm@case is a standard case statement. +% #1 is the string or the purely expandable macro to be tested. +% #2 is a sequence of tests of the form: +% value: token or group used if #1 is equal to value +% The sequence ends with \crfnm@endCases. +% In the groups to be executed, arguments in a macro definition +% have to be doubled. +% If all tests fails, does nothing and prints a warning on the terminal. + +\def\crfnm@case[#1] #2\crfnm@endCases{% + \begingroup + \edef\crfnm@comparandum{#1}% + \crfnm@@case #2% + \crfnm@comparandum: {% + \crfnm@warn{% + All tests failed in \unexpanded{\crfnm@case[#1] + #2 \crfnm@endCases}, doing nothing% + }% + } + \crfnm@endCases +} + +\def\crfnm@@case #1: #2{% + \edef\crfnm@comparans{#1}% + \ifx\crfnm@comparans\crfnm@comparandum + \def\crfnm@todo{\endgroup #2\crfnm@gobbleNextCases}% + \else + \def\crfnm@todo{\expandafter\crfnm@@case\crfnm@gobbleSpaces}% + \fi + \crfnm@todo +} + +\def\crfnm@gobbleSpaces#1{#1} + +\def\crfnm@gobbleNextCases #1\crfnm@endCases{} + +\def\crfnm@newCsnameAlias[#1]#2{% + % #1 is a control sequence (e.g. \mymacro). + % #2 is a cs name corresponding to an already defined + % control sequence (e.g. mappedto\tobereplaced). + \expandafter\let\expandafter#1\csname #2\endcsname +} + +\def\crfnm@capitalize#1{% + \expandafter\crfnm@uppercaseFirstLetter #1% +} + +\def\crfnm@uppercaseFirstLetter#1{% + % \uppercase, \lowercase and \crfnm@case + % are not purely expandable + \ifx#1aA% + \else\ifx#1bB% + \else\ifx#1cC% + \else\ifx#1dD% + \else\ifx#1eE% + \else\ifx#1fF% + \else\ifx#1gG% + \else\ifx#1hH% + \else\ifx#1iI% + \else\ifx#1jJ% + \else\ifx#1kK% + \else\ifx#1lL% + \else\ifx#1mM% + \else\ifx#1nN% + \else\ifx#1oO% + \else\ifx#1pP% + \else\ifx#1qQ% + \else\ifx#1rR% + \else\ifx#1sS% + \else\ifx#1tT% + \else\ifx#1uU% + \else\ifx#1vV% + \else\ifx#1wW% + \else\ifx#1xX% + \else\ifx#1yY% + \else\ifx#1zZ% + % In forks, the first argument of \crossrefenum is \crfnm@secondarySubtype, + % so it is already capitalized. + \else #1% + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi +} + +\def\crfnm@ifequal[#1][#2]#3#4{% + \edef\crfnm@comparans{#1}% + \edef\crfnm@comparandum{#2}% + \ifx\crfnm@comparans\crfnm@comparandum #3\else #4\fi +} + +\def\crfnm@loopOverArgs #1with #2{% + \crfnm@loopOver@args[#2]#1\crfnm@end +} + +\def\crfnm@loopOver@args[#1]#2{% + % #1 is the macro with one argument + % to be called with #2 + \edef\crfnm@arg{#2}% + \ifx\crfnm@arg\crfnm@end + \def\crfnm@todo{}% + \else + #1{#2}% + \def\crfnm@todo{\crfnm@loopOver@args[#1]}% + \fi + \crfnm@todo +} + +\def\crfnm@ifIsOneOf[#1][#2]#3#4{% + % #1 expands to a string, #2 expands to a list + \crfnm@foundfalse + \def\crfnm@setIfFound ##1{% + \edef\crfnm@itemSearched{#1}% + \edef\crfnm@toBeTested{##1}% + \ifx\crfnm@toBeTested\crfnm@itemSearched + \crfnm@foundtrue + \fi + }% + \expandafter\crfnm@loopOverArgs #2with \crfnm@setIfFound + \ifcrfnm@found + \def\crfnm@todo{#3}% + \else + \def\crfnm@todo{#4}% + \fi + \crfnm@todo +} + +%%% Initialization: Format-specific %%% + +% \fmtname changes between MKIV and LMTX in ConTeXt, +% so we use the value of \contextformat (to which \fmtname +% is made let-equal in ConTeXt). +% See https://source.contextgarden.net/tex/context/base/mkiv/context.mkiv?search=%5Cfmtname#l49 +\edef\crfnm@context{\csname contextformat\endcsname} +\def\crfnm@latex{LaTeX2e} +\def\crfnm@optex{OpTeX} + +% Supported types +\crfnm@case[\fmtname] + \crfnm@context: { + \def\crfnm@supportedTypes{{\crfnm@page}{\crfnm@note}{\crfnm@line}{\crfnm@pagenote}{\crfnm@pageline}} + } + \crfnm@latex: { + \def\crfnm@supportedTypes{{\crfnm@page}{\crfnm@note}{\crfnm@edpage}{\crfnm@edline}{\crfnm@pagenote}{\crfnm@edpageline}} + } +\crfnm@endCases + +% The following format-specific instructions are necessary to get +% the raw page number, which is used in comparisons. +% The raw page number must be unique (e.g. absolute page number). +% It must be possible to get it via a purely expandable macro. +\crfnm@case[\fmtname] + \crfnm@context: { + % Since I have not found any ConTeXt macro to get the raw values, + % we look directly in the auxiliary file from the second pass on. + \directlua{ + ordered_ref_data = structures.lists.collected + arbitrary_ref_data = structures.references.collected + function get_raw_ref_number(label, type) + found = false + if arbitrary_ref_data then + for _, ref_data in pairs(arbitrary_ref_data) do + if ref_data[label] then + label_data = ref_data[label] + for _, data_part in pairs(label_data) do + if data_part[type] then + found = true + tex.print(data_part[type]) + end + end + end + end + end + if not(found) and ordered_ref_data then + for i = 1, \luaescapestring{\utfchar{0x0023}ordered_ref_data} do + if ordered_ref_data[i].references.reference == label then + found = true + tex.print(ordered_ref_data[i].references[type]) + end + end + end + if not(found) then tex.print(0) end + end + } + } + \crfnm@latex: { + % If you use nameref (e.g. through hyperref), + % please make sure to load it before this code + % so that it does not erase our redefinition of \label. + % More details here: + % https://comp.text.tex.narkive.com/PI1P2Nlt/hyperref-and-redefining-label-ref-and-pageref-again + \RequirePackage[abspage]{zref} + \zref@setdefault{0} + \let\crfnm@label@beforezref\label + \def\label##1{% + \crfnm@label@beforezref{##1}% + \zref@labelbyprops{##1}{abspage, default}% + } + } +\crfnm@endCases + +% Macros for getting raw reference numbers. +% They must be purely expandable. +\crfnm@case[\fmtname] + \crfnm@context: { + \def\crfnm@getPageNumber##1{\directlua{get_raw_ref_number('##1', 'realpage')}} + \def\crfnm@getNoteNumber##1{\directlua{get_raw_ref_number('##1', 'order')}} + \def\crfnm@getLineNumber##1{\directlua{get_raw_ref_number('lr:b:##1', 'linenumber')}} + } + \crfnm@latex: { + \def\crfnm@getPageNumber##1{\zref@extract{##1}{abspage}} + \def\crfnm@getNoteNumber##1{\zref@extract{##1}{default}} + \def\crfnm@getEdpageNumber##1{\xpageref{##1}} + \def\crfnm@getEdlineNumber##1{\xlineref{##1}} + } +\crfnm@endCases + +% Macros for typesetting the references. +\crfnm@case[\fmtname] + \crfnm@context: { + \def\crfnm@PageRef##1{\at[##1]} + \def\crfnm@NoteRef##1{\in[##1]} + \def\crfnm@LineRef##1{\in[lr:b:##1]} + } + \crfnm@latex: { + \def\crfnm@PageRef##1{\pageref{##1}} + \def\crfnm@NoteRef##1{\ref{##1}} + \def\crfnm@EdpageRef##1{\edpageref{##1}} + \def\crfnm@EdlineRef##1{\edlineref{##1}} + } +\crfnm@endCases + +% Formatting macros +\crfnm@case[\fmtname] + \crfnm@context: { + \let\crfnmSuperscript\high + \let\crfnmSubscript\low + } + \crfnm@latex: { + \let\crfnmSuperscript\textsuperscript + \let\crfnmSubscript\textsubscript + } +\crfnm@endCases + +% Issue warnings +% \crfnm@warn@newPassNeeded is needed only for those format +% that may not reprocess the TeX file automatically +% when the auxiliary file changed. +\crfnm@case[\fmtname] + \crfnm@latex: { + \let\crfnm@warn@newPassNeeded\@latex@warning@no@line + } + \fmtname: {\let\crfnm@warn@newPassNeeded\relax} +\crfnm@endCases + + +%%% Initialization: Auxiliary file %%% + +% Configure the auxiliary file. +\crfnm@case[\fmtname] + \crfnm@context: { + \definedataset[printedRefsNb] + } + \crfnm@latex: { + \let\crfnm@auxfile\@auxout + } +\crfnm@endCases + +% Initialize the counter used in the auxiliary file +% to identify the informations associated with each +% call to \crossrefenum +\newcount\crfnm@ienum +\crfnm@ienum=0 +% In double references, we need to count separately +% the number of typeset references (after collapsing) +% for each part. To do this, we divide by 2 the maximum value +% that a counter can have and we use the result +% as the start of the index for \crfnm@ienum when used +% on the secondary subtype of a double reference. +% As a consequence, it is not possible to use \crossrefenum +% more than 2^30/2 times in the same document. +\newcount\crfnm@ienum@secondaryOfDouble +\crfnm@ienum@secondaryOfDouble=0 +\def\crfnm@secondaryOfDouble@istart{536870912} % = 2^30/2 +% This counter is used to register the total number +% of typeset references for every invocation of \crossrefenum +% (for a simple reference) or for each part of a double reference. +\newcount\crfnm@printedRefsNb +\crfnm@printedRefsNb=0 + +%%% Initialization: Constants %%% + +% Keywords and parameter values +\def\crfnm@empty{} +\def\crfnm@always{always} +\def\crfnm@yes{yes} +\def\crfnm@plural{pl} +\def\crfnm@first{first} +\def\crfnm@singleFirst{singlefirst} +\def\crfnm@end{crfnm@end} +\def\crfnm@labelRangeSep{ to } +\def\crfnm@withPrefix{withprefix} +\def\crfnm@enumend{crfnm@enumend} +\def\crfnm@normal{normal} +\def\crfnm@crossrefenum@secondArg@possibleValues{{withprefix}{noprefix}{yes}{no}} + +% Reference types +% Reledmac \pstartref is not supported, since users know if two consecutive references +% are in the same paragraph or not. They can alternate between direct use of \pstartref +% and \crossrefenum for lines and/or pages. +% \annotationref is not supported because I don't have any experience of it. +\def\crfnm@page{Page} +\def\crfnm@note{Note} +\def\crfnm@line{Line} +\def\crfnm@edpage{Edpage} +\def\crfnm@edline{Edline} +\def\crfnm@pagenote{Pagenote} +\def\crfnm@pageline{Pageline} +\def\crfnm@edpageline{Edpageline} +\let\crfnm@PagenotePrimary\crfnm@page +\let\crfnm@PagenoteSecondary\crfnm@note +\let\crfnm@PagelinePrimary\crfnm@page +\let\crfnm@PagelineSecondary\crfnm@line +\let\crfnm@EdpagelinePrimary\crfnm@edpage +\let\crfnm@EdpagelineSecondary\crfnm@edline + +%%% Initialization: Conditionals %%% + +\newif\ifcrfnm@found +\newif\ifcrfnm@enumIsFinished +\newif\ifcrfnm@simulated +\newif\ifcrfnm@areSingleAndRange +\newif\ifcrfnm@isFirstToken +\newif\ifcrfnm@singleFirst + + +%%% Initialization: Auxiliary macros related to the data structure of \crossrefenum %%% + +\edef\crfnm@simpleRefTypes{{\crfnm@page}{\crfnm@note}{\crfnm@line}{\crfnm@edpage}{\crfnm@edline}} +\edef\crfnm@doubleRefTypes{{\crfnm@pagenote}{\crfnm@pageline}{\crfnm@edpageline}} +\edef\crfnm@customizableDefaultConfig{{Collapsable}{EnumDelim}{EnumDelimInSecond}{BeforeLastInEnum}{BeforeLastInSecond}{RangeSep}} +\edef\crfnm@customizableDefaultDoubleConfig{{Collapsable}{EnumDelim}{BeforeLastInEnum}{RangeSep}{SubtypesSep}{PrintFirstPrefix}{GroupSubtypes}{Order}} +\edef\crfnm@customizableDefaultSecondaryOfDoubleConfig{{Collapsable}{NumberingContinuousAcrossDocument}{PrintPrefixInSecond}{FormatInSecond}} + +\newif\ifcrfnm@isDoubleRef +\def\crfnm@ifIsDoubleRef#1#2{\ifcrfnm@isDoubleRef #1\else #2\fi} + +\def\crfnm@ifIsRange#1#2#3{% + \expandafter\crfnm@ifIs\crfnm@labelRangeSep @in {#1} {#2} {#3}% +} + +\def\crfnm@ifIs#1@in #2#3#4{% + \def\crfnm@ifIsIn##1#1##2\@nil{% + \def\crfnm@afterSubstring{##2}% + \ifx\crfnm@afterSubstring\crfnm@empty #4\else #3\fi + }% + \expandafter\crfnm@ifIsIn#2#1\@nil +} + +\def\crfnm@enumid#1{% + \crfnm@ifIsSecondaryOfDouble[ienum: #1]{% + secondaryofdouble@% + \romannumeral\numexpr #1-\crfnm@secondaryOfDouble@istart\relax + @\romannumeral\the\crfnm@ienum@secondaryOfDouble + }{% + \romannumeral #1% + }% +} + +\def\crfnm@currEnumId{\crfnm@enumid{\the\crfnm@ienum}} + +\def\crfnm@ifIsSecondaryOfDouble[ienum: #1]#2#3{% + \ifnum #1 > \crfnm@secondaryOfDouble@istart + #2% + \else + #3% + \fi +} + +\def\crfnm@setIfIsDoubleRef{% + \crfnm@ifIsOneOf[\crfnm@refType][\crfnm@doubleRefTypes]{% + \crfnm@isDoubleReftrue + }{% + \crfnm@isDoubleReffalse + }% +} + +\def\crfnm@ifIsList[#1]#2#3{% + \expandafter\futurelet\expandafter\crfnm@nextToken + \expandafter\crfnm@ifIsBgroup #1\endofcheck{#2}{#3}% +} + +\def\crfnm@ifIsBgroup#1\endofcheck#2#3{% + % \crfnm@nextToken is the first token in the #1 of \crfnm@ifIsList. + % All the #1 of \crfnm@ifIsList is stored here in #1 and discarded. + \ifx\crfnm@nextToken\bgroup #2\else #3\fi +} + +\def\crfnm@newListFrom[#1][#2] -> #3{% + % #1 is either a list or a reference. + % #2 is a reference. + % #2 is appended to #1. + % #3 is the control sequence which the resulting list will be bound to. + \crfnm@ifIsList[#1]{% + \edef#3{#1{#2}}% + }{% + \edef#3{{#1}{#2}}% + }% +} + +\def\crfnm@replaceFirstInList[#1]#2{% + % #1 is a token, #2 is a list of tokens + {#1}\crfnm@gobbleFirst #2% +} + +\def\crfnm@gobbleFirst#1{} + + +%%% Initialization: Default configuration %%% + +% Prefixes +\def\crfnmPage{p.~} +\def\crfnmPages{pp.~} +\def\crfnmNote{n.~} +\def\crfnmNotes{nn.~} +\def\crfnmLine{l. } +\def\crfnmLines{ll.} +\let\crfnmEdpage\crfnmPage +\let\crfnmEdpages\crfnmPages +\def\crfnmEdline{l.~} +\def\crfnmEdlines{ll.~} + +% Macros with typed and default variants +\def\crfnmDefaultCollapsable{yes} +\def\crfnmNoteCollapsable{no} +\def\crfnmDefaultNumberingContinuousAcrossDocument{yes} +\def\crfnmDefaultEnumDelim{, } +\let\crfnmDefaultEnumDelimInSecond\crfnmDefaultEnumDelim +\def\crfnmDefaultBeforeLastInEnum{ and } +\let\crfnmDefaultBeforeLastInSecond\crfnmDefaultBeforeLastInEnum +\def\crfnmDefaultRangeSep{–} +\def\crfnmDefaultSubtypesSep{, } +\def\crfnmDefaultPrintFirstPrefix{always} +\def\crfnmDefaultFormatInSecond#1{#1} +\def\crfnmDefaultPrintPrefixInSecond{yes} +\def\crfnmDefaultGroupSubtypes{no} +\let\crfnmDefaultOrder\crfnm@normal + +%%% \crossrefenum %%% + +%%% \crossrefenum: Public macro with optional arguments %%% + +% \crossrefenum has two optional arguments. +% See the definition of \crfnm@enum below for the recognized values. + +\def\crfnm@firstArg@default{page} +\def\crfnm@secondArg@default{withprefix} + +\def\crossrefenum{% + \futurelet\crfnm@nextToken\crfnm@setEnumMacro +} + +\def\crfnm@setEnumMacro{% + \ifx\crfnm@nextToken [% + \def\crfnm@todo{\crfnm@setArgAndContinue[first]}% + \else + \def\crfnm@todo{% + \expandafter\expandafter\expandafter\crfnm@enum + \expandafter\expandafter\expandafter + % The following line break must be commented out. + [\expandafter\crfnm@firstArg@default\expandafter]% + \expandafter[\crfnm@secondArg@default]% + }% + \fi + \crfnm@todo +} + +\def\crfnm@setArgAndContinue[#1][#2]{% + % #1 is "first" or "second" + % #2 is one of the optional arguments + % passed to the main macro + \def\crfnm@argPos{#1}% + \def\crfnm@argValue{#2}% + \futurelet\crfnm@nextToken\crfnm@set@argAndContinue +} + +\def\crfnm@set@argAndContinue{% + \ifx\crfnm@argPos\crfnm@first + \ifx\crfnm@nextToken [% + \edef\crfnm@firstArg{[\crfnm@argValue]}% + \def\crfnm@todo{\crfnm@setArgAndContinue[second]}% + \else + \crfnm@ifIsOneOf[\crfnm@argValue][\crfnm@crossrefenum@secondArg@possibleValues]{% + \def\crfnm@todo{% + \crfnm@enum[\crfnm@firstArg@default][\crfnm@argValue]% + }% + }{% + \def\crfnm@todo{% + \crfnm@enum[\crfnm@argValue][\crfnm@secondArg@default]% + }% + }% + \fi + \else + \def\crfnm@todo{% + \expandafter\crfnm@enum\crfnm@firstArg[\crfnm@argValue]% + }% + \fi + \crfnm@todo +} + +%%% \crossrefenum: Main private macro %%% + +\def\crfnm@enum[#1][#2]#3{% + % #1 = reference type + % #2 = withprefix / noprefix or yes / no + % #3 = the enumeration + {% + % Initializes the environment for this invocation, + % then passes the enumeration to the parsing + % and formatting macro \crfnm@formatEnum. + \global\advance\crfnm@ienum by 1 + % The reference type is capitalized so that it can be used + % to refer to macro names typed in camelCase + % (e.g. in \crfnm@initializeCsnames). + \edef\crfnm@refType{\crfnm@capitalize{#1}}% + \crfnm@ifIsOneOf[\crfnm@refType][\crfnm@supportedTypes]{}{% + \errmessage{crossrefenum: Unsupported type + #1 for format \fmtname{}.} + }% + \crfnm@setIfIsDoubleRef + \crfnm@applyDefaultConfigIfUndefined + \crfnm@initializeCsnames + \edef\crfnm@hasPrefix{#2}% + \ifx\crfnm@hasPrefix\crfnm@withPrefix + \let\crfnm@hasPrefix\crfnm@yes + \fi + \crfnm@enumIsFinishedfalse + \crfnm@isFirstTokentrue + \crfnm@ifIsSecondaryOfDouble[ienum: \the\crfnm@ienum]{% + \global\advance\crfnm@ienum@secondaryOfDouble by 1 + }{}% + % We get the number of references typeset for the current + % invocation of \crossrefenum in the last compilation to know + % whether to use the singular or plural form of the prefix. + \edef\crfnm@printedRefsNb@previousPass{% + \crfnm@getPrintedRefsNb@previousPass + }% + % The following macro will process sequentially + % all references in the enumeration. + \expandafter\crfnm@formatEnum#3{crfnm@enumend}% + }% +} + +\def\crfnm@applyDefaultConfigIfUndefined{% + \def\crfnm@applyToThisType{\crfnm@applyDefaultMacroToType[\crfnm@refType]}% + \crfnm@ifIsDoubleRef{% + \expandafter\crfnm@loopOverArgs \crfnm@customizableDefaultDoubleConfig with \crfnm@applyToThisType + \crfnm@setSubtypesOrder + \def\crfnm@applyToPrimarySubtype{\crfnm@applyDefaultMacroToType[\csname crfnm@\crfnm@refType Primary\endcsname]}% + \expandafter\crfnm@loopOverArgs \crfnm@customizableDefaultConfig with \crfnm@applyToPrimarySubtype + \def\crfnm@applyToSecondarySubtype{\crfnm@applyDefaultMacroToType[\csname crfnm@\crfnm@refType Secondary\endcsname]}% + \expandafter\crfnm@loopOverArgs \crfnm@customizableDefaultSecondaryOfDoubleConfig with \crfnm@applyToSecondarySubtype + }{% + \expandafter\crfnm@loopOverArgs \crfnm@customizableDefaultConfig with \crfnm@applyToThisType + }% +} + +\def\crfnm@applyDefaultMacroToType[#1]#2{% + % #1 = type, #2 = csname without "crfnmDefault" + % \csname crfnm#1#2\endcsname is the csname for this type + \expandafter\ifx\csname crfnm#1#2\endcsname\relax + % The csname must be generated before it is passed + % to \let in \crfnm@newCsnameAlias + \expandafter\crfnm@newCsnameAlias\expandafter[\csname crfnm#1#2\endcsname] + {crfnmDefault#2}% + \fi +} + +\def\crfnm@initializeCsnames{% + \crfnm@newCsnameAlias[\crfnm@rangeSep]{crfnm\crfnm@refType RangeSep}% + \crfnm@ifIsDoubleRef{% + \crfnm@newCsnameAlias[\crfnm@doubleRefOrder]{crfnm\crfnm@refType Order}% + \crfnm@newCsnameAlias[\crfnm@firstSubtype]{crfnm@\crfnm@refType First}% + \crfnm@newCsnameAlias[\crfnm@secondSubtype]{crfnm@\crfnm@refType Second}% + \crfnm@newCsnameAlias[\crfnm@primarySubtype]{crfnm@\crfnm@refType Primary}% + \crfnm@newCsnameAlias[\crfnm@secondarySubtype]{crfnm@\crfnm@refType Secondary}% + \crfnm@newCsnameAlias[\crfnm@getRawValuePrimary]{crfnm@get\crfnm@primarySubtype Number}% + \crfnm@newCsnameAlias[\crfnm@getRawValueSecondary]{crfnm@get\crfnm@secondarySubtype Number}% + \crfnm@newCsnameAlias[\crfnm@primaryCollapsable]{crfnm\crfnm@primarySubtype Collapsable}% + \crfnm@newCsnameAlias[\crfnm@secondaryCollapsable]{crfnm\crfnm@secondarySubtype Collapsable}% + \crfnm@newCsnameAlias[\crfnm@secondaryNumberingContinuous]{crfnm\crfnm@secondarySubtype NumberingContinuousAcrossDocument}% + \crfnm@newCsnameAlias[\crfnm@enumDelim]{crfnm\crfnm@refType EnumDelim}% + \crfnm@newCsnameAlias[\crfnm@beforeLastInEnum]{crfnm\crfnm@refType BeforeLastInEnum}% + \crfnm@newCsnameAlias[\crfnm@separatorBetweenSubtypes]{crfnm\crfnm@refType SubtypesSep}% + \crfnm@newCsnameAlias[\crfnm@formatSecondary]{crfnm\crfnm@secondarySubtype FormatInSecond}% + \crfnm@newCsnameAlias[\crfnm@printFirstPrefix]{crfnm\crfnm@refType PrintFirstPrefix}% + \crfnm@newCsnameAlias[\crfnm@isSecondaryPrefixPrinted]{crfnm\crfnm@secondarySubtype PrintPrefixInSecond}% + \crfnm@newCsnameAlias[\crfnm@groupSubtypes]{crfnm\crfnm@refType GroupSubtypes}% + }{% + \crfnm@ifIsSecondaryOfDouble[ienum: \the\crfnm@ienum]{% + \crfnm@newCsnameAlias[\crfnm@enumDelim]{crfnm\crfnm@refType EnumDelimInSecond}% + \crfnm@newCsnameAlias[\crfnm@beforeLastInEnum]{crfnm\crfnm@refType BeforeLastInSecond}% + }{% + \crfnm@newCsnameAlias[\crfnm@enumDelim]{crfnm\crfnm@refType EnumDelim}% + \crfnm@newCsnameAlias[\crfnm@beforeLastInEnum]{crfnm\crfnm@refType BeforeLastInEnum}% + }% + \crfnm@newCsnameAlias[\crfnm@collapsable]{crfnm\crfnm@refType Collapsable}% + \crfnm@newCsnameAlias[\crfnm@getRawValue]{crfnm@get\crfnm@refType Number}% + \crfnm@newCsnameAlias[\crfnm@typesetSingleRef]{crfnm@\crfnm@refType Ref}% + }% +} + +\def\crfnm@setSubtypesOrder{% + \crfnm@newCsnameAlias[\crfnm@thisTypePrimary]{crfnm@\crfnm@refType Primary}% + \crfnm@newCsnameAlias[\crfnm@thisTypePrimary]{crfnm@\crfnm@refType Primary}% + \expandafter\ifx\csname crfnm\crfnm@refType Order\endcsname\crfnm@normal + \expandafter\let\csname crfnm@\crfnm@refType First\endcsname% + \crfnm@thisTypePrimary + \expandafter\let\csname crfnm@\crfnm@refType Second\endcsname% + \crfnm@thisTypeSecondary + \else + \expandafter\let\csname crfnm@\crfnm@refType First\endcsname% + \crfnm@thisTypeSecondary + \expandafter\let\csname crfnm@\crfnm@refType Second\endcsname% + \crfnm@thisTypePrimary + \fi +} + +\def\crfnm@ifIsInverted#1#2{% + \ifx\crfnm@doubleRefOrder\crfnm@normal #2\else #1\fi +} + +% Get the number of the parts of the current enumeration +% in the preceding pass from the auxiliary file. +% The macro must be purely expandable and return a number. +\crfnm@case[\fmtname] + \crfnm@context: { + \def\crfnm@getPrintedRefsNb@previousPass{% + \directlua{ + registeredValue = '\datasetvariable{printedRefsNb}{\crfnm@currEnumId}{value}' + if registeredValue == '' then tex.print(0) else tex.print(registeredValue) end + }% + } + } + \fmtname: { + \def\crfnm@getPrintedRefsNb@previousPass{% + \expandafter + \ifx\csname crfnm@printedrefsnb@\crfnm@currEnumId\endcsname\relax + 0 + \else + \csname crfnm@printedrefsnb@\crfnm@currEnumId\endcsname + \fi + } + } +\crfnm@endCases + +%%% \crossrefenum: Processing the individual references in the enumeration %%% + +\def\crfnm@formatEnum#1{% + % #1 is a string consisting of either: + % *