1498 lines
49 KiB
TeX
1498 lines
49 KiB
TeX
%***********************************************************************
|
||
\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:
|
||
% * <label>
|
||
% * <label1> to <label2>
|
||
% * crfnm@enumend
|
||
\crfnm@ifIsBeginOfEnum{%
|
||
\crfnm@setCurrentRef{#1}%
|
||
% We typeset the prefix at the beginning of the enumeration
|
||
% for simple references for it appears once at the beginning of the enumeration.
|
||
% For double references, it is typeset at the beginning
|
||
% of every part of the enumeration.
|
||
\crfnm@ifIsDoubleRef{}{\crfnm@typesetPrefix}%
|
||
}{%
|
||
\crfnm@triggerWarnings{#1}%
|
||
\crfnm@advanceInEnumWith{#1}%
|
||
% The following macro compares the current reference
|
||
% with the preceding one and either merges them
|
||
% or typesets the preceding reference.
|
||
\crfnm@combine
|
||
}%
|
||
\crfnm@ifIsEndOfEnum{%
|
||
\ifnum\crfnm@printedRefsNb@previousPass=\the\crfnm@printedRefsNb\relax\else
|
||
\crfnm@warn@newPassNeeded{%
|
||
crossrefenum changed some enumerations.
|
||
Rerun to get all prefixes right.%
|
||
}%
|
||
\fi
|
||
\crfnm@registerPrintedRefsNb
|
||
\crfnm@ifIsDoubleRef{\global\crfnm@ienum@secondaryOfDouble=0}{}%
|
||
}{%
|
||
\expandafter\crfnm@formatEnum
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@setCurrentRef#1{%
|
||
\crfnm@ifIsDoubleRef{%
|
||
\def\crfnm@currentPrimary{#1}%
|
||
\def\crfnm@currentSecondary{#1}%
|
||
}{%
|
||
\def\crfnm@current{#1}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@ifIsBeginOfEnum#1#2{%
|
||
\edef\crfnm@csnameCurrent{%
|
||
crfnm@current\ifcrfnm@isDoubleRef Primary\fi%
|
||
}%
|
||
\expandafter\ifx\csname\crfnm@csnameCurrent\endcsname\relax
|
||
#1%
|
||
\else
|
||
#2%
|
||
\fi
|
||
}
|
||
|
||
\def\crfnm@typesetPrefix{%
|
||
\ifx\crfnm@hasPrefix\crfnm@yes
|
||
\crfnm@ifIsDoubleRef{%
|
||
\crfnm@ifIsInverted{%
|
||
\crfnm@typeset@@prefix[sg]%
|
||
}{%
|
||
\ifx\crfnm@printFirstPrefix\crfnm@always
|
||
\crfnm@typeset@@prefix[sg]%
|
||
\else
|
||
\ifcrfnm@isFirstToken\crfnm@typeset@prefix\fi
|
||
\fi
|
||
}%
|
||
}{%
|
||
\crfnm@typeset@prefix
|
||
}%
|
||
\fi
|
||
}
|
||
|
||
\def\crfnm@typeset@prefix{%
|
||
\ifnum\crfnm@printedRefsNb@previousPass>1
|
||
\crfnm@typeset@@prefix[pl]%
|
||
\else
|
||
\crfnm@typeset@@prefix[sg]%
|
||
\fi
|
||
}
|
||
|
||
\def\crfnm@typeset@@prefix[#1]{%
|
||
\def\crfnm@prefixform{#1}%
|
||
\csname crfnm%
|
||
\crfnm@ifIsDoubleRef{%
|
||
\crfnm@ifIsInverted{\crfnm@secondSubtype}{\crfnm@firstSubtype}%
|
||
}{%
|
||
\crfnm@refType
|
||
}%
|
||
\ifx\crfnm@prefixform\crfnm@plural s\fi
|
||
\endcsname
|
||
}
|
||
|
||
\def\crfnm@triggerWarnings#1{%
|
||
% Raises the “undefined label” or “references have changed” warnings
|
||
% even if the label doesn't get used in this pass, thus causing a new
|
||
% pass to be performed.
|
||
% Works in LaTeX because warnings are sent via \immediate\write.
|
||
% It should also work in ConTeXt because it writes the logs through
|
||
% a Lua call, not \write.
|
||
\def\crfnm@tested{#1}%
|
||
\ifx\crfnm@tested\crfnm@enumend\else
|
||
\setbox0=\hbox{\crfnm@simulateTypesetting{#1}}%
|
||
\fi
|
||
}
|
||
|
||
\def\crfnm@simulateTypesetting#1{%
|
||
\crfnm@simulatedtrue
|
||
\crfnm@ifIsDoubleRef{%
|
||
% We can't use \crfnm@typesetdouble here, for it would result
|
||
% in nested calls to \setbox0.
|
||
% Nevertheless we have to test for both subtypes,
|
||
% since the value of each of them may change
|
||
% while that of the other remains the same.
|
||
\let\crfnm@realRefType\crfnm@refType%
|
||
\crfnm@isDoubleReffalse
|
||
\edef\crfnm@refType{\crfnm@primarySubtype}%
|
||
\crfnm@initializeCsnames
|
||
\crfnm@wrapInDisplayMacro{#1}%
|
||
\edef\crfnm@refType{\crfnm@secondarySubtype}%
|
||
\crfnm@initializeCsnames
|
||
\crfnm@wrapInDisplayMacro{#1}%
|
||
\let\crfnm@refType\crfnm@realRefType
|
||
\crfnm@isDoubleReftrue
|
||
\crfnm@initializeCsnames
|
||
}{%
|
||
\crfnm@wrapInDisplayMacro{#1}%
|
||
}%
|
||
\crfnm@simulatedfalse
|
||
}
|
||
|
||
\def\crfnm@advanceInEnumWith#1{%
|
||
\crfnm@ifIsDoubleRef{%
|
||
\let\crfnm@precedingPrimary\crfnm@currentPrimary
|
||
\let\crfnm@precedingSecondary\crfnm@currentSecondary
|
||
\def\crfnm@currentPrimary{#1}%
|
||
\def\crfnm@currentSecondary{#1}%
|
||
}{%
|
||
\let\crfnm@preceding\crfnm@current
|
||
\def\crfnm@current{#1}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@combine{%
|
||
\crfnm@ifIsEndOfEnum{%
|
||
\crfnm@enumIsFinishedtrue
|
||
\ifcrfnm@isFirstToken\else\crfnm@beforeLastInEnum\fi
|
||
\crfnm@typesetPrecedingRef
|
||
}{%
|
||
\crfnm@compareTypes
|
||
\ifcrfnm@areSingleAndRange
|
||
\crfnm@combineSingleAndRange
|
||
\else
|
||
\edef\crfnm@maybeRange{\csname crfnm@current\crfnm@ifIsDoubleRef{Primary}{}\endcsname}%
|
||
\crfnm@ifIsRange\crfnm@maybeRange{%
|
||
\crfnm@combineRanges
|
||
}{%
|
||
\crfnm@combineSingles
|
||
}%
|
||
\fi
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@ifIsEndOfEnum#1#2{%
|
||
\edef\crfnm@currentInEnum{%
|
||
\crfnm@ifIsDoubleRef{%
|
||
\crfnm@currentPrimary
|
||
}{%
|
||
\crfnm@current
|
||
}%
|
||
}%
|
||
\ifx\crfnm@currentInEnum\crfnm@enumend
|
||
#1%
|
||
\else
|
||
#2%
|
||
\fi
|
||
}
|
||
|
||
% Write the number of the parts of the current enumeration
|
||
% to the auxiliary file.
|
||
\def\crfnm@registerPrintedRefsNb{%
|
||
\crfnm@case[\fmtname]
|
||
\crfnm@context: {%
|
||
\ifx\fmtname\crfnm@context
|
||
\setdataset[printedRefsNb][\crfnm@currEnumId][value={\the\crfnm@printedRefsNb}]%
|
||
\fi
|
||
}
|
||
\fmtname: {%
|
||
\immediate\write\crfnm@auxfile{%
|
||
\gdef\expandafter\noexpand\csname crfnm@printedrefsnb@\crfnm@currEnumId\endcsname
|
||
{\the\crfnm@printedRefsNb}%
|
||
}%
|
||
}
|
||
\crfnm@endCases
|
||
}
|
||
|
||
\def\crfnm@typesetPrecedingRef{%
|
||
\crfnm@ifIsDoubleRef{%
|
||
\crfnm@typesetDoubleRef{\crfnm@precedingPrimary}{\crfnm@precedingSecondary}%
|
||
}{%
|
||
\crfnm@wrapInDisplayMacro{\crfnm@preceding}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@compareTypes{%
|
||
\crfnm@setPossibleRangeCs
|
||
\crfnm@ifIsRange{\crfnm@possibleRange@preceding}{%
|
||
\crfnm@ifIsRange{\crfnm@possibleRange@current}{%
|
||
\crfnm@areSingleAndRangefalse
|
||
}{%
|
||
\crfnm@areSingleAndRangetrue
|
||
}%
|
||
}{%
|
||
\crfnm@ifIsRange{\crfnm@possibleRange@current}{%
|
||
\crfnm@areSingleAndRangetrue
|
||
}{%
|
||
\crfnm@areSingleAndRangefalse
|
||
}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@setPossibleRangeCs{%
|
||
% We use the secondary subtype, since it can become a range
|
||
% as an effect of \crfnm@combineSingles while the primary subtype
|
||
% keeps being a single; the reverse can't be true.
|
||
\crfnm@newCsnameAlias[\crfnm@possibleRange@preceding]{crfnm@preceding\ifcrfnm@isDoubleRef Secondary\fi}%
|
||
\crfnm@newCsnameAlias[\crfnm@possibleRange@current]{crfnm@current\ifcrfnm@isDoubleRef Secondary\fi}%
|
||
}
|
||
|
||
\def\crfnm@combineSingles{%
|
||
\crfnm@ifIsDoubleRef{%
|
||
\crfnm@combine@singles@double
|
||
}{%
|
||
\crfnm@combine@singles@simple
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@combine@singles@double{%
|
||
\edef\crfnm@raw@precedingPrimary{\crfnm@getRawValuePrimary\crfnm@precedingPrimary}%
|
||
\edef\crfnm@raw@currentPrimary{\crfnm@getRawValuePrimary\crfnm@currentPrimary}%
|
||
\crfnm@ifequal[\crfnm@raw@precedingPrimary][\crfnm@raw@currentPrimary]{%
|
||
\edef\crfnm@currentPrimary{\crfnm@precedingPrimary}%
|
||
\crfnm@newListFrom[\crfnm@precedingSecondary][\crfnm@currentSecondary] -> \crfnm@currentSecondary
|
||
}{%
|
||
\crfnm@typesetPrecedingRange
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@combine@singles@simple{%
|
||
\edef\crfnm@raw@preceding{\crfnm@getRawValue\crfnm@preceding}%
|
||
\edef\crfnm@raw@current{\crfnm@getRawValue\crfnm@current}%
|
||
\crfnm@ifequal[\crfnm@raw@preceding][\crfnm@raw@current]{%
|
||
%Do nothing, so discard \crfnm@preceding.
|
||
}{%
|
||
\crfnm@ifConsecutiveCollapsable[\crfnm@raw@preceding][\crfnm@raw@current]{%
|
||
\edef\crfnm@current{\crfnm@preceding\crfnm@labelRangeSep\crfnm@current}%
|
||
}{%
|
||
\ifcrfnm@isFirstToken\else
|
||
\crfnm@enumDelim
|
||
\fi
|
||
\crfnm@wrapInDisplayMacro{\crfnm@preceding}%
|
||
}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@combineRanges{%
|
||
\crfnm@ifIsDoubleRef{%
|
||
\crfnm@combine@ranges@doubles
|
||
}{%
|
||
\crfnm@combine@ranges@simples
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@getLabelInRange@begin[#1]{%
|
||
\expandafter\crfnm@get@labelInRange@begin\expandafter[#1]%
|
||
}
|
||
\def\crfnm@getLabelInRange@end[#1]{%
|
||
\expandafter\crfnm@get@labelInRange@end\expandafter[#1]%
|
||
}
|
||
\expandafter\def\expandafter\crfnm@get@labelInRange@begin\expandafter[\expandafter#\expandafter1\crfnm@labelRangeSep#2]{#1}%
|
||
\expandafter\def\expandafter\crfnm@get@labelInRange@end\expandafter[\expandafter#\expandafter1\crfnm@labelRangeSep#2]{#2}%
|
||
|
||
\def\crfnm@combine@ranges@simples{%
|
||
\edef\crfnm@precedingBegin{\crfnm@getLabelInRange@begin[\crfnm@preceding]}%
|
||
\edef\crfnm@precedingEnd{\crfnm@getLabelInRange@end[\crfnm@preceding]}%
|
||
\edef\crfnm@currentBegin{\crfnm@getLabelInRange@begin[\crfnm@current]}%
|
||
\edef\crfnm@currentEnd{\crfnm@getLabelInRange@end[\crfnm@current]}%
|
||
\edef\crfnm@raw@precedingBegin{\crfnm@getRawValue\crfnm@precedingBegin}%
|
||
\edef\crfnm@raw@precedingEnd{\crfnm@getRawValue\crfnm@precedingEnd}%
|
||
\edef\crfnm@raw@currentBegin{\crfnm@getRawValue\crfnm@currentBegin}%
|
||
\edef\crfnm@raw@currentEnd{\crfnm@getRawValue\crfnm@currentEnd}%
|
||
\def\crfnm@mergeRanges{%
|
||
\edef\crfnm@current{\crfnm@precedingBegin\crfnm@labelRangeSep\crfnm@currentEnd}%
|
||
}%
|
||
\crfnm@ifequal[\crfnm@raw@precedingEnd][\crfnm@raw@currentBegin]{%
|
||
\crfnm@mergeRanges
|
||
}{%
|
||
\crfnm@ifConsecutiveCollapsable[\crfnm@raw@precedingEnd][\crfnm@raw@currentBegin]{%
|
||
\crfnm@mergeRanges
|
||
}{%
|
||
\ifcrfnm@isFirstToken\else\crfnm@enumDelim\fi
|
||
\crfnm@wrapInDisplayMacro{\crfnm@preceding}%
|
||
}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@combine@ranges@doubles{%
|
||
% \crfnm@<pre/cur>Secondary are identical with \crfnm@<pre/cur>Primary
|
||
% at the beginning and at the end of this macro
|
||
% because the secondary value may not be an enumeration
|
||
% at either ends of a range.
|
||
% That is why we don't use them in our comparisons here.
|
||
% Note: when the lineation is not continuous, we cannot handle
|
||
% properly the case where the end of the first range is on the last
|
||
% line of a page and the beginning of the second range is on the
|
||
% first line of the following page. This is because we cannot know
|
||
% if a given line is the last on the page.
|
||
\edef\crfnm@precedingBegin{\crfnm@getLabelInRange@begin[\crfnm@precedingPrimary]}%
|
||
\edef\crfnm@precedingEnd{\crfnm@getLabelInRange@end[\crfnm@precedingPrimary]}%
|
||
\edef\crfnm@currentBegin{\crfnm@getLabelInRange@begin[\crfnm@currentPrimary]}%
|
||
\edef\crfnm@currentEnd{\crfnm@getLabelInRange@end[\crfnm@currentPrimary]}%
|
||
\edef\crfnm@primarySubtype@precedingEnd{\crfnm@getRawValuePrimary\crfnm@precedingEnd}%
|
||
\edef\crfnm@primarySubtype@currentBegin{\crfnm@getRawValuePrimary\crfnm@currentBegin}%
|
||
\edef\crfnm@secondarySubtype@precedingEnd{\crfnm@getRawValueSecondary\crfnm@precedingEnd}%
|
||
\edef\crfnm@secondarySubtype@currentBegin{\crfnm@getRawValueSecondary\crfnm@currentBegin}%
|
||
\crfnm@ifequal[\crfnm@primarySubtype@precedingEnd][\crfnm@primarySubtype@currentBegin]{%
|
||
\crfnm@ifequal[\crfnm@secondarySubtype@precedingEnd][\crfnm@secondarySubtype@currentBegin]{%
|
||
\crfnm@mergeRanges
|
||
}{%
|
||
\crfnm@ifConsecutiveCollapsable[secondary]%
|
||
[\crfnm@secondarySubtype@precedingEnd][\crfnm@secondarySubtype@currentBegin]
|
||
{%
|
||
\crfnm@mergeRanges
|
||
}{%
|
||
\edef\crfnm@primarySubtype@precedingBegin{\crfnm@getRawValuePrimary\crfnm@precedingBegin}%
|
||
\edef\crfnm@primarySubtype@currentEnd{\crfnm@getRawValuePrimary\crfnm@currentEnd}%
|
||
\crfnm@ifequal[\crfnm@primarySubtype@precedingBegin][\crfnm@primarySubtype@currentEnd]{%
|
||
% Two discountinuous ranges of the secondary subtype on the same page.
|
||
\crfnm@newListFrom[\crfnm@precedingSecondary][\crfnm@currentSecondary] -> \crfnm@currentSecondary
|
||
}{%
|
||
\crfnm@typesetPrecedingRange
|
||
}%
|
||
}%
|
||
}%
|
||
}{%
|
||
\ifx\crfnm@secondaryNumberingContinuous\crfnm@yes
|
||
% It would make no sense to test for identical line numbers here.
|
||
\crfnm@ifConsecutiveCollapsable[primary]%
|
||
[\crfnm@primarySubtype@precedingEnd][\crfnm@primarySubtype@currentBegin]
|
||
{%
|
||
\crfnm@ifConsecutiveCollapsable[secondary]%
|
||
[\crfnm@secondarySubtype@precedingEnd][\crfnm@secondarySubtype@currentBegin]
|
||
{%
|
||
\crfnm@mergeRanges
|
||
}{%
|
||
\crfnm@typesetPrecedingRange
|
||
}%
|
||
}{%
|
||
\crfnm@typesetPrecedingRange
|
||
}%
|
||
\else
|
||
\crfnm@typesetPrecedingRange
|
||
\fi
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@mergeRanges{%
|
||
\edef\crfnm@currentPrimary{\crfnm@precedingBegin\crfnm@labelRangeSep\crfnm@currentEnd}%
|
||
\let\crfnm@currentSecondary\crfnm@currentPrimary
|
||
}
|
||
|
||
\def\crfnm@combineSingleAndRange{%
|
||
\crfnm@setPossibleRangeCs
|
||
\crfnm@ifIsRange{\crfnm@possibleRange@current}{%
|
||
\crfnm@combine@singleAndRange[singlefirst]%
|
||
}{%
|
||
\crfnm@combine@singleAndRange[reversed]%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@typesetPrecedingRange{%
|
||
\ifcrfnm@isFirstToken\else
|
||
\crfnm@enumDelim
|
||
\fi
|
||
\crfnm@typesetDoubleRef{\crfnm@precedingPrimary}{\crfnm@precedingSecondary}%
|
||
}%
|
||
|
||
\def\crfnm@combine@singleAndRange[#1]{%
|
||
\crfnm@setIfIsSingleFirst[#1]%
|
||
\crfnm@ifIsDoubleRef{%
|
||
\crfnm@combine@single@and@range@double
|
||
}{%
|
||
\ifcrfnm@singleFirst
|
||
\let\crfnm@single\crfnm@preceding
|
||
\let\crfnm@range\crfnm@current
|
||
\else
|
||
\let\crfnm@single\crfnm@current
|
||
\let\crfnm@range\crfnm@preceding
|
||
\fi
|
||
\crfnm@combine@single@and@range@simple
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@setIfIsSingleFirst[#1]{%
|
||
\def\crfnm@singlePos{#1}% expected: singlefirst or reversed
|
||
\ifx\crfnm@singlePos\crfnm@singleFirst
|
||
\crfnm@singleFirsttrue
|
||
\else
|
||
\crfnm@singleFirstfalse
|
||
\fi
|
||
}
|
||
|
||
\def\crfnm@combine@single@and@range@simple{%
|
||
\edef\crfnm@begin@range{\crfnm@getLabelInRange@begin[\crfnm@range]}%
|
||
\edef\crfnm@end@range{\crfnm@getLabelInRange@end[\crfnm@range]}%
|
||
\edef\crfnm@raw@single{\crfnm@getRawValue\crfnm@single}%
|
||
\edef\crfnm@raw@begin@range{\crfnm@getRawValue\crfnm@begin@range}%
|
||
\edef\crfnm@raw@end@range{\crfnm@getRawValue\crfnm@end@range}%
|
||
\ifcrfnm@singleFirst
|
||
\crfnm@ifAreEqualOrConsecutiveCollapsable[][\crfnm@raw@single][\crfnm@raw@begin@range]{%
|
||
\edef\crfnm@current{%
|
||
\crfnm@newRangeWithReplacement[change: \crfnm@current, with: \crfnm@preceding, at: beg]%
|
||
}%
|
||
}{%
|
||
\crfnm@typesetInEnum{\crfnm@preceding}%
|
||
}%
|
||
\else
|
||
\crfnm@ifequal[\crfnm@raw@end@range][\crfnm@raw@single]{%
|
||
\edef\crfnm@current{\crfnm@preceding}%
|
||
}{%
|
||
\crfnm@ifConsecutiveCollapsable[\crfnm@raw@end@range][\crfnm@raw@single]{%
|
||
\edef\crfnm@current{%
|
||
\crfnm@newRangeWithReplacement[change: \crfnm@preceding, with: \crfnm@current, at: end]%
|
||
}%
|
||
}{%
|
||
\crfnm@typesetInEnum{\crfnm@preceding}%
|
||
}%
|
||
}%
|
||
\fi
|
||
}
|
||
|
||
\def\crfnm@combine@single@and@range@double{%
|
||
\ifcrfnm@singleFirst
|
||
\edef\crfnm@currentBegin{\crfnm@getLabelInRange@begin[\crfnm@currentPrimary]}%
|
||
\edef\crfnm@primaryRawValue@preceding{\crfnm@getRawValuePrimary\crfnm@precedingPrimary}%
|
||
\edef\crfnm@primaryRawValue@current{\crfnm@getRawValuePrimary\crfnm@currentBegin}%
|
||
\edef\crfnm@secondaryRawValue@preceding{\crfnm@getRawValueSecondary\crfnm@precedingSecondary}%
|
||
\edef\crfnm@secondaryRawValue@current{\crfnm@getRawValueSecondary\crfnm@currentBegin}%
|
||
\let\crfnm@typesetPreceding\crfnm@typesetPrecedingRef
|
||
\def\crfnm@rangeRoot{crfnm@current}%
|
||
\def\crfnm@singleRoot{crfnm@preceding}%
|
||
\else
|
||
\edef\crfnm@precedingEnd{\crfnm@getLabelInRange@end[\crfnm@precedingPrimary]}%
|
||
\edef\crfnm@primaryRawValue@preceding{\crfnm@getRawValuePrimary\crfnm@precedingEnd}%
|
||
\edef\crfnm@primaryRawValue@current{\crfnm@getRawValuePrimary\crfnm@currentPrimary}%
|
||
\edef\crfnm@secondaryRawValue@preceding{\crfnm@getRawValueSecondary\crfnm@precedingEnd}%
|
||
\edef\crfnm@secondaryRawValue@current{\crfnm@getRawValueSecondary\crfnm@currentSecondary}%
|
||
\let\crfnm@typesetPreceding\crfnm@typesetPrecedingRange
|
||
\def\crfnm@rangeRoot{crfnm@preceding}%
|
||
\def\crfnm@singleRoot{crfnm@current}%
|
||
\fi
|
||
\crfnm@ifequal[\crfnm@primaryRawValue@current][\crfnm@primaryRawValue@preceding]{%
|
||
\crfnm@ifAreEqualOrConsecutiveCollapsable[secondary]%
|
||
[\crfnm@secondaryRawValue@current][\crfnm@secondaryRawValue@preceding]%
|
||
{%
|
||
\crfnm@mergeSingleAndRangeDouble
|
||
}{%
|
||
\crfnm@typesetPreceding
|
||
}%
|
||
}{%
|
||
\crfnm@ifConsecutiveCollapsable[secondary]%
|
||
[\crfnm@secondaryRawValue@current][\crfnm@secondaryRawValue@preceding]%
|
||
{%
|
||
\crfnm@mergeSingleAndRangeDouble
|
||
}{%
|
||
\crfnm@typesetPreceding
|
||
}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@mergeSingleAndRangeDouble{%
|
||
\edef\crfnm@changedBoundary{\ifcrfnm@singleFirst beg\else end\fi}%
|
||
\crfnm@mergeSingleAndRangeDouble@subtype
|
||
[changeRoot: \crfnm@rangeRoot, withRoot: \crfnm@singleRoot, at: \crfnm@changedBoundary][Primary]%
|
||
\crfnm@mergeSingleAndRangeDouble@subtype
|
||
[changeRoot: \crfnm@rangeRoot, withRoot: \crfnm@singleRoot, at: \crfnm@changedBoundary][Secondary]%
|
||
}
|
||
|
||
\def\crfnm@mergeSingleAndRangeDouble@subtype[changeRoot: #1, withRoot: #2, at: #3][#4]{%
|
||
\edef\crfnm@rangeToBeChanged{\csname #1#4\endcsname}%
|
||
\edef\crfnm@singleForChange{\csname #2#4\endcsname}%
|
||
\expandafter\edef\csname crfnm@current#4\endcsname{%
|
||
\crfnm@newRangeWithReplacement
|
||
[change: \crfnm@rangeToBeChanged, with: \crfnm@singleForChange, at: #3]%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@ifAreEqualOrConsecutiveCollapsable[#1][#2][#3]#4#5{%
|
||
% #1 is “primary”, “secondary” or empty (for simple types).
|
||
\crfnm@ifequal[#2][#3]{#4}{%
|
||
\crfnm@ifConsecutiveCollapsable[#1][#2][#3]{#4}{#5}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@ifConsecutiveCollapsable[#1]{%
|
||
% If the current reference has a double type, this macro must carry a first argument
|
||
% indicating if the current subtype is “primary”, “secondary”.
|
||
% With a simple type, it may be missing or empty.
|
||
% The other two arguments are the raw reference values to be compared.
|
||
% The comparison itself is performed by \crfnm@if@consecutiveCollapsable,
|
||
% which takes the type indication as a mandatory argument.
|
||
% The following code here simply sets the type if it is not provided by the user.
|
||
\crfnm@ifIsOneOf[#1][{{primary}{secondary}{}}]{%
|
||
\def\crfnm@macroWithParam{\crfnm@if@consecutiveCollapsable[#1]}%
|
||
}{%
|
||
\def\crfnm@macroWithParam{\crfnm@if@consecutiveCollapsable[][#1]}%
|
||
}%
|
||
\crfnm@macroWithParam
|
||
}
|
||
|
||
\def\crfnm@if@consecutiveCollapsable[#1][#2][#3]#4#5{%
|
||
% #1 is “primary”, “secondary” or empty (for simple types).
|
||
% #2 and #3 are the raw numbers for the first and the second references.
|
||
\crfnm@newCsnameAlias[\crfnm@thisTypeCollapsable]{crfnm@\crfnm@ifIsDoubleRef{#1C}{c}ollapsable}%
|
||
\crfnm@newCsnameAlias[\crfnm@testedType]{crfnm@\crfnm@ifIsDoubleRef{#1Subtype}{refType}}%
|
||
\ifx\crfnm@thisTypeCollapsable\crfnm@yes
|
||
\crfnm@ifSimpleOrPrimaryType{% Uses \crfnm@testedType
|
||
\crfnm@ifAreConsecutive[#2][#3]{#4}{#5}%
|
||
}{%
|
||
\ifx\crfnm@secondaryNumberingContinuous\crfnm@yes
|
||
\crfnm@ifAreConsecutive[#2][#3]{#4}{#5}%
|
||
\else #5\fi
|
||
}%
|
||
\else #5\fi
|
||
}
|
||
|
||
\def\crfnm@ifSimpleOrPrimaryType#1#2{%
|
||
\crfnm@ifIsOneOf[\crfnm@testedType][\crfnm@simpleRefTypes]{#1}{%
|
||
\ifx\crfnm@testedType\crfnm@primarySubtype #1\else #2\fi
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@ifAreConsecutive[#1][#2]#3#4{%
|
||
\ifnum\numexpr#1+1\relax=#2 #3\else #4\fi
|
||
}
|
||
|
||
\def\crfnm@newRangeWithReplacement[change: #1, with: #2, at: #3#4]{%
|
||
% #3#4 is “beg” or “end” (we test only the first letter).
|
||
% This macro must be purely expandable.
|
||
\ifx #3b%
|
||
#2 to \crfnm@getLabelInRange@end[#1]%
|
||
\else
|
||
\crfnm@getLabelInRange@begin[#1] to #2%
|
||
\fi
|
||
}
|
||
|
||
\def\crfnm@typesetInEnum#1{%
|
||
\ifcrfnm@isFirstToken\else\crfnm@enumDelim\fi
|
||
\crfnm@wrapInDisplayMacro{#1}%
|
||
}
|
||
|
||
\def\crfnm@wrapInDisplayMacro#1{%
|
||
\crfnm@countInPrintedRefs
|
||
\crfnm@wrapRangeOrSingle{#1}%
|
||
\crfnm@isFirstTokenfalse
|
||
}
|
||
|
||
\def\crfnm@countInPrintedRefs{%
|
||
\ifcrfnm@simulated\else
|
||
% Since the incrementation is local,
|
||
% \crfnm@printedRefsNb will be automatically reset to 0
|
||
% at the end of the current invocation of \crossrefenum.
|
||
\advance\crfnm@printedRefsNb by 1
|
||
\fi
|
||
}
|
||
|
||
\def\crfnm@wrapRangeOrSingle#1{%
|
||
\edef\crfnm@toBeWrapped{#1}%
|
||
\crfnm@ifIsRange{\crfnm@toBeWrapped}{%
|
||
\crfnm@wrapRange{\crfnm@toBeWrapped}%
|
||
}{%
|
||
\crfnm@ifIsDoubleRef{%
|
||
% We are in the primary part of a double type,
|
||
% since the secondary one is handled by \crfnm@fork
|
||
% like a simple type.
|
||
\crfnm@newCsnameAlias[\crfnm@typesetSingleRef]{crfnm@\crfnm@primarySubtype Ref}%
|
||
}{}%
|
||
\crfnm@typesetSingleRef{\crfnm@toBeWrapped}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@wrapRange#1{%
|
||
\expandafter\crfnm@wrap@range\expandafter[#1]%
|
||
}
|
||
|
||
\expandafter\def\expandafter\crfnm@wrap@range\expandafter[\expandafter#\expandafter1\crfnm@labelRangeSep#2]{%
|
||
\crfnm@typesetRange{#1}{#2}%
|
||
}
|
||
|
||
\def\crfnm@typesetRange#1#2{%
|
||
\edef\crfnm@refTypeForRange{%
|
||
\crfnm@ifIsDoubleRef{\crfnm@primarySubtype}{\crfnm@refType}%
|
||
}%
|
||
\edef\crfnm@beginRangeToTypeset{#1}%
|
||
\edef\crfnm@endRangeToTypeset{#2}%
|
||
\crfnm@typeset@range{\crfnm@beginRangeToTypeset}{\crfnm@endRangeToTypeset}[%
|
||
cs to get the raw reference number: crfnm@get\crfnm@refTypeForRange Number,
|
||
cs to print the reference: crfnm@\crfnm@refTypeForRange Ref%
|
||
]%
|
||
}
|
||
|
||
\def\crfnm@typeset@range#1#2[%
|
||
cs to get the raw reference number: #3,
|
||
cs to print the reference: #4%
|
||
]{%
|
||
% #1 and #2 are the labels
|
||
\def\crfnm@getCountCsname{#3}%
|
||
\edef\crfnm@firstNumber{\csname\crfnm@getCountCsname\endcsname{#1}}%
|
||
\edef\crfnm@secondNumber{\csname\crfnm@getCountCsname\endcsname{#2}}%
|
||
\def\crfnm@typeset{\expandafter\csname #4\endcsname}%
|
||
\ifx\crfnm@firstNumber\crfnm@secondNumber
|
||
\crfnm@typeset{#1}%
|
||
\else
|
||
\crfnm@countInPrintedRefs
|
||
\crfnm@typeset{#1}\crfnm@rangeSep\crfnm@typeset{#2}%
|
||
\fi
|
||
}
|
||
|
||
\def\crfnm@typesetDoubleRef#1#2{%
|
||
% #1 is a label
|
||
% #2 is a list of labels to be passed to \crossrefenum
|
||
\crfnm@ifIsInverted{%
|
||
\crfnm@typesetDoubleRef@inverted{#1}{#2}%
|
||
}{%
|
||
\crfnm@typesetDoubleRef@normal{#1}{#2}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@typesetDoubleRef@normal#1#2{%
|
||
\ifx\crfnm@groupSubtypes\crfnm@yes
|
||
\crfnm@typesetDoubleRef@normal@grouped{#1}{#2}%
|
||
\else
|
||
\crfnm@typesetDoubleRef@normal@split{#1}{#2}%
|
||
\fi
|
||
}
|
||
|
||
\def\crfnm@typesetDoubleRef@normal@grouped#1#2{%
|
||
\crfnm@typesetPrefix
|
||
\crfnm@wrapInDisplayMacro{#1}%
|
||
\crfnm@separatorBetweenSubtypes
|
||
\crfnm@formatSecondary{%
|
||
\crfnm@fork{%
|
||
\crfnm@ifIsList[#2]{%
|
||
\edef\crfnm@enumOfSecondary{#2}%
|
||
}{%
|
||
\edef\crfnm@enumOfSecondary{{#2}}%
|
||
}%
|
||
\crfnm@enum[\crfnm@secondarySubtype][\crfnm@isSecondaryPrefixPrinted]{\crfnm@enumOfSecondary}%
|
||
}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@typesetDoubleRef@normal@split#1#2{%
|
||
\edef\crfnm@labelForPrimary{#1}%
|
||
\crfnm@ifIsRange\crfnm@labelForPrimary{%
|
||
\crfnm@typesetDoubleRef@normal@split@range{#1}{#2}%
|
||
}{%
|
||
\crfnm@typesetDoubleRef@normal@split@single{#1}{#2}%
|
||
}%
|
||
}
|
||
|
||
\def\crfnm@typesetDoubleRef@normal@split@range#1#2{%
|
||
\edef\crfnm@labelForPrimary{#1}%
|
||
\edef\crfnm@beginRangeLabel{%
|
||
\crfnm@getLabelInRange@begin[\crfnm@labelForPrimary]%
|
||
}%
|
||
\edef\crfnm@endRangeLabel{%
|
||
\crfnm@getLabelInRange@end[\crfnm@labelForPrimary]%
|
||
}%
|
||
\edef\crfnm@beginPrimaryRaw{\crfnm@getRawValuePrimary\crfnm@beginRangeLabel}%
|
||
\edef\crfnm@endPrimaryRaw{\crfnm@getRawValuePrimary\crfnm@endRangeLabel}%
|
||
\ifx\crfnm@beginPrimaryRaw\crfnm@endPrimaryRaw
|
||
\edef\crfnm@labelsForSecondary{#2}%
|
||
\crfnm@typesetDoubleRef@normal@grouped{\crfnm@beginRangeLabel}{#2}%
|
||
\else
|
||
\crfnm@ifIsList[#2]{%
|
||
\edef\crfnm@allSecondaryLabels{#2}%
|
||
}{%
|
||
\edef\crfnm@allSecondaryLabels{{#2}}%
|
||
}%
|
||
\edef\crfnm@labelsForSecondary{%
|
||
\crfnm@replaceFirstInList[\crfnm@endRangeLabel]{\crfnm@allSecondaryLabels}%
|
||
}%
|
||
\crfnm@typesetPrefix
|
||
\crfnm@wrapInDisplayMacro{\crfnm@beginRangeLabel}%
|
||
\crfnm@separatorBetweenSubtypes
|
||
\crfnm@formatSecondary{%
|
||
\crfnm@fork{%
|
||
\crfnm@enum[\crfnm@secondarySubtype][\crfnm@isSecondaryPrefixPrinted]{%
|
||
{\crfnm@beginRangeLabel}%
|
||
}%
|
||
}%
|
||
}%
|
||
\crfnm@rangeSep
|
||
\crfnm@wrapInDisplayMacro{\crfnm@endRangeLabel}%
|
||
\crfnm@separatorBetweenSubtypes
|
||
\crfnm@formatSecondary{%
|
||
\crfnm@fork{%
|
||
\crfnm@enum[\crfnm@secondarySubtype][\crfnm@isSecondaryPrefixPrinted]{\crfnm@labelsForSecondary}%
|
||
}%
|
||
}%
|
||
\fi
|
||
}
|
||
|
||
\def\crfnm@typesetDoubleRef@normal@split@single#1#2{%
|
||
\crfnm@typesetDoubleRef@normal@grouped{#1}{#2}%
|
||
}
|
||
|
||
\def\crfnm@typesetDoubleRef@inverted#1#2{%
|
||
\crfnm@formatSecondary{%
|
||
\crfnm@fork{%
|
||
\crfnm@ifIsList[#2]{%
|
||
\edef\crfnm@enumOfSecondary{#2}%
|
||
}{%
|
||
\edef\crfnm@enumOfSecondary{{#2}}%
|
||
}%
|
||
\crfnm@enum[\crfnm@secondarySubtype][withprefix]{\crfnm@enumOfSecondary}%
|
||
}%
|
||
}%
|
||
\crfnm@separatorBetweenSubtypes
|
||
\crfnm@typesetPrefix
|
||
\crfnm@wrapInDisplayMacro{#1}%
|
||
}
|
||
|
||
\def\crfnm@fork#1{%
|
||
\crfnm@saveState
|
||
\global\advance\crfnm@ienum by \crfnm@secondaryOfDouble@istart
|
||
\global\advance\crfnm@ienum by -1
|
||
\crfnm@printedRefsNb=0
|
||
#1%
|
||
\crfnm@restoreState
|
||
}
|
||
|
||
\def\crfnm@saveState{%
|
||
\edef\crfnm@parentIenum{\the\crfnm@ienum}%
|
||
\edef\crfnm@parentPrintedRefsNb{\the\crfnm@printedRefsNb}%
|
||
\let\crfnm@parentCurrentPrimary\crfnm@currentPrimary
|
||
\let\crfnm@parentCurrentSecondary\crfnm@currentSecondary
|
||
\let\crfnm@parentPrecedingPrimary\crfnm@precedingPrimary
|
||
\let\crfnm@parentPrecedingSecondary\crfnm@precedingSecondary
|
||
\let\crfnm@parentRefType\crfnm@refType
|
||
}
|
||
|
||
\def\crfnm@restoreState{%
|
||
\crfnm@isDoubleReftrue
|
||
\global\crfnm@ienum=\crfnm@parentIenum
|
||
\crfnm@printedRefsNb=\crfnm@parentPrintedRefsNb
|
||
\let\crfnm@currentPrimary\crfnm@parentCurrentPrimary
|
||
\let\crfnm@currentSecondary\crfnm@parentCurrentSecondary
|
||
\let\crfnm@precedingPrimary\crfnm@parentPrecedingPrimary
|
||
\let\crfnm@precedingSecondary\crfnm@parentPrecedingSecondary
|
||
\let\crfnm@refType\crfnm@parentRefType
|
||
}
|
||
|
||
\catcode`\@=\crfnmOriginalCatcodeAt
|
||
|