\cref
\Cref
\crefrange
\Crefrange
Define the main referencing command \cref and the start-of-sentence variant
\Cref, along with the reference range commands\crefrangeand\Crefrange.
1065\DeclareRobustCommand{\cref}[1]{\@cref{cref}{#1}}
1066\DeclareRobustCommand{\Cref}[1]{\@cref{Cref}{#1}}
1067\DeclareRobustCommand{\crefrange}[2]{\@setcrefrange{#1}{#2}{cref}{}}
1068\DeclareRobustCommand{\Crefrange}[2]{\@setcrefrange{#1}{#2}{Cref}{}}
\if@crefstarred The\if@crefstarredflag is set within starred variants of cleverefcommands.
Starred variants are only defined if either thehyperref or varioref package is loaded, so we only define it in those cases.14
1069\@ifpackageloaded{hyperref}{\newif\if@crefstarred}{%
1070 \@ifpackageloaded{varioref}{\newif\if@crefstarred}{}}
\@cref To save duplicating code, the referencing macros pass an argument determining the variant to an auxilliary macro\@cref, which does the real work. The\@cref macro is the behemoth at the heart of all the clever referencing features. It deals with grouping references by type, type-setting the conjunctions between groups, choosing the right formatting macro to use for each reference, and compressing consecutive references into ranges.
1071\def\@cref#1#2{%
1072 \leavevmode%
1073 \begingroup%
Initialise some things, and put all the references into a stack called\@refstack.
Note that we fully expand the second argument, in case it contains commands that expand to label names rather than label names per se.
1074 \countdef\count@consecutive=0%
14In fact, the flag isn’t needed when onlyvariorefis loaded and thelegacyvariorefis set, unlessthepoormanoption is also set. However, avoiding the redundant\if in these cases doesn’t seem worth the significantly more complicated code that would be required.
1075 \countdef\count@group=1%
1076 \count@group=1%
1077 \def\cref@variant{#1}%
1078 \newif\if@secondref%
1079 \cref@stack@init{\@refstack}%
1080 \edef\@tempa{#2}%
1081 \expandafter\cref@stack@push\expandafter{\@tempa}{\@refstack}%
1082 \cref@isstackfull{\@refstack}%
Loop until the reference stack is empty.
1083 \@whilesw\if@cref@stackfull\fi{%
Move next group of references with same type into\@refsubstack.
1084 \cref@stack@init{\@refsubstack}%
1085 \if@cref@sort%
1086 \cref@processgroupall{\@refstack}{\@refsubstack}%
1087 \cref@stack@sort{\@refsubstack}{\cref@countercmp}%
1088 \else%
1089 \cref@processgroup{\@refstack}{\@refsubstack}%
1090 \fi%
Type-set appropriate conjunction between groups of reference types.
1091 \ifnum\count@group=1\relax%
1092 \advance\count@group 1%
1093 \else%
1094 \cref@isstackfull{\@refstack}%
1095 \if@cref@stackfull%
1096 \@setcref@middlegroupconjunction%
1097 \else%
1098 \ifnum\count@group=2\relax%
1099 \@setcref@pairgroupconjunction%
1100 \else%
1101 \@setcref@lastgroupconjunction%
1102 \fi%
1103 \fi%
1104 \advance\count@group 1%
1105 \def\cref@variant{cref}%
1106 \fi%
Process first group of consecutive references.
1107 \if@cref@compress%
1108 \cref@processconsecutive%
1109 {\@refsubstack}{\@beginref}{\@endref}{\count@consecutive}%
1110 \else%
1111 \edef\@beginref{\cref@stack@top{\@refsubstack}}%
1112 \cref@stack@pop{\@refsubstack}%
Empty references serve no purpose when we’re not compressing consecutive refer- ences, so we simply remove them.
1113 \@whilesw\ifx\@beginref\@empty\fi{%
1114 \cref@stack@pop{\@refsubstack}%
1115 \cref@isstackempty{\@refsubstack}%
1116 \if@cref@stackempty%
1117 \let\@beginref\relax%
1118 \else%
1119 \edef\@beginref{\cref@stack@top{\@refsubstack}}%
1120 \fi}%
1121 \let\@endref\relax%
1122 \count@consecutive=1\relax%
1123 \fi%
If there were no consecutive references, type-set the first reference;
1124 \ifnum\count@consecutive=1\relax%
1125 \cref@isstackfull{\@refsubstack}%
1126 \if@cref@stackfull%
1127 \expandafter\@setcref%
1128 \expandafter{\@beginref}{\cref@variant}{@first}%
1129 \else%
1130 \expandafter\@setcref%
1131 \expandafter{\@beginref}{\cref@variant}{}%
1132 \fi%
if there were only two consecutive references, type-set the first one and return the second to the substack (we add an empty reference after it just to make sure there’s no further compression);
1133 \else%
1134 \ifnum\count@consecutive=2\relax%
1135 \expandafter\@setcref%
1136 \expandafter{\@beginref}{\cref@variant}{@first}%
1137 \expandafter\cref@stack@push\expandafter%
1138 {\@endref,}{\@refsubstack}%
otherwise, type-set a reference range.
1139 \else%
1140 \edef\@tempa{{\@beginref}{\@endref}}%
1141 \if@cref@stackempty%
1142 \expandafter\@setcrefrange\@tempa{\cref@variant}{}%
1143 \else%
1144 \expandafter\@setcrefrange\@tempa{\cref@variant}{@first}%
1145 \fi%
1146 \fi%
1147 \fi%
Process further groups of consecutive references, until substack is empty.
1148 \@secondreftrue%
1149 \cref@isstackfull{\@refsubstack}%
1150 \@whilesw\if@cref@stackfull\fi{%
1151 \if@cref@compress%
1152 \cref@processconsecutive%
1153 {\@refsubstack}{\@beginref}{\@endref}{\count@consecutive}%
1154 \else%
1155 \edef\@beginref{\cref@stack@top{\@refsubstack}}%
1156 \cref@stack@pop{\@refsubstack}%
Empty references serve no purpose when we’re not compressing consecutive refer- ences, so we simply remove them.
1157 \@whilesw\ifx\@beginref\@empty\fi{%
1158 \cref@stack@pop{\@refsubstack}%
1159 \cref@isstackempty{\@refsubstack}%
1160 \if@cref@stackempty%
1161 \let\@beginref\relax%
1162 \else%
1163 \edef\@beginref{\cref@stack@top{\@refsubstack}}%
1164 \fi}%
1165 \let\@endref\relax%
1166 \count@consecutive=1\relax%
1167 \fi%
If the substack is now empty, we will need to type-set an “end” reference, otherwise we will need to type-set a “middle” reference.
1168 \cref@isstackempty{\@refsubstack}%
1169 \if@cref@stackempty%
1170 \if@secondref%
1171 \def\@pos{@second}%
1172 \else%
1173 \def\@pos{@last}%
1174 \fi%
1175 \else%
1176 \def\@pos{@middle}%
1177 \fi%
If there were no consecutive references, just type-set the next reference;
1178 \ifnum\count@consecutive=1\relax%
1179 \edef\@tempa{{\@beginref}{cref}{\@pos}}%
1180 \expandafter\@setcref\@tempa%
1181 \else%
if there were only two consecutive references, type-set the first one, and return the second one to the substack,
1182 \ifnum\count@consecutive=2\relax%
1183 \expandafter\@setcref\expandafter%
1184 {\@beginref}{cref}{@middle}%
1185 \expandafter\cref@stack@push\expandafter%
1186 {\@endref}{\@refsubstack}%
otherwise, type-set a reference range.
1187 \else%
1188 \edef\@tempa{{\@beginref}{\@endref}{cref}{\@pos}}%
1189 \expandafter\@setcrefrange\@tempa%
1190 \fi%
1191 \fi%
1192 \@secondreffalse%
1193 \cref@isstackfull{\@refsubstack}%
1194 }% end loop over reference substack
1195 \cref@isstackfull{\@refstack}%
if we’re type-setting a\labelcrefreference and references in stack have different types, throw a warning and stop processing
1196 \if@cref@stackfull%
1197 \def\@tempa{#1}\def\@tempb{labelcref}%
1198 \ifx\@tempa\@tempb\relax%
1199 \protect\G@refundefinedtrue%
1200 \nfss@text{\reset@font\bfseries\space ??}%
1201 \@latex@warning{References in label reference on page \thepage
1202 \space have different types}%
1203 \@cref@stackfullfalse%
1204 \fi%
1205 \fi%
1206 }% end loop over main reference stack
1207 \endgroup}
\@setcref The internal\@setcrefmacro deals with actually type-setting the reference, by calling the appropriate type-dependent formatting macro defined by\crefformat etc.
1208\def\@setcref#1#2#3{%
1209 \expandafter\ifx\csname r@cref@#1\endcsname\relax%
1210 \protect\G@refundefinedtrue%
1211 \nfss@text{\reset@font\bfseries ??}%
1212 \@latex@warning{Reference ‘#1’ on page \thepage \space undefined}%
1213 \else%
1214 \cref@gettype{#1}{\@temptype}% puts label type in \@temptype
1215 \cref@getlabel{#1}{\@templabel}% puts label in \@templabel
1216 \expandafter\ifx\csname #2@\@temptype @format#3\endcsname\relax%
If reference format is undefined, but we’re type-setting a\labelcref, fall back to default\labelcrefformats.
1217 \edef\@tempa{#2}\def\@tempb{labelcref}%
1218 \ifx\@tempa\@tempb\relax%
1219 \expandafter\@@setcref\expandafter%
1220 {\csname #2@default@format#3\endcsname}{#1}%
1221 \else%
1222 \protect\G@refundefinedtrue%
1223 \nfss@text{\reset@font\bfseries ??}~\@templabel%
1224 \@latex@warning{#2 \space reference format for label type
1225 ‘\@temptype’ undefined}%
1226 \fi%
1227 \else%
1228 \expandafter\@@setcref\expandafter%
1229 {\csname #2@\@temptype @format#3\endcsname}{#1}%
1230 \fi%
1231 \fi}
\@@setcref We separate out the very final type-setting step into a separate macro, in order to make it easier to redefine things later to make them work with thehyperref package.
1232\def\@@setcref#1#2{\cref@getlabel{#2}{\@templabel}#1{\@templabel}{}{}}
\@setcrefrange The internal\@setcrefrangemacro deals with type-setting reference ranges, just as \@setcref does for normal references. The actual type-setting is no more complicated in the range case; it’s the error checking that makes the code so much longer. We now have to check whethertworeferences are undefined, whethertwo reference formats are undefined, whether the reference types are consistent, and also combinations of these various errors.
1233\def\@setcrefrange#1#2#3#4{%
1234 \begingroup%
Check if both references are defined.
1235 \expandafter\ifx\csname r@cref@#1\endcsname\relax%
1236 \protect\G@refundefinedtrue%
1237 \@latex@warning{Reference ‘#1’ on page \thepage \space%
1238 undefined}%
1239 \expandafter\ifx\csname r@cref@#2\endcsname\relax%
1240 \nfss@text{\reset@font\bfseries ??}--%
1241 \nfss@text{\reset@font\bfseries ??}%
1242 \@latex@warning{Reference ‘#2’ on page \thepage \space%
1243 undefined}%
1244 \else%
1245 \cref@getlabel{#2}{\@labelb}%
1246 \nfss@text{\reset@font\bfseries ??}--\@labelb%
1247 \fi%
1248 \else%
1249 \expandafter\ifx\csname r@cref@#2\endcsname\relax%
1250 \protect\G@refundefinedtrue%
1251 \cref@getlabel{#1}{\@labela}%
1252 \@labela--\nfss@text{\reset@font\bfseries ??}%
1253 \@latex@warning{Reference ‘#2’ on page \thepage %
1254 \space undefined}%
If both references are defined, check that the reference format is defined.
1255 \else%
1256 \cref@gettype{#1}{\@typea}%
1257 \cref@gettype{#2}{\@typeb}%
1258 \cref@getlabel{#1}{\@labela}%
1259 \cref@getlabel{#2}{\@labelb}%
1260 \edef\@formata{\expandafter\noexpand%
1261 \csname #3range@\@typea @format#4\endcsname}%
1262 \edef\@formatb{\expandafter\noexpand%
1263 \csname #3range@\@typeb @format#4\endcsname}%
1264 \expandafter\ifx\@formata\relax%
If reference format is undefined, but we’re type-setting a\labelcref, fall back to default\labelcrefformats.
1265 \edef\@tempa{#3}\def\@tempb{labelcref}%
1266 \ifx\@tempa\@tempb\relax%
1267 \expandafter\@@setcrefrange\expandafter%
1268 {\csname #3range@default@format#4\endcsname}{#1}{#2}%
1269 \else%
1270 \protect\G@refundefinedtrue%
1271 \nfss@text{\reset@font\bfseries ??}~\@labela--\@labelb%
1272 \@latex@warning{#3\space reference range format for label
1273 type ‘\@typea’ undefined}%
1274 \fi%
1275 \else%
If reference types are identical, type-set reference range, otherwise display warning.
(Note: there’s no need to check if reference format for second type is defined, since if it isn’t it will be caught here as a non-identical type.)
1276 \ifx\formata\formatb%
1277 \expandafter\@@setcrefrange\expandafter{\@formata}{#1}{#2}%
1278 \else%
1279 \protect\G@refundefinedtrue%
1280 \nfss@text{\reset@font\bfseries ??}~\@labela--\@labelb%
1281 \@latex@warning{References ‘#1’ and ‘#2’ in reference range
1282 on page \thepage have different types}%
1283 \fi%
1284 \fi%
1285 \fi%
1286 \fi%
1287 \endgroup}
\@@setcrefrange We again separate out the very final type-setting step into a separate macro, in order to make it easier to redefine things later to make them work with the hyperrefpackage.
1288\def\@@setcrefrange#1#2#3{%
1289 \cref@getlabel{#2}{\@labela}%
1290 \cref@getlabel{#3}{\@labelb}%
1291 #1{\@labela}{\@labelb}{}{}{}{}}
The type-setting of conjunctions is also separated out into separate macros, for the same reason.
1292\def\@setcref@pairgroupconjunction{\crefpairgroupconjunction}
1293\def\@setcref@middlegroupconjunction{\crefmiddlegroupconjunction}
1294\def\@setcref@lastgroupconjunction{\creflastgroupconjunction}
\labelcref
\namecref
\nameCref
\lcnamecref
\namecrefs
\nameCrefs
\lcnamecrefs
Finally, we define a \labelcref that returns just the type-set label part of a (multi-)reference, without the reference name, and conversely \namecref,
\nameCref, \namecrefs and \nameCrefs commands that return just the type- set name of a reference, without the reference label. The latter four retrieve the reference name from the corresponding \crefname or \Crefname definition, so they only work when this has been defined. We also define \lcnamecref and
\lcnamecrefs commands which force the reference name to lowercase, for use when thecapitalise option is enabled.
1295\DeclareRobustCommand{\labelcref}[1]{\@cref{labelcref}{#1}}
1296\DeclareRobustCommand{\namecref}[1]{%
1297 \expandafter\ifx\csname r@cref@#1\endcsname\relax%
1298 \protect\G@refundefinedtrue%
1299 \nfss@text{\reset@font\bfseries ??}%
1300 \@latex@warning{Reference ‘#1’ on page \thepage \space undefined}%
1301 \else%
1302 \cref@gettype{#1}{\@tempa}%
1303 \@ifundefined{cref@\@tempa @name}{%
1304 \protect\G@refundefinedtrue%‘‘
1305 \nfss@text{\reset@font\bfseries ??}%
1306 \@latex@warning{Reference name for label type ‘\@tempa’ undefined}%
1307 }{\csname cref@\@tempa @name\endcsname}%
1308 \fi}
1309\DeclareRobustCommand{\nameCref}[1]{%
1310 \expandafter\ifx\csname r@cref@#1\endcsname\relax%
1311 \protect\G@refundefinedtrue%
1312 \nfss@text{\reset@font\bfseries ??}%
1313 \@latex@warning{Reference ‘#1’ on page \thepage \space undefined}%
1314 \else%
1315 \cref@gettype{#1}{\@tempa}%
1316 \@ifundefined{Cref@\@tempa @name}{%
1317 \protect\G@refundefinedtrue%‘‘
1318 \nfss@text{\reset@font\bfseries ??}%
1319 \@latex@warning{Reference name for label type ‘\@tempa’ undefined}%
1320 }{\csname Cref@\@tempa @name\endcsname}%
1321 \fi}
1322\DeclareRobustCommand{\lcnamecref}[1]{%
1323 \expandafter\ifx\csname r@cref@#1\endcsname\relax%
1324 \protect\G@refundefinedtrue%
1325 \nfss@text{\reset@font\bfseries ??}%
1326 \@latex@warning{Reference ‘#1’ on page \thepage \space undefined}%
1327 \else%
1328 \cref@gettype{#1}{\@tempa}%
1329 \@ifundefined{cref@\@tempa @name}{%
1330 \protect\G@refundefinedtrue%‘‘
1331 \nfss@text{\reset@font\bfseries ??}%
1332 \@latex@warning{Reference name for label type ‘\@tempa’ undefined}%
1333 }{\expandafter\expandafter\expandafter%
1334 \MakeLowercase\csname cref@\@tempa @name\endcsname}%
1335 \fi}
1336\DeclareRobustCommand{\namecrefs}[1]{%
1337 \expandafter\ifx\csname r@cref@#1\endcsname\relax%
1338 \protect\G@refundefinedtrue%
1339 \nfss@text{\reset@font\bfseries ??}%
1340 \@latex@warning{Reference ‘#1’ on page \thepage \space undefined}%
1341 \else%
1342 \cref@gettype{#1}{\@tempa}%
1343 \@ifundefined{cref@\@tempa @name@plural}{%
1344 \protect\G@refundefinedtrue%‘‘
1345 \nfss@text{\reset@font\bfseries ??}%
1346 \@latex@warning{Reference name for label type ‘\@tempa’ undefined}%
1347 }{\csname cref@\@tempa @name@plural\endcsname}%
1348 \fi}
1349\DeclareRobustCommand{\nameCrefs}[1]{%
1350 \expandafter\ifx\csname r@cref@#1\endcsname\relax%
1351 \protect\G@refundefinedtrue%
1352 \nfss@text{\reset@font\bfseries ??}%
1353 \@latex@warning{Reference ‘#1’ on page \thepage \space undefined}%
1354 \else%
1355 \cref@gettype{#1}{\@tempa}%
1356 \@ifundefined{Cref@\@tempa @name@plural}{%
1357 \protect\G@refundefinedtrue%‘‘
1358 \nfss@text{\reset@font\bfseries ??}%
1359 \@latex@warning{Reference name for label type ‘\@tempa’ undefined}%
1360 }{\csname Cref@\@tempa @name@plural\endcsname}%
1361 \fi}
1362\DeclareRobustCommand{\lcnamecrefs}[1]{%
1363 \expandafter\ifx\csname r@cref@#1\endcsname\relax%
1364 \protect\G@refundefinedtrue%
1365 \nfss@text{\reset@font\bfseries ??}%
1366 \@latex@warning{Reference ‘#1’ on page \thepage \space undefined}%
1367 \else%
1368 \cref@gettype{#1}{\@tempa}%
1369 \@ifundefined{cref@\@tempa @name@plural}{%
1370 \protect\G@refundefinedtrue%‘‘
1371 \nfss@text{\reset@font\bfseries ??}%
1372 \@latex@warning{Reference name for label type ‘\@tempa’ undefined}%
1373 }{\expandafter\expandafter\expandafter%
1374 \MakeLowercase\csname cref@\@tempa @name@plural\endcsname}%
1375 \fi}