%*********************************************************************** \def\crfnmName{crossrefenum} \def\crfnmShortDesc{Smart typesetting of enumerated cross-references for various TeX formats} \def\crfnmAuthor{Bastien Dumont} \def\crfnmDate{2023/02/20} \def\crfnmVersion{1.0.1} % % Copyright 2022-2023 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 %%% \crfnm@case[\fmtname] \crfnm@context: { \unexpanded\def\crossrefenum{\crfnm@crossrefenum} } \crfnm@latex: { \protected\def\crossrefenum{\crfnm@crossrefenum} } \crfnm@endCases % \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\crfnm@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: % *