%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% % This is file 'skeyval-for.tex', version 1.3, 2013/05/15. % % % % This package and accompanying files may be distributed and/or % % modified under the conditions of the LaTeX Project Public License, % % either version 1.3 of this license or any later version. The latest % % version of this license is in http://www.latex-project.org/lppl.txt % % and version 1.3 or later is part of all distributions of LaTeX % % version 2005/12/01 or later. % % % % The LPPL maintenance status of this software is 'author-maintained'. % % % % This software is provided 'as it is', without warranty of any kind, % % either expressed or implied, including, but not limited to, the % % implied warranties of merchantability and fitness for a particular % % purpose. % % % % The following files constitute the skeyval bundle and must be % % distributed as a whole: % % % % README, skeyval.sty, skeyval-core.tex, skeyval-for.tex, % % skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, % % skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, % % skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2, % % skeyval-view-pokayoke1. % % % % Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \begingroup% \let\e\endlinechar\edef\p{\the\e}\e13\edef\n{\the\catcode\e}% \xdef\skv@for@restorecatcodes{% \let\noexpand\skv@for@restorecatcodes\relax% \endlinechar=\p\relax\catcode\number\e=\n\relax% \catcode\string`\noexpand`\string=\the\catcode\string``\relax% \catcode\string`\noexpand=\string=\the\catcode\string`=\relax% }% \endgroup% \endlinechar\string=13\relax% \catcode13\string=5\relax% \catcode\string``\string=12\relax \catcode\string`=\string=12\relax \def\skvgobble#1{} \def\do#1{\catcode`\expandafter\skvgobble\string#1=\the\catcode`#1\relax} \edef\skv@for@restorecatcodes{% \unexpanded\expandafter{\skv@for@restorecatcodes}% \do\ \do\%\do\@\do\(\do\)\do\[\do\]\do\|\do\:\do\;\do\,\do\.% \do\>\do\<\do\!\do\*\do\+\do\-\do\^\do\_\do\&\do\$\do\~\do\'% \do\"\do\ } \catcode`\ =10\relax \catcode`\@=11 \catcode`\(=12 \catcode`\)=12 \catcode`\[=12 \catcode`\]=12 \catcode`\|=12 \catcode`\:=12 \catcode`\;=12 \catcode`\,=12 \catcode`\*=12 \catcode`\+=12 \catcode`\-=12 \catcode`\<=12 \catcode`\>=12 \catcode`\!=12 \catcode`\.=12 \catcode`\^=07 \catcode`\_=08 \catcode`\&=04 \catcode`\$=03 \catcode`\~=13 \catcode`\%=14 \catcode`\'=12 \catcode`\"=12 \csname skeyval-for-loaded\endcsname \expandafter\let\csname skeyval-for-loaded\endcsname\endinput \ifx\ProvidesFile\@undefined \message{File 'skeyval-for.tex' 2013/05/15 v1.3 Loops for skeyval package (AM)} \else \ProvidesFile{skeyval-for.tex} [2013/05/15 v1.3 Loops for skeyval package (AM)] \@addtofilelist{skeyval-for.tex} \fi \skvrobustdef*\skv@nostackerr{% \skv@err{You've called an empty stack}\skv@ehd } % \skvsavestate{} % % See file skeyval-core.tex for \skvpushfunctions and \skvpopfunctions. % \skvrobustdef*\skvsavestate#1#2#3{% \skvgadvanceno#3\@ne \begingroup \let\s\string\escapechar\m@ne \def\skv@prova##1{\s##1@skv@\romannumeral#3}% \def\do##1{\let\noexpand##1\skvnoexpandcs{\skv@prova{##1}}}% \skvifcsdefTF{\s#1@skv@stack}{}{\skvcsdef{\s#1@skv@stack}{\nostack}}% \skvcsxdef{\s#1@skv@stack}{#2{\skvexpandcsonce{\s#1@skv@stack}}}% \def\do##1{\let\skvnoexpandcs{\skv@prova{##1}}\noexpand##1}% \edef\reserved@a{\endgroup#2}\reserved@a } % \skvrestorestate \skvrobustdef*\skvrestorestate#1#2{% \begingroup \let\nostack\skv@nostackerr \edef\skv@elt{\skvnoexpandcs{\skvremovescape#1@skv@stack}}% \expandafter\ifx\skv@elt\relax \skv@err{Stack of '\noexpand#1' is undefined}\skv@ehd \fi \edef\skv@prova{\skvexpandtwice\skv@elt}% \edef\skv@provb##1##{\endgroup##1\gdef\skvexpandonce\skv@elt}% \expandafter\skv@provb\skv@prova \skvgadvanceno#2\m@ne } \skvnewregisters\bool{% \ifbreakallforeachloops,\ifskvbreakloop,\ifforeachlastitem, \ifskvprocessempty,\ifskv@foreach@swa,\ifskv@foreach@swb, \ifskv@foreach@parenthesis,\ifskv@useemptylist,\ifskv@inforeach, } \skvnewlet\skvbreakloop\skvbreaklooptrue \skvnewlet\breaknewforeach\skvbreaklooptrue % \breakallforeachloops will break all current loops (inner and outer): \skvnewdef*\breakallforeachloops{% \skvbreaklooptrue\breakallforeachloopstrue } \skvnewnumbers[skv@]{csvdepth,dolistdepth} % % \skvdolist{}{}{} % \skvdolist*{}{}{} % \skvparselist{}{}{} % \skvparselist*{}{}{} % \skvprocesslist{}{}{} % \skvprocesslist*{}{}{} % % 1. These macros can process both csv and tsv/nsv lists. Use empty % for tsv lists. % 2. These macros can be nested to any depth, with different parsers % on each level. % 3. \skvdolist and \skvparselist will not process an empty list, but % \skvprocesslist will do so. % 4. For comma lists, \skvcommaloop and \skvcommaparse are faster. % See later. % 5. For processing kv lists, use \skvparsekvlist. % 6. The preservation of outer braces isn't a priority in this loop. % \skvrobustdef*\skvdolist{\skv@useemptylistfalse\skv@testst\skv@dolist} \skvrobustdef*\skv@dolist#1#2#3#4{% \skv@usetempst{#2}#3% % \skvlistcount is used by listkeys. \skvsavestate\skvdolist{% \do\skv@dolist@callback \do\skv@dolist@a\do\skvlistcount\do\ifskv@useemptylist }\skv@dolistdepth \edef\skv@dolist@callback{\unexpanded{#4}}% \def\skvlistcount{0}% \def\skv@dolist@a##1##2#1{% \skvifstrcmpTF{##2}{\skv@dolist@nil}{% % To allow nesting of loop: \skvbreakloopfalse }{% \edef##1{\unexpanded{##2}}% \edef\skvlistcount{\the\numexpr\skvlistcount+1}% \skv@dolist@callback\relax \ifskvbreakloop \skvbreakloopfalse \begingroup \def\skv@dolist@a####1####2\skv@dolist@nil#1{% \endgroup \edef\skvremainder{\unexpanded{####2}}% }% \fi \skv@dolist@a{##1}% }% }% \ifskv@useemptylist \def\reserved@a##1##2##3{##3}% \else \let\reserved@a\skvifemptyTF \fi \reserved@a#3{}{% \expandafter\skv@dolist@a\expandafter#3#3#1\skv@dolist@nil#1% }% \skvrestorestate\skvdolist\skv@dolistdepth } % First normalize the list before parsing. \skvrobustdef*\skvparselist{\skv@useemptylistfalse\skv@testst\skv@parselist} \skvrobustdef*\skvprocesslist{\skv@useemptylisttrue\skv@testst\skv@parselist} \skvrobustdef*\skv@parselist#1#2#3{% \skv@usetempst{#2}#3% \skvcsvnormalize[#1]#3% \skv@tempsttrue \skv@dolist{#1}#3#3% } \skvnewlet\foreachlistbreaker\relax \skvnewlet\foreachlistpauser\relax \skvnewdef*\skv@listbreakertoks{\foreachlistbreaker} \skvnewdef*\skv@listpausertoks{\foreachlistpauser} \skvnewlet\skvprocessempty\skvprocessemptytrue % Reversing tokens: \skvnewdef*\skvreverse#1{\skv@reverse#1\skv@reverse@stop} \skvnewdef*\skv@reverse#1#2\skv@reverse@stop{% \if\relax\detokenize{#2}\relax\skv@reverse@stop\fi \skv@reverse#2\skv@reverse@stop\skvreversedo{#1}% } \skvnewdef*\skv@reverse@stop#1\skv@reverse@stop{\fi} \let\skvreversedo\@iden \skvrobustdef*\skv@removetrailingparser#1#2{% \skvxifinTF{\detokenize{#1}\relax}{\skvoxdetok#2\relax}{% \def\skv@prova##1#1\skv@trim@nil{\unexpanded{##1}}% \edef#2{\expandafter\skv@prova#2\skv@trim@nil}% }{}% } % \skvrecurse\while<\if...>\fi % % On entry, the condition is checked before the body is executed. % % \@tempcnta\z@ % \skvrecurse{ % \advance\@tempcnta\@ne % \@tempcntb\z@ % \skvrecurse % \advance\@tempcntb\@ne % \typeout{Doing \the\@tempcnta,\the\@tempcntb} % \while % \ifnum\@tempcntb<3 % \fi % } % \while % \ifnum\@tempcnta<4 % \fi % \skvnewcounts{skv@recurse@cnt} \skvrobustdef\skvrecurse#1\while#2\fi{% \skv@recurse@cnt\skvz@ \@expandtwoargs\skv@dobody{\skvtrimspace{#2}}{\skvtrimspace{#1}}% } \skvrobustdef\skv@dobody#1#2{% \advance\skv@recurse@cnt\@ne \ifnum\skv@recurse@cnt>10000\relax \@latex@error{Possibly an infinite loop in \string\skvrecurse} {Maybe you didn't increment some counter or \MessageBreak the termination condition was never satisfied.}% \fi #1\relax\expandafter\@iden\else\expandafter\@gobble\fi {#2\relax\skv@dobody{#1}{#2}}% } % A version of LaTeX's \@tfor that can parse undoubled parameter % characters and terminate the loop by using \skvbreakloop. % % \skvtfor:={}\do{} % \skvtfor*:={}\do{} % % Example: % % \skvnewregister\count{\nr} % \skvtfor\x:=a \ifx {\def\x#1{#1}} \fi\do{% % \nr\z@ % \skvtfor\y:=12345\do{% % \typeout{Doing: \detokenize\expandafter{\x}--\y}% % \advance\nr\@ne % \ifnum\nr>\tw@\skvbreakloop\fi % } % } % \skvnewdef*\skv@tfor@nil{\skv@tfor@nil} \skvrobustdef*\skvtfor{\skv@testst\skv@tfor} \skvrobustdef*\skv@tfor#1:={\skv@tf@r#1 } \skvrobustdef\skv@tf@r#1#2\do#3{% \edef#1{\skvtrimspace{#2}}% \edef#1{\skvifdefboolTF{skv@tempst}\skvexpandtwice\skvexpandonce{#1}}% \skvifemptyTF#1{}{% \skvbreakloopfalse \expandafter\skv@tforloop#1\skv@tfor@nil\skv@tfor#1{#3}% }% } \skvrobustdef\skv@tforloop#1#2\skv@tfor#3#4{% \edef#3{\unexpanded{#1}}% \skvifxTF#3\skv@tfor@nil{% \skvbreakloopfalse }{% #4\relax \ifskvbreakloop \skvbreakloopfalse \begingroup \def\skv@tforloop##1\skv@tfor@nil\skv@tfor##2##3{% \endgroup \edef\skvremainder{\unexpanded{##1}}% }% \fi \skv@tforloop#2\skv@tfor#3{#4}% }% } %+++++++++++++++ Non-expandable comma loops ++++++++++++++%% % % 1. These follow from \skvdolist and \skvparselist, but they are % specialized for comma lists and they are faster, since they don't % stack any state. % 2. There is no fear of parameter characters in being mixed % with those of \skv@commaloop@picknext. % 3. These loops can be nested to any depth. % 4. The preservation of outer braces isn't a priority in these loops. % % \skvcommaloop{}{} % \skvcommaloop*{}{} % % Example: % % \skvcommaloop{x#1,y#1}\tempa{\edef\xx#1{#1\tempa}} % \skvrobustdef*\skvcommaloop{\skv@testst\skv@commaloop} \skvrobustdef\skv@commaloop#1#2#3{% \skv@usetempst{#1}#2% % Don't put \skvcsvnormalize#2 here. Use \skvcommaparse instead. % Some callers of \skvcommaloop already have their lists normalized. \skvifxTF#2\@empty{}{% \skvbreakloopfalse \skvexpandnext{\skv@commaloop@picknext#2{#3}}#2,\skv@commaloop@nil,% }% } \skvrobustdef\skv@commaloop@picknext#1#2#3,{% \skvifstrcmpTF{#3}{\skv@commaloop@nil}{% \skvbreakloopfalse }{% \edef#1{\unexpanded{#3}}% #2\relax \ifskvbreakloop \skvbreakloopfalse \begingroup \long\def\skv@commaloop@picknext##1##2##3\skv@commaloop@nil,{% \endgroup \edef\skvremainder{\unexpanded{##3}}% }% \fi \skv@commaloop@picknext#1{#2}% }% } % % \skvecommaloop{}{} % \skvecommaloop*{}{} % % \skvecommaloop is as \skvcommaloop but will execute % once when is empty. This is needed for processing empty % families. % \skvrobustdef\skvecommaloop{\skv@testst\skv@ecommaloop} \skvrobustdef\skv@ecommaloop#1#2#3{% \edef#2{\unexpanded{\skv@commaloop@picknext#2{#3}}}% \ifskv@tempst\expandafter\expandafter\fi#2#1,\skv@commaloop@nil,% } % % \skvcommaparse{}{} % \skvcommaparse*{}{} % % \skvcommaparse is as \skvcommaloop but will first normalize % using \skvcsvnormalize. % \skvrobustdef*\skvcommaparse{\skv@testst\skv@commaparse} \skvrobustdef\skv@commaparse#1#2#3{% \skv@usetempst{#1}#2% \skvcsvnormalize#2% \skvcommaloop*#2#2{#3}% } % \skvkvparse{}{} % \skvkvparse*{}{} % % 1. \skvkvparse is as \skvcommaloop but will first normalize using % \skvkvnormalize. % 2. It is meant for processing key-value lists. % \skvrobustdef*\skvkvparse{\skv@testst\skv@kvparse} \skvnewlet\skvparsekvlist\skvkvparse \skvrobustdef\skv@kvparse#1#2#3{% \skv@usetempst{#1}#2% \skvkvnormalize#2% \skvcommaloop*#2#2{#3}% } % \skvcountelements[]{}{} % \skvcountelements*[]{}{} \skvrobustdef*\skvcountelements{\skv@teststopt\skv@countelements,} \skvrobustdef*\skv@countelements[#1]#2#3{% \begingroup \skv@usetempst{#2}\skv@tempa \@tempcnta\skvz@ \skvdolist*{#1}\skv@tempa\skv@prova{% \advance\@tempcnta\@ne }% \edef#3{\the\@tempcnta}% \skvaftergroupdef#3\endgroup } % If the number of elements in a list is equal or greater than . % \skvifelementcount[]{}{}{}{} % \skvifelementcount*[]{}{}{}{} \skvrobustdef*\skvifelementcount{\skv@teststopt\skv@ifelementcount,} \skvrobustdef*\skv@ifelementcount[#1]#2#3{% \begingroup \skv@usetempst{#2}\skv@tempa \@tempcnta\skvz@ \skv@swafalse \skvdolist*{#1}\skv@tempa\skv@prova{% \advance\@tempcnta\@ne \ifnum\@tempcnta=#3\relax \skv@swatrue\skvbreakloop \fi }% \expandafter\endgroup\ifskv@swa \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi } % \skv@foreach@normalize[] \skvrobustdef*\skv@foreach@normalize{\skv@testopt\skv@foreach@norm@lize,} \skvrobustdef*\skv@foreach@norm@lize[#1]#2{% \skvxifntypeTF{\detokenize{#1}}\skvcsvnormalize\skvmacnormalize[#1]#2% } % \newforeach[] {} {} % \newforeach*[] {} {} % \newforeach[] in {} do {} % \newforeach*[] in {} do {} % \newforeach[] in {} ; % \newforeach*[] in {} ; % % 1. is the code that will be executed for each element % of the list. It will refer to the holder macros . % % 3. Elements of the form (a,b) and [a,b] are grabbed together. % % 4. Use \breaknewforeach to break out of the loop prematurely. % % 5. \newforeach can be nested. % % 6. The star (*) variant of \newforeach is equivalent to using the % key 'list is a macro' (or *) in . % % \skv@foreach@holderdepth must be different from \foreachnestdepth, % to avoid confusing two different stacks. \skvnewnumbers{foreachnestdepth,skv@foreach@holderdepth,% skv@foreach@nra,skv@warnsubparser} % \newforeach will not accept \skvifstreq or \skvifstrcmpTF because % they don't start with '\if'. So we introduce \ifforeachstrcmp: \skvnewlet\ifforeachstrcmp\skvifstreq \skvnewdef*\skv@foreach@onlyinitially{} \skvrobustdef*\skvforeachonlyinitially#1{% \edef\skv@foreach@onlyinitially{% \skvexpandonce\skv@foreach@onlyinitially \unexpanded{#1}% }% } % \skv@foreach@addtocallback{}{} \skvrobustdef*\skv@foreach@addtocallback#1#2{% \skvcsedef{skv@foreach@#1callback}{% \skvifcsdefFT{skv@foreach@#1callback}{}{% \skvexpandcsonce{skv@foreach@#1callback}% }% % No \unexpanded for #2 here, since #2 is to be expanded: #2% }% } \skvnewlet\skv@foreach@codemark\relax \skvrobustdef*\skv@foreach@addtohook#1#2#3{% \begingroup \skvifdefTF#2{}{\def#2{}}% \edef\x{\detokenize{\skv@foreach@codemark#3\skv@foreach@codemark}}% \skvxifinTF\x{\skvoxdetok#2}{}{% \edef#2{% \skvifstrcmpTF{#1}{pre}{% \skv@foreach@codemark\unexpanded{#3}\skv@foreach@codemark \skvexpandonce{#2}% }{% \skvexpandonce{#2}% \skv@foreach@codemark\unexpanded{#3}\skv@foreach@codemark }% }% }% \skvaftergroupdef#2\endgroup } % \prependtobeginforeach[]{} \skvrobustdef*\prependtobeginforeach{% \skv@testopt{\skv@atbeginforeach{pre}}{}% } % \appendtobeginforeach[]{} \skvrobustdef*\appendtobeginforeach{% \skv@testopt{\skv@atbeginforeach{app}}{}% } \skvnewlet\atbeginforeach\appendtobeginforeach \skvrobustdef*\skv@atbeginforeach#1[#2]#3{% \skvifblankTF{#2}{% \skvaftercsname{\skv@foreach@addtohook{#1}}% {skv@foreach@atbeginhook@\skvrom\@ne}{#3}% }{% \skvcommaloop{#2}\skv@tempa{% \skvaftercsname{\skv@foreach@addtohook{#1}}% {skv@foreach@atbeginhook@\skvrom\number\skv@tempa}{#3}% }% }% } % \prependtoendforeach[]{} \skvrobustdef*\prependtoendforeach{% \skv@testopt{\skv@atendforeach{pre}}{}% } % \appendtoendforeach[]{} \skvrobustdef*\appendtoendforeach{% \skv@testopt{\skv@atendforeach{app}}{}% } \skvnewlet\atendforeach\appendtoendforeach \skvrobustdef*\skv@atendforeach#1[#2]#3{% \skvifblankTF{#2}{% \skvaftercsname{\skv@foreach@addtohook{#1}}% {skv@foreach@atendhook@\skvrom\@ne}{#3}% }{% \skvcommaloop{#2}\skv@tempa{% \skvaftercsname{\skv@foreach@addtohook{#1}}% {skv@foreach@atendhook@\skvrom\number\skv@tempa}{#3}% }% }% } % \atbeginforeachondepth{}{} \skvrobustdef*\atbeginforeachondepth#1#2{% \appendtobeginforeach[#1]{#2}% } % \atendforeachondepth{}{} \skvrobustdef*\atendforeachondepth#1#2{% \appendtoendforeach[#1]{#2}% } % \skv@foreach@fi@toks must use \detokenize. Don't change to \string! \skvnewedef*\skv@foreach@fi@toks{\detokenize{\fi}} \skvnewedef*\skv@foreach@if@toks{\string\if} % \skv@foreach@ifacceptkv and \skv@foreach@maketester must come % before the initialization of keys: \skvrobustdef*\skv@foreach@ifacceptkv#1#2{% \def\next{}% \ifskvindef\else \edef\skv@prova{\unexpanded{#1}}% \ifnum0>\numexpr0\ifx\skv@prova\@empty-1\else \ifx\skv@prova\@nnil-1\else+0\fi\fi\relax\relax \skv@err{Invalid syntax '\detokenize{#1}'}\skv@ehd \else \edef\next{\unexpanded{#2}}% \fi \fi \next } \skvrobustdef*\skv@foreach@ifholderisonecmd#1#2#3{% \skvifntypeTF{#2}{% \skvifescapedTF{#2}{% #3% }{% \skv@err{Value of key '#1' must \MessageBreak be escaped: the holder macro \MessageBreak to be evaluated}\skv@ehd }% }{% \skv@err{Value of key '#1' must \MessageBreak be only one token: the holder \MessageBreak macro to be evaluated}\skv@ehd }% } % \skv@foreach@maketester{}{} % % 1. Only balanced conditionals beginning with \if... and ending with \fi % are allowed. Restricting the type of allowed conditionals is % necessary for auto syntax checking. % 2. is either 0 or 1, signifying whether or not the condition % should be entered in postcallback. This is because % \skv@foreach@maketester is called (by key 'loop stopper') for % formating the premature exit condition and (in % \skv@foreach@parsecountin and \skv@foreachfox@parsecountin) for the % condition for counting an item of the list. In the latter case, % there is no need to enter the formated % condition in the postcallback, since it it is entered in the % 'afterprecallback' or (in the case of \foreachfox) in 'precallback'. % % Examples: \ifnum\x>10\fi, \ifx\x\cmd\fi. % \skvrobustdef*\skv@foreach@maketester#1#2#3{% % Make '#1' innocent in a macro, in case it contains parameter % characters. \skv@prova will appear only in the error message. \begingroup \edef\skv@prova{\detokenize{#1}}% \skvifblankTF{#1}{% \skv@err{A blank conditional has been given in \MessageBreak\string\newforeach or a similar command}\skv@ehd }{% \skvxifinTF{\skv@foreach@fi@toks\relax}{\detokenize{#1}\relax}{% \skvxifinTF{\relax\skv@foreach@if@toks}{\relax\detokenize{#1}}{% \edef#2{\noexpand\skvifconditionTF\unexpanded{#1}}% \ifnum#3=\@ne \skv@foreach@addtocallback{post}{% \unexpanded{\skvifconditionTF#1}{\noexpand\skvbreakloop}{}% }% \fi }{% \skv@err{Invalid conditional '\skv@prova'} {Invalid, possibly unbalanced, conditional '\skv@prova'}% }% }{% \skv@err{Invalid conditional '\skv@prova'}\skv@ehd }% }% \skvexpanded{\endgroup \skvcmdexit#2% \ifnum#3=\@ne \skvcmdexit\skv@foreach@postcallback \fi }% } \skvquickkeys.define{skeyval/foreach}{% .exec/ \def\skv@foreach@parser{,} \def\skv@foreach@subparser{/} ; parser/{,}/ \edef\skv@foreach@parser{\unexpanded{#1}} \skvstripouterbraces{2}\skv@foreach@parser \skvxifntypeTF{\detokenize{#1}}{% \begingroup % It is assumed that every n-type parser and subparser % must have catcode 12: \skvexpandnext{\catcode`}\skv@foreach@parser=12\relax \skvrescan\skv@foreach@parser \skvaftergroupdef\skv@foreach@parser\endgroup }{} ; subparser/{/}/ \edef\skv@foreach@subparser{\unexpanded{#1}} \skvstripouterbraces{2}\skv@foreach@subparser \skvxifntypeTF{\detokenize{#1}}{ \begingroup \skvexpandnext{\catcode`}\skv@foreach@subparser=12\relax \skvrescan\skv@foreach@subparser \skvaftergroupdef\skv@foreach@subparser\endgroup }{} ; terminator,callback terminator/{;}/ \edef\skv@foreach@terminator{\unexpanded{#1}}% \skvstripouterbraces{2}\skv@foreach@terminator ; % process up to = % Maximum number of items to process: process up to,process up to number// \skviflacus#1\then\else \skvensureinteger{process up to}{#1}% \def\skv@foreach@processupto{#1}% \skvstripouterbraces{2}\skv@foreach@processupto \fi ; process empty list/true/ \edef\skv@foreach@processempty{0\skvifstrcmpTF{true}{#1}01}% /true,false ; % 'break=' % Break list processing when is satisfied. must % be a balanced plain TeX conditional. Eg, 'exit when={\ifnum\x=20\fi}'. % Notice the use of outer braces in '{\ifnum\x=20\fi}'. This avoids % conflicting the two equality signs: for the key-value and for number % testing. .exec/\let\skv@foreach@exittester\@secondoftwo; break,loop stopper,exit when/\if01\fi/ \edef\skv@tempa{\unexpanded{#1}}% \skvstripouterbraces{2}\skv@tempa \skvexpbracenext\skv@foreach@maketester\skv@tempa \skv@foreach@exittester\@ne ; % Java-type of continue: If the user wants to ignore the callback for % some items, he can instantiate the key 'condition='. % must be a balanced plain TeX conditional. Eg, % continue={\ifnum\x=20\fi}. .exec/\let\skv@foreach@continuetester\@secondoftwo; continue,ignore callback/\if01\fi/ \edef\skv@tempa{\unexpanded{#1}}% \skvstripouterbraces{2}\skv@tempa \skvexpbracenext\skv@foreach@maketester\skv@tempa \skv@foreach@continuetester\skvz@ ; % Eg, 'evaluate = \x as \z using \numexpr\x*2'. 'as' and 'using', and the % tokens after them, can be missing, but the formula must be complete. evaluate/\@nil/ \skv@foreach@ifacceptkv{#1}{% \skv@foreach@parseevaluate{#1}% }% ; % The evaluator \numexpr will invariably be used internally for this key. % 'as' and 'using' are illegal here. This is only a shortcut for 'evaluate'. evaluate num,evaluate number/\@nil/ \skv@foreach@ifacceptkv{#1}{% \skv@foreach@ifholderisonecmd{evaluate number}{#1}{% \skv@foreach@parseevaluate{#1as#1using\numexpr#1}% }% }% ; % The evaluator \dimexpr will invariably be used internally for this key. % 'as' and 'using' are illegal here. This is only a shortcut for 'evaluate'. evaluate dim,evaluate dimension/\@nil/ \skv@foreach@ifacceptkv{#1}{% \skv@foreach@ifholderisonecmd{evaluate dimension}{#1}{% \skv@foreach@parseevaluate{#1as#1using\dimexpr#1}% }% }% ; % Eg, 'expand=\x'. % Fully expand holder macro. This is equivalent to, eg, edef\x{\x}. % 'as' and 'using' are illegal here. This is only a shortcut for 'evaluate'. expand,expanded/\@nil/ \skv@foreach@ifacceptkv{#1}{% \skv@foreach@ifholderisonecmd{expand}{#1}{% \skv@foreach@parseevaluate{#1as#1using#1}% }% }% ; % Eg, 'pgf parse = \x as \xe using \x*3'. 'as' and 'using', and the % tokens after them, can be present or missing. % \pgfmathparse is always used for this key. pgf evaluate,pgf parse,pgfmath parse/\@nil/ \skv@foreach@ifacceptkv{#1}{% \skv@foreach@parsepgfmathparse{#1}% }% ; % count in = \y all \x satisfying initially % Eg, % count in = \p all \x satisfying \ifnum\x>4\fi, or % count in = \p all \x satisfying \skvifnumTF\x>4 % The counting is not additive, meaning that the counter is initialized % to zero on each depth. count in,count/\@nil/ \skv@foreach@ifacceptkv{#1}{% \skv@foreach@parsecountin{#1}% }% ; % Eg, 'remember=\x as \y initially A': remember/\@nil/ \skv@foreach@ifacceptkv{#1}{% \skv@foreach@parseremember{#1}% }% ; % Eg, 'recall=\x initially A'. % 'recall' is as 'remember', but will save the value of the holder macro % in \. 'as' is invalid/illegal here, since a % retainer macro is built internally: retain,recall,call up/\@nil/ \skv@foreach@ifacceptkv{#1}{% \skv@foreach@parserecall{#1}% }% ; item counter,counter/\foreachdefaultitemcounter/ \skvifescapedTF{#1}{% \def\skv@foreach@itemcounter{#1}% }{% \skv@err{Non-escaped value '\detokenize{#1}' \MessageBreak for key 'item counter'}\skv@ehd }% ; list breaker/\foreachlistbreaker/ \edef\skv@prova{\unexpanded{#1}}% \ifx\skv@prova\@empty \skv@err{Invalid empty value for key 'list breaker'}\skv@ehd \else \let\skv@listbreakertoks\skv@prova \fi ; list pauser/\foreachlistpauser/ \edef\skv@prova{\unexpanded{#1}}% \ifx\skv@prova\@empty \skv@err{Invalid empty value for key 'list pauser'}\skv@ehd \else \let\skv@listpausertoks\skv@prova \fi ; % Remember outside the loop the holder values. Of course, this % means remembering only the latest values. recover holder values,recover holder values after loop/true/ \edef\skv@foreach@recoverholders{0\skvifstrcmpTF{true}{#1}01}% /true,false ; % This default value of 'link' is required by \skvautocompletelist: .exec code/\def\skv@foreach@link{\@nil}; link/\@nil/ \edef\skv@prova{\unexpanded{#1}}% \ifcase0% \ifx\skv@prova\@empty 1\fi \ifx\skv@prova\@nnil 1\fi\relax \edef\skv@foreach@link{\unexpanded{#1}}% \skvstripouterbraces{2}\skv@foreach@link \fi ; grow/\@nil/ \edef\skv@prova{\unexpanded{#1}}% \ifx\skv@prova\@nnil\else \skvcsedef{skv@foreach@grow#1}{00} \edef\skv@prova{\skvifstrcmpTF{#1}{left}{right}{left}}% \skvcsedef{skv@foreach@grow\skv@prova}{01}% \fi /left,right ; .exec/ \def\skv@foreach@growleft{01} \def\skv@foreach@growright{01} ; grow left/true/ \edef\skv@foreach@growleft{0\skvifstrcmpTF{true}{#1}01} /true,false ; grow right/true/ \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}01} /true,false ; % Keep the decimals in rounded numbers or dimensions when list is % auto-completed. The value value of this key is 'true'. keep decimals/true/ \edef\skv@foreach@keepdecimals{0\skvifstrcmpTF{true}{#1}01} /true,false ; keep high decimals,keep only high decimals/true/ \edef\skv@foreach@keephighdecimals{0\skvifstrcmpTF{true}{#1}01} /true,false ; % This key means that, eg, for \x/\y, do \let\y=\x if \y has no % user value, ie, if the user gives as an item 'a' instead of % 'a/b' or 'a/a'. inherit,transfer macro values/true/ \edef\skv@foreach@inherit{0\skvifstrcmpTF{true}{#1}01} /true,false ; expand before fill,expand list before fill/true/ \edef\skv@foreach@expandbeforefill{0\skvifstrcmpTF{true}{#1}01} /true,false ; expand list once,x1,list is a macro,macro list/true/ \edef\skv@foreach@expandlistonce{0\skvifstrcmpTF{true}{#1}01}% /true,false ; expand list twice,x2/true/ \edef\skv@foreach@expandlisttwice{0\skvifstrcmpTF{true}{#1}01}% /true,false ; % Don't use 'expand' for this key, to avoid confusing it with % the 'expand' for holder macros: expand list,fully expand list,expand list fully,xx/true/ \edef\skv@foreach@expandlistfully{0\skvifstrcmpTF{true}{#1}01}% /true,false ; reverse list,reverse,reflect/true/ \edef\skv@foreach@reverselist{0\skvifstrcmpTF{true}{#1}01} /true,false ; % 'hide parameters' can be used to avoid doubling the parameter % characters in the callback. hide parameters/true/ \edef\skv@foreach@hideparameters{0\skvifstrcmpTF{true}{#1}01} /true,false ; } % The following keys don't need presetting. The user must supply % values when they are called. In internal loops, their values will % have to be revised from those of the outer loop. % % link,evaluate,,evaluate num,evaluate dim,expand,count in, % process up to,grow % \skvquickkeys.preset{skeyval/foreach}{% parser,subparser,loop stopper,callback terminator,process up to, process empty list=false,item counter,list breaker,list pauser, recover holder values=false,grow left=false,grow right=false, keep decimals=true,keep high decimals=false,inherit=false, expand before fill=false,reverse list=false,expand list once=false, expand list twice=false,expand list fully=false,hide parameters=false } \skvnewdef*\skv@foreach@kvlist{} % \setupforeach{} \skvrobustdef*\setupforeach#1{% \skvifblankTF{#1}{}{% \skvaddtolist\skv@foreach@kvlist{#1}% }% } \skvrobustdef*\skv@foreach@setkeys#1{% \def\reserved@a{\skvquickkeys.set{skeyval/foreach}}% \expandafter\reserved@a\expandafter{\skv@foreach@kvlist,#1}% } % evaluate= as using % % 1. Evaluation is done with \edef unless \pgfmathparse is present % in or key 'pgf evaluate' is called. % % 2. must be a valid formula, eg, % % \pgfmathparse\x*2 % \pgfmathparse{exp(50)*\x*2+sin(.5*pi)*60} % \numexpr\x*2 % \skvexpandonce\x % % or simply % % 'evaluate \x as \x using ' % % The latter is equivalent to asking for full expansion. See also % the keys 'evaluate num', 'evaluate dim', and 'expand'. % % 3. This allows to be generic. % \skvrobustdef*\skv@foreach@parseevaluate#1{% \begingroup \def\skv@tempxifin##1##2{% \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% }% \skv@foreach@swafalse \def\skv@tempd{}% \def\skv@tempa##1as##2using##3\skv@nil{% \edef\skv@prova{\skvtrimspace{##1}}% \edef\skv@provb{\skvtrimspace{##2}}% \edef\skv@provc{\skvtrimspace{##3}}% \ifx\skv@prova\@empty \skv@err{Value of key 'evaluate' has no holder macro}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@prova}{% \expandafter\skvifntypeTF\expandafter{\skv@prova}{}{% \skv@err{Value of key 'evaluate': more than 1 \MessageBreak token \skvoxdetok\skv@prova. \MessageBreak I can't find holder macro}\skv@ehd }% }{% \skv@err{Value of key 'evaluate': \MessageBreak holder macro \skvoxdetok\skv@prova not escaped}\skv@ehd }% \fi \ifx\skv@provb\@empty \skv@err{Value of key 'evaluate' has no child macro}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@provb}{% \expandafter\skvifntypeTF\expandafter{\skv@provb}{}{% \skv@err{Value of key 'evaluate': more than 1 \MessageBreak token \skvoxdetok\skv@provb. \MessageBreak I can't find child macro}\skv@ehd }% }{% \skv@err{Value of key 'evaluate': \MessageBreak child \skvoxdetok\skv@provb not escaped}\skv@ehd }% \fi \ifx\skv@provc\@empty \skv@err{Value of key 'evaluate' has no formula or \MessageBreak holder macro to be expanded}\skv@ehd \fi \skv@tempxifin{\pgfmathparse}{##3}{% \def\skv@tempc####1\pgfmathparse####2\skv@nil{% \ifx\@nnil####1\@nnil \skv@foreach@swatrue \else \skv@err{Invalid token \detokenize{####1} \MessageBreak before \string\pgfmathparse}\skv@ehd \fi }% \skv@tempc##3\skv@nil }{% \skv@tempxifin{\numexpr}{##3}{% \def\skv@tempd{\relax}% }{% \skv@tempxifin{\dimexpr}{##3}{% \def\skv@tempd{\relax}% }{% \def\skv@tempd{}% }% }% }% }% \skv@tempxifin{using}{#1}{% \skv@tempxifin{as}{#1}{% % 'as' and 'using' are present: maybe there is a formula. \skv@foreach@swbtrue \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'evaluate': \MessageBreak there is 'using', but no 'as'}\skv@ehd }% }{% % No formula given. Maybe the key is 'expand' or still 'evaluate' % but without formula. \skv@foreach@swbfalse \skv@tempxifin{as}{#1}{% \def\skv@tempb##1as##2##3\skv@nil{% \ifx\@nnil##1\@nnil \skv@err{Value of key 'evaluate' has no holder macro}\skv@ehd \else \ifx\@nnil##2% \skv@err{Value of key 'evaluate' has no child macro}\skv@ehd \else \skv@tempa##1as##2using##1\skv@nil \fi \fi }% \skv@tempb#1{\@nnil}\skv@nil }{% % No 'as' or 'using': #1 should be only the holder macro: \ifx\@nnil#1\@nnil \skv@err{Value of key 'evaluate' has no holder macro}\skv@ehd \else \skvifntypeTF{#1}{% % Expand the holder macro: \skv@tempa#1as#1using#1\skv@nil }{% \skv@err{Value of key 'evaluate': more than 1 \MessageBreak token '\detokenize{#1}'. \MessageBreak I can't find holder macro}\skv@ehd }% \fi }% }% \skv@foreach@addtocallback{afterpre}{% \ifskv@foreach@swa % has the syntax \pgfmathparse{\x}. \skvexpandonce\skv@provc \let\skvexpandonce\skv@provb\noexpand\pgfmathresult \else % has the syntax \numexpr\x*2 or \dimexpr\x*2. % \ifskv@foreach@swb is true when a formula has been given. \edef\skvexpandonce\skv@provb{% \ifskv@foreach@swb\noexpand\the\fi \skvexpandonce\skv@provc\skv@tempd }% \fi }% \skvaftergroupdef\skv@foreach@afterprecallback\endgroup } % pgfmath parse= as using % % 1. Evaluation is always done with \pgfmathparse. % % 2. must be \pgfmathparse-able. % \skvrobustdef*\skv@foreach@parsepgfmathparse#1{% \begingroup \ifdefined\pgfmathparse\else \skv@err{No \string\pgfmathparse; 'pgfmath' module not loaded}\skv@ehd \fi \def\skv@tempxifin##1##2{% \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% }% \skv@foreach@swafalse \def\skv@tempa##1as##2using##3\skv@nil{% \edef\skv@prova{\skvtrimspace{##1}}% \edef\skv@provb{\skvtrimspace{##2}}% \edef\skv@provc{\skvtrimspace{##3}}% \ifx\skv@prova\@empty \skv@err{Value of key 'pgfmath parse' has no holder macro}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@prova}{% \expandafter\skvifntypeTF\expandafter{\skv@prova}{}{% \skv@err{Value of key 'pgfmath parse': more than 1 \MessageBreak token \skvoxdetok\skv@prova. \MessageBreak I can't find holder macro}\skv@ehd }% }{% \skv@err{Value of key 'pgfmath parse': \MessageBreak holder macro \skvoxdetok\skv@prova not escaped}\skv@ehd }% \fi \ifx\skv@provb\@empty \skv@err{Value of key 'pgfmath parse' has no child macro}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@provb}{% \expandafter\skvifntypeTF\expandafter{\skv@provb}{}{% \skv@err{Value of key 'pgfmath parse': more than 1 \MessageBreak token \skvoxdetok\skv@provb. \MessageBreak I can't find child macro}\skv@ehd }% }{% \skv@err{Value of key 'pgfmath parse': \MessageBreak child \skvoxdetok\skv@provb not escaped}\skv@ehd }% \fi \ifx\skv@provc\@empty \skv@err{Value of key 'pgfmath parse' has no formula or \MessageBreak holder macro to be expanded}\skv@ehd \fi \skv@tempxifin{\pgfmathparse}{##3}{% \def\skv@tempc####1\pgfmathparse####2\skv@nil{% \ifx\@nnil####1\@nnil \skv@foreach@swatrue \else \skv@err{Invalid token \detokenize{####1} \MessageBreak before \string\pgfmathparse}\skv@ehd \fi }% \expandafter\skv@tempc\skv@provc\skv@nil }{% \skv@tempxifin{\numexpr}{##3}{% \skv@err{Value of key 'pgfmath parse': \MessageBreak\noexpand\numexpr not allowed}\skv@ehd }{% \skv@tempxifin{\dimexpr}{##3}{% \skv@err{Value of key 'pgfmath parse': \MessageBreak\noexpand\dimexpr not allowed}\skv@ehd }{% \skv@foreach@swatrue \edef\skv@provc{\noexpand\pgfmathparse{\skvexpandonce\skv@provc}}% }% }% }% }% \skv@tempxifin{using}{#1}{% \skv@tempxifin{as}{#1}{% % 'as' and 'using' are present: maybe there is a formula. \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'pgfmath parse': \MessageBreak there is 'using', but no 'as'}\skv@ehd }% }{% \skv@tempxifin{as}{#1}{% \def\skv@tempb##1as##2##3\skv@nil{% \ifx\@nnil##1\@nnil \skv@err{Value of key 'pgfmath parse' has no holder macro}\skv@ehd \else \ifx\@nnil##2% \skv@err{Value of key 'pgfmath parse' has no child macro}\skv@ehd \else \skv@tempa##1as##2using##1\skv@nil \fi \fi }% \skv@tempb#1{\@nnil}\skv@nil }{% % No 'as' or 'using': #1 should be only the holder macro: \ifx\@nnil#1\@nnil \skv@err{Value of key 'pgfmath parse' has no holder macro}\skv@ehd \else \skvifntypeTF{#1}{% % Evaluate the holder macro: \skv@tempa#1as#1using#1\skv@nil }{% \skv@err{Value of key 'pgfmath parse': more than 1 \MessageBreak token '\detokenize{#1}'. \MessageBreak I can't find holder macro}\skv@ehd }% \fi }% }% \skv@foreach@addtocallback{afterpre}{% \ifskv@foreach@swa \skvexpandonce\skv@provc \let\skvexpandonce\skv@provb\noexpand\pgfmathresult \fi }% \skvaftergroupdef\skv@foreach@afterprecallback\endgroup } % count in = \y all \x satisfying initially % % 1. must be a balanced and valid TeX conditional, like % % \ifnum\x>2\fi, \ifx\x\@empty\fi % % 2. The aim is to allow general conditions (not only those involving % numerals) to be submitted. % % 3. PGF's \foreach doesn't have this feature; it has only a general % counter, eg, % % '\foreach \x [count=\xi] in {a,...,e}'. % % Generic counting is available in \newforeach by default, without % user request. The macros \foreachcurrentitem, \foreachitemcount, % \foreachnextitem are always available on each nesting level. The % boolean \ifforeachlastitem is also always available, to indicate when % the last item of the list has been reached: % % \ifforeachlastitem \typeout{Processing last entry of the list} \fi % % 4. Counting is done from 1 (zero) unless is given after % 'initially'. % \skvrobustdef*\skv@foreach@parsecountin#1{% \begingroup \def\skv@tempxifin##1##2{% \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% }% \def\skv@tempa##1\skv@nil{% \skv@tempxifin{initially}{##1}{% \skv@tempb##1\skv@nil }{% \skv@tempb##1initially\skv@nil }% }% \def\skv@tempb##1all##2satisfying##3initially##4\skv@nil{% \edef\skv@prova{\skvtrimspace{##1}}% \edef\skv@provb{\skvtrimspace{##2}}% \edef\skv@provc{\skvtrimspace{##3}}% \edef\skv@provd{\skvtrimspace{##4}}% \ifx\skv@prova\@empty \skv@err{Value of key 'count' has no counter macro}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@prova}{% \expandafter\skvifntypeTF\expandafter{\skv@prova}{}{% \skv@err{Value of key 'count in': more than 1 \MessageBreak token \skvoxdetok\skv@prova. \MessageBreak I can't find counter macro}\skv@ehd }% }{% \skv@err{Value of key 'count':\MessageBreak counter macro \skvoxdetok\skv@prova not escaped}\skv@ehd }% \fi \ifx\skv@provd\@empty \expandafter\def\skv@prova{0}% \else \skvifintegerTF\skv@provd{% \expandafter\let\skv@prova\skv@provd }{% \skv@err{Value of key 'count':\MessageBreak initial \skvoxdetok\skv@provd not an integer}\skv@ehd }% \fi \skv@foreach@swafalse \ifx\skv@provc\@empty % No tester but there may be a holder macro to test. The holder % macro, on its own, isn't sufficient to conduct a test: \let\skv@foreach@itemcounter\skv@prova \else \ifx\skv@provb\@empty\else % If there isn't a holder macro or quantity to test, then no % test is possible: \expandafter\skvifescapedTF\expandafter{\skv@provb}{% \expandafter\skvifntypeTF\expandafter{\skv@provb}{}{% \skv@err{Value of key 'count in': more than 1 \MessageBreak token \skvoxdetok\skv@provb. \MessageBreak I can't find holder macro}\skv@ehd }% }{% \skv@err{Value of key 'count':\MessageBreak holder macro \skvoxdetok\skv@provb not escaped}\skv@ehd }% \skv@foreach@swatrue % \skv@tester is the second argument of \skv@foreach@maketester. % \skv@tester is used in pushing the item counter: \skvexpbracenext\skv@foreach@maketester\skv@provc\skv@tester\skvz@ \fi \fi }% \skv@tempxifin{satisfying}{#1}{% \skv@tempxifin{all}{#1}{% % 'all' and 'satisfying' are present: \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'count': \MessageBreak there is 'satisfying', but no 'all'}\skv@ehd }% }{% \skv@tempxifin{all}{#1}{% \skv@tempa#1satisfying\skv@nil }{% % No 'all' or 'satisfying': #1 should be only the counter macro: \ifx\@nnil#1\@nnil \skv@err{Value of key 'count' has no counter macro}\skv@ehd \else \skvifntypeTF{#1}{% \skv@tempa#1all satisfying\skv@nil }{% \skv@err{Value of key 'count in': more than 1 \MessageBreak token '\detokenize{#1}'. \MessageBreak I can't find counter macro}\skv@ehd }% \fi }% }% \ifskv@foreach@swa \skv@foreach@addtocallback{afterpre}{% \noexpand\ifnum\noexpand\foreachitemcount=\@ne \def\skvexpandonce\skv@prova{\number\skv@prova}% \noexpand\fi \skvexpandonce\skv@tester{% \noexpand\skvpushnumber\skvexpandonce\skv@prova }{}% }% \fi \skvexpanded{\endgroup \ifskv@foreach@swa \skvcmdexit\skv@foreach@afterprecallback \else \skvcmdexit\skv@foreach@itemcounter \fi }% } % remember= as initially % \skvrobustdef*\skv@foreach@parseremember#1{% \begingroup \def\skv@tempxifin##1##2{% \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% }% \skv@tempxifin{(}{#1}{% \skv@err{Value of key 'remember': '(' found. \MessageBreak I don't accept this PGF format. \MessageBreak Remove the parenthesis '()'}\skv@ehd }{}% \def\skv@tempa##1as##2initially##3\skv@nil{% \edef\skv@prova{\skvtrimspace{##1}}% \edef\skv@provb{\skvtrimspace{##2}}% \edef\skv@provc{\skvtrimspace{##3}}% \skv@foreach@swafalse \ifx\skv@prova\@empty \skv@err{Value of key 'remember' has no holder macro: \MessageBreak i.e., no macro that holds input}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@prova}{}{% \skv@err{Value of key 'remember': \MessageBreak Holder macro \skvoxdetok\skv@prova not escaped}\skv@ehd }% \fi \ifx\skv@provb\@empty \skv@err{Value of key 'remember' has no child macro; \MessageBreak i.e., no macro after 'as'}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@provb}{% \skv@foreach@swatrue }{% \skv@err{Value of key 'remember': \MessageBreak Child \skvoxdetok\skv@provb not escaped}\skv@ehd }% \fi }% \skv@tempxifin{initially}{#1}{% \skv@tempxifin{as}{#1}{% \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'remember': \MessageBreak There is 'initially', but no 'as'}\skv@ehd }% }{% \skv@tempxifin{as}{#1}{% \skv@tempa#1initially\skv@nil }{% % No 'as' and 'initially': \edef\skv@prova{\skvtrimspace{#1}}% \ifx\skv@prova\@empty\else % Go and raise error in \skv@tempa: \skv@tempa#1as initially\skv@nil \fi }% }% \ifskv@foreach@swa % Initially: \skv@foreach@addtocallback{pre}{% % Don't remove this \ifnum, otherwise the initial assignment % will be overwritten on subsequent returns: \noexpand\ifnum\noexpand\foreachitemcount=\@ne \edef\skvexpandonce\skv@provb{% \noexpand\unexpanded{\skvexpandonce\skv@provc}% }% \noexpand\fi }% \skv@foreach@addtocallback{post}{% \let\skvexpandonce\skv@provb\skvexpandonce\skv@prova }% \fi \skvexpanded{\endgroup \ifskv@foreach@swa \skvcmdexit\skv@foreach@precallback \skvcmdexit\skv@foreach@postcallback \fi }% } % recall= initially . % % This builds a retainer macro of the form \. % % 'as' is invalid/illegal here, since a retainer macro is built internally. % \skvrobustdef*\skv@foreach@parserecall#1{% \begingroup \def\skv@tempxifin##1##2{% \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% }% \skv@tempxifin{(}{#1}{% \skv@err{Value of key 'recall': '(' found. \MessageBreak I don't accept this PGF format. \MessageBreak remove the parenthesis '()'}\skv@ehd }{}% \skv@foreach@swafalse \def\skv@tempa##1initially##2\skv@nil{% \edef\skv@prova{\skvtrimspace{##1}}% \edef\skv@provb{\skvtrimspace{##2}}% \ifx\skv@prova\@empty \skv@err{Value of key 'recall' has no holder macro: \MessageBreak i.e., no macro that holds input}\skv@ehd \else \expandafter\skvifntypeTF\expandafter{\skv@prova}{% \expandafter\skvifescapedTF\expandafter{\skv@prova}{% \edef\skv@elt{\expandafter\skvremovescape\skv@prova}% \skv@foreach@swatrue % Initially: \skv@foreach@addtocallback{pre}{% % Don't remove this \ifnum, otherwise the initial assignment % will be overwritten on subsequent returns: \noexpand\ifnum\noexpand\foreachitemcount=\@ne \skvcsedef{foreachlast\skv@elt}{% \noexpand\unexpanded{\skvexpandonce\skv@provb}% }% \noexpand\fi }% \skv@foreach@addtocallback{post}{% \skvcslet{foreachlast\skv@elt}\skvexpandonce\skv@prova }% }{% \skv@err{Value of key 'recall': \MessageBreak \detokenize{#1} is not escaped}\skv@ehd }% }{% \skv@err{Value of key 'recall': \MessageBreak \detokenize{#1} is not one token}\skv@ehd }% \fi }% \skv@tempxifin{as}{#1}{% \skv@err{Value of key 'recall': invalid 'as' found. \MessageBreak This key doesn't expect 'as' since \MessageBreak it automatically builds a retainer macro \MessageBreak of the form \}\skv@ehd }{% \skv@tempxifin{initially}{#1}{% \skv@tempa#1\skv@nil }{% \ifx\@nnil#1\@nnil\else \skv@tempa#1initially\skv@nil \fi }% }% \skvexpanded{\endgroup \ifskv@foreach@swa \skvcmdexit\skv@foreach@precallback \skvcmdexit\skv@foreach@postcallback \fi }% } % \skv@foreach@doreverselist{}{} \skvnewdef*\skv@foreach@doreverselist#1#2{% \begingroup \def\skv@tempb{}% \def\skv@tempa##1#1##2\skv@reverse@stop{% \if\relax\detokenize{##2}\relax\skv@reverse@stop\fi \skv@tempa##2\skv@reverse@stop \edef\skv@tempb{% \skvexpandonce\skv@tempb\ifx\skv@tempb\@empty\else#1\fi \unexpanded{##1}% }% }% \def\skv@reverse@stop##1\skv@reverse@stop{\fi}% \expandafter\skv@tempa#2#1\skv@reverse@stop \let#2\skv@tempb \skvaftergroupdef#2\endgroup } % Eg, \skv@dots@in\skv@nil...\skv@nnil\skv@stop \skvnewdef*\skv@dots@in#1...#2#3\skv@stop{% \ifx\skv@nnil#2\in@false\else\in@true\fi } \skvrobustdef*\skv@foreach@latehookerr{% \def\skv@foreach@latehook{% \begingroup \let\s\string \skv@err{A \noexpand\newforeach hook (\s\prependtobeginforeach, \MessageBreak\s\appendtobeginforeach, \s\atbeginforeach, \MessageBreak\s\prependtoendforeach, \s\appendtoendforeach, \MessageBreak or \s\atendforeach) has been illegally \MessageBreak issued within \s\newforeach} {\s\newforeach\space hook command shouldn't be issued within \s\newforeach.}% \endgroup }% \skvletmanytocmd{% \prependtobeginforeach,\appendtobeginforeach,\atbeginforeach, \prependtoendforeach,\appendtoendforeach,\atendforeach }\skv@foreach@latehook } \skvrobustdef*\skv@foreach@pushstate{% \skvsavestate\skv@foreach@stack{% \do\skv@foreach@starform\do\skv@foreach@parser \do\skv@foreach@subparser\do\skv@foreach@listisamacro \do\skv@foreach@processupto\do\skv@foreach@processempty \do\skv@foreach@exittester\do\skv@foreach@continuetester \do\skv@foreach@grow\do\skv@foreach@growleft\do\skv@foreach@growright \do\skv@foreach@terminator\do\skv@foreach@recoverholders \do\skv@foreach@normalizelist\do\skv@foreach@callback \do\skv@foreach@hideparameters\do\skv@foreach@callback@hiddenparameters \do\skv@foreach@auxcallback\do\skv@foreach@precallback \do\skv@foreach@afterprecallback\do\skv@foreach@postcallback \do\skv@foreach@onlyinitially \do\foreachlistremainder\do\skv@foreach@mainloop \do\skv@foreach@getnext\do\skv@foreach@picknext\do\skv@foreach@getrm \do\skv@foreach@do@a\do\skv@foreach@do@b % Macros '...lookahead...' need stacking in \foreachfox and when % \newforeach is nested with \foreachfox: \do\skv@foreach@lookahead@a\do\skv@foreach@lookahead@b \do\skv@foreach@lookahead@c\do\skv@foreach@lookahead@d \do\skv@foreach@paramlist\do\skv@foreach@holderlist \do\skv@foreach@userlist\do\skv@foreach@inherit \do\skv@foreach@keepdecimals\do\skv@foreach@keephighdecimals \do\skv@foreach@itemcounter\do\skv@foreach@link \do\skv@foreach@expandbeforefill\do\skv@foreach@expandlistonce \do\skv@foreach@expandlisttwice\do\skv@foreach@expandlistfully \do\skv@listbreakertoks\do\skv@listpausertoks \do\skv@foreach@reverselist\do\foreachcurrentitem \do\foreachnextitem\do\foreachitemcount\do\foreachprevitem % The following commands are disabled on entry into the loop. % Hence they need to be stacked here: \do\prependtobeginforeach\do\appendtobeginforeach\do\atbeginforeach \do\prependtoendforeach\do\appendtoendforeach\do\atendforeach }\foreachnestdepth } \skvrobustdef*\skv@foreach@popstate{% \skvrestorestate\skv@foreach@stack\foreachnestdepth } \skvnewlet\skv@foreach@nil\relax \skvnewdef*\skv@foreach@nnil{\skv@foreach@nil} \skvrobustdef*\newforeach{\skv@testst\skv@newforeach@beginprescan} \skvrobustdef*\skv@newforeach@beginprescan{% \skv@inforeachtrue \edef\skv@foreach@starform{0\ifskv@tempst0\else1\fi}% \begingroup \def\skv@foreach@holderlist{}% \def\skv@tempa{% \skvexpanded{\endgroup \noexpand\skv@foreach@endprescan {\skvexpandonce\skv@foreach@holderlist}% }% }% \let\bgroup\relax \skvifnextchar[{% \endgroup\skv@foreach@scanarg }{% \skvifnextchar i{% \endgroup \skv@err{\string\newforeach: no holder macro seen}\skv@ehd }{% \skvifnextchar\skv@orig@bgroup{% \endgroup \skv@err{\string\newforeach: no holder macro seen}\skv@ehd }{% \skv@foreach@collectholders }% }% }% } \skvrobustdef*\skv@foreach@collectholders#1{% \edef\skv@foreach@holderlist{% \skvexpandonce\skv@foreach@holderlist\skvtrimspace{#1}% }% \skvifnextchar[{% \skv@tempa }{% \skvifnextchar i{% \skv@tempa[]% }{% \skvifnextchar\skv@orig@bgroup{% \skv@tempa[]% }{% \skv@foreach@collectholders }% }% }% } \skvrobustdef*\skv@foreach@endprescan#1[#2]{% \skvifblankTF{#1}{% \skv@err{\string\newforeach: no holder macros seen}\skv@ehd }{% \skv@foreach@scanarg[#2]#1% }% } \skvrobustdef*\skv@foreach@scanarg{\skv@testopt\skv@foreach@scanarg@a{}} \skvrobustdef*\skv@foreach@scanarg@a[#1]{% \skv@foreach@pushstate \skv@foreach@latehookerr % \foreachitemcount must be a macro, not a counter, because it is stacked: \def\foreachitemcount{0}% % Don't confuse macros of various depths; reset them here: \def\do##1{\def##1{}}% \do\skv@foreach@itemcounter\do\skv@foreach@processupto \do\skv@foreach@callback\do\skv@foreach@auxcallback \do\skv@foreach@callback@hiddenparameters \do\skv@foreach@precallback\do\skv@foreach@afterprecallback \do\skv@foreach@postcallback\do\skv@foreach@onlyinitially % The keys have to be set here, to determine if the list is a macro, etc. % Since \skv@foreach@precallback are initialized in each nest, the % keys have to be reset here. Reset all keys: they might have been % fixed by the outer loop and the inner loop might assume the default % values of the keys are those being used. \skv@foreach@setkeys{#1}% % We've set the keys; let's overrule \skv@foreach@expandlistonce if % we had seen a star suffix. Don't overrule \skv@foreach@expandlisttwice % and \skv@foreach@expandlistfully. \if\skv@foreach@starform \def\skv@foreach@expandlistonce{00}% \fi \ifcase0% % Take only one case: \if\skv@foreach@expandlistonce\else \if\skv@foreach@expandlisttwice\else \if\skv@foreach@expandlistfully\else 1\fi\fi\fi\relax \def\skv@foreach@listisamacro{00}% \else \def\skv@foreach@listisamacro{01}% \fi \begingroup % Collect item holders. Don't confuse explicit \bgroup for left brace: \skv@cnta\skvz@ \def\skv@foreach@holderlist{}% \let\bgroup\relax \skvifnextchar i\skv@foreach@scanarg@c{% \skvifnextchar\skv@orig@bgroup \skv@foreach@scanarg@d\skv@foreach@scanarg@b }% } % #1: one holer macro or subparser. \skvrobustdef*\skv@foreach@scanarg@b#1{% % Odd items must be subparser: \ifodd\skv@cnta \ifnum\skv@cnta=\@ne \skvifescapedTF{#1}{% \skv@err{Token '\noexpand#1' cannot be a subparser; \MessageBreak it seems to be a holder macro. I expected \MessageBreak the subparser to be the token here.}\skv@ehd }{% \edef\skv@prova{\skvtrimspace{#1}}% \let\elt\skvexpandonce \let\skv@elt\skv@foreach@subparser \if\elt\skv@prova\elt\skv@elt\else % Don't stack \skv@warnsubparser, so that the following % warning isn't called more than once in the inner loop. \ifnum\skv@warnsubparser=\skvz@ \skvgadvanceno\skv@warnsubparser\@ne \skv@warn{Scanned subparser '\elt\skv@prova' is different from \MessageBreak the default or user-supplied subparser '\elt\skv@elt'. \MessageBreak I have used '\elt\skv@prova', but please submit \MessageBreak '\elt\skv@prova' as the value of the key 'subparser' \MessageBreak so that I can stop giving this warning. }% \fi \let\skv@foreach@subparser\skv@prova \fi }% \fi \else \skvifescapedTF{#1}{}{% \skv@err{Token '\noexpand#1' is not escaped \MessageBreak and can't be a holder macro}\skv@ehd }% \fi \advance\skv@cnta\@ne \edef\skv@foreach@holderlist{% \skvexpandonce\skv@foreach@holderlist\skvtrimspace{#1}% }% \skvifnextchar i\skv@foreach@scanarg@c{% \skvifnextchar\skv@orig@bgroup \skv@foreach@scanarg@d\skv@foreach@scanarg@b }% } \skvrobustdef*\skv@foreach@scanarg@c#1#2{% \skvifstrcmpTF{#1#2}{in}{% \skv@foreach@scanarg@d }{% \skv@err{I have seen 'i' but no expected 'in'}\skv@ehd }% } \skvrobustdef*\skv@foreach@scanarg@d{% \ifx\skv@foreach@holderlist\@empty \skv@err{No item holder macros before 'in' \MessageBreak or before left brace}\skv@ehd \fi \skvifnextchar\skv@orig@bgroup{% \skv@foreach@scanarg@e }{% \if\skv@foreach@listisamacro \expandafter\skv@foreach@scanarg@e \else \def\reserved@a##1{% \skvifmacroTF{##1}{% \def\skv@tempehd{Maybe a star (*) suffix after \noexpand\newforeach or key 'expand list once', etc., \MessageBreak is missing.}% }{% \let\skv@tempehd\skv@ehd }% \skv@err{I expected a left brace for beginning of list, \MessageBreak since you haven't told me that your \MessageBreak list is a macro. Instead I found '\detokenize{##1}'. \MessageBreak If your list is indeed a macro, you can \MessageBreak either put star (*) after \noexpand\newforeach \MessageBreak or use the key 'expand list once' \MessageBreak or 'expand list twice' or 'list is a macro', etc.% }\skv@tempehd }% \expandafter\reserved@a \fi }% } % #1: or \skvrobustdef*\skv@foreach@scanarg@e#1{% \edef\skv@foreach@userlist{\unexpanded{#1}}% \skvifnextchar\skv@orig@bgroup\skv@foreach@scanarg@h{% \skvifnextchar d\skv@foreach@scanarg@f\skv@foreach@scanarg@g }% } \skvrobustdef*\skv@foreach@scanarg@f#1#2{% \skvifstrcmpTF{#1#2}{do}{% \skvifnextchar\skv@orig@bgroup \skv@foreach@scanarg@h\skv@foreach@scanarg@g }{% \skv@err{I have seen 'd' but no the expected 'do'}\skv@ehd }% } % We've exhausted all options for grabbing the callback, so now % look for terminator (default ;). % % 1. If there is no terminator ahead, the use of \skv@prova will trigger % 'the use of ... does not match its definition' or % 'runaway argument ...'. % 2. This covers the case when \newforeach or \foreach comes next in % the callback. \skvrobustdef*\skv@foreach@scanarg@g{% \def\skv@prova##1{% \def\skv@prova####1##1{% % Look out for a case like 'parser='. % Eg, \newforeach[parser=;]. In this case, the value ';' of % key 'parser' will mistakenly be assumed to be the callback % terminator. It should be enclosed in braces. \skvxifinTF{\detokenize{parser=}\relax}{\detokenize{####1}\relax}{% \skvxifinTF{[}{\detokenize{####1}}{% \skv@err{Put '##1' in braces for key 'parser=##1'. \MessageBreak Try [parser={##1}]} {Maybe parser '##1' is the value of a key/option of \noexpand\newforeach and needs to be enclosed in braces. The '##1' I have just encountered doesn't seem to be the one ending a TikZ object. Maybe you need to do [parser={##1}].}% }{% % Otherwise, let's try continue: \skvexpanded{% \noexpand\skv@foreach@scanarg@h{\skvtrimspace{####1}##1}% }% }% }{% \skvexpanded{% \noexpand\skv@foreach@scanarg@h{\skvtrimspace{####1}##1}% }% }% }% \skv@prova }% % In case callback terminator is currently active, rescan it. \skvrescan\skv@foreach@terminator \expandafter\skv@prova\expandafter{\skv@foreach@terminator}% } % #1: callback \skvrobustdef*\skv@foreach@scanarg@h#1{% \skvexpanded{\endgroup % The subparser may have changed along the way % (see \skv@foreach@scanarg@b): \skvcmdexit\skv@foreach@subparser \skv@foreach@mainprocess {\skvexpandonce\skv@foreach@holderlist}% {\skvexpandonce\skv@foreach@userlist}% {\skvtrimspace{#1}}% }% } % #1: holder macros % #2: List or list command % #3: Callback \skvrobustdef*\skv@foreach@mainprocess#1#2#3{% \edef\skv@foreach@userlist{% \if\skv@foreach@expandlistonce \expandafter\skvexpandonce \else \if\skv@foreach@expandlisttwice \expandafter\expandafter\expandafter\skvexpandtwice \else \if\skv@foreach@expandlistfully \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter\@iden \else \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter\unexpanded \fi \fi \fi {#2}% }% % Initial code, if any: \skvcsuse{skv@foreach@atbeginhook@\skvrom\foreachnestdepth}% \skvifdefTF\foreachprevitem{}{\def\foreachprevitem{}}% \expandafter\skv@foreach@normalize\expandafter[\skv@foreach@parser]% \skv@foreach@userlist % Why 'keep double parser' here? Think of a list like 32//13,11/23/,... \skvexpbracenext\skvdefinekeepdoubleparsernormalizer \skv@foreach@subparser\skv@tempa \edef\skv@foreach@userlist{\skvexpbracenext\skv@tempa\skv@foreach@userlist}% \ifnum\foreachnestdepth=\skvz@ \breakallforeachloopsfalse \fi \skvbreakloopfalse \foreachlastitemfalse \def\skv@foreach@lookahead@a##1{% \def\skv@foreach@picknext{##1.}% \futurelet\skv@foreach@next\skv@foreach@lookahead@b }% \def\skv@foreach@lookahead@b{% \ifx\skv@foreach@next[% \expandafter\skv@foreach@lookahead@c \else \ifx\skv@foreach@next(% \expandafter\expandafter\expandafter\skv@foreach@lookahead@d \else \expandafter\expandafter\expandafter\skv@foreach@picknext \fi \fi }% \def\skv@foreach@lookahead@c[##1]{\skv@foreach@picknext[{##1}]}% \def\skv@foreach@lookahead@d(##1){\skv@foreach@picknext({##1})}% \def\skv@foreach@mainloop##1{% \def\skv@foreach@getnext####1##1####2\skv@foreach@stop{% \edef\foreachnextitem{\skvexpandonce{\@gobble####1}}% \ifx\foreachnextitem\skv@foreach@nnil \foreachlastitemtrue \def\foreachnextitem{}% \fi }% \def\skv@foreach@do@a####1##1####2\skv@foreach@stop{% \edef\foreachcurrentitem{\skvexpandonce{\@gobble####1}}% \skvifxTF\foreachcurrentitem\skv@foreach@nnil{% \skvbreakloopfalse \foreachlastitemfalse }{% \skvifxTF\foreachcurrentitem\skv@listbreakertoks{% \skv@foreach@getrm{####2}% }{% \skvifxTF\foreachcurrentitem\skv@listpausertoks{% \message{^^J! List pause: ^^JType x or X to quit, or to proceed^^J}% \begingroup \endlinechar\m@ne\global\read-1 to\@gtempa \endgroup \skvexpandarg\lowercase{\def\noexpand\@gtempa{\@gtempa}}% \skvxifstrcmpTF\@gtempa{x}{% \skv@foreach@getrm{####2}% }{% \skv@foreach@do@b{####2}% }% }{% \skv@foreach@do@b{####2}% }% }% }% }% \def\skv@foreach@do@b####1{% \edef\foreachitemcount{\the\numexpr\foreachitemcount+1}% \ifx\skv@foreach@itemcounter\@empty\else \expandafter\let\skv@foreach@itemcounter\foreachitemcount \fi \skv@foreach@lookahead@a\skv@foreach@getnext####1\skv@foreach@stop % If the user decides to continue after \foreachlistpauser is picked up, % don't use \foreachlistpauser as an item: \skvifxTF\foreachcurrentitem\skv@listpausertoks{}{% \skvexpbracenext\skv@foreach@callback\foreachcurrentitem \let\foreachprevitem\foreachcurrentitem }% \ifx\skv@foreach@processupto\@empty\else \ifnum\foreachitemcount<\skv@foreach@processupto\relax\else \skvbreakloop \fi \fi \skvifdefboolTF{skvbreakloop}{% \skv@foreach@getrm{####1}% }{% \skv@foreach@lookahead@a\skv@foreach@do@a####1\skv@foreach@stop }% }% \def\skv@foreach@getrm####1{% \ifbreakallforeachloops\else \skvbreakloopfalse \fi \foreachlastitemfalse \def\skv@prova########1\skv@foreach@nil##1{% \edef\foreachlistremainder{\unexpanded{########1}}% \skv@removetrailingparser{##1}\foreachlistremainder }% \skv@prova####1% }% \skvifxTF\skv@foreach@userlist\@empty{% \if\skv@foreach@processempty\skvafterfi \skv@foreach@callback{}% \fi }{% \def\do####1{\if####1true\else false\fi}% \skvexpandsecond{\skvautocompletelist*}{[% % Note: the value of 'expand list once', etc., can't be % transferred automatically to \skvautocompletelist since they % have been used above to expand list. parser={\skv@foreach@parser}, link={\skvexpandonce\skv@foreach@link}, grow left=\do\skv@foreach@growleft, grow right=\do\skv@foreach@growright, keep decimals=\do\skv@foreach@keepdecimals, keep high decimals=\do\skv@foreach@keephighdecimals, expand before fill=\do\skv@foreach@expandbeforefill ]}\skv@foreach@userlist\skv@foreach@userlist \if\skv@foreach@reverselist\skvafterfi \expandafter\skv@foreach@doreverselist\expandafter {\skv@foreach@parser}\skv@foreach@userlist \fi \expandafter\skv@foreach@lookahead@a\expandafter\skv@foreach@do@a \skv@foreach@userlist##1\skv@foreach@nil##1\skv@foreach@stop }% }% \skv@foreach@makeprecode{#1}% \if\skv@foreach@recoverholders\else \expandafter\skvsavestate\expandafter\skv@foreach@holderstate \expandafter{\skv@foreach@holderlist}\skv@foreach@holderdepth \fi \skv@foreach@makeauxcallback{#3}% \skvexpandbracenext\skv@foreach@mainloop\skv@foreach@parser \skvcsuse{skv@foreach@atendhook@\skvrom\foreachnestdepth}% \if\skv@foreach@recoverholders\else \skvrestorestate\skv@foreach@holderstate\skv@foreach@holderdepth \fi \skv@foreach@popstate \ifnum\foreachnestdepth=\skvz@ \def\skv@warnsubparser{0}% \fi \skv@inforeachfalse } % \skv@foreach@makeprecode{} % % 'Holder macro' here means, eg, \x and \y in % % \newforeach \x/\y in {1/a,2/b,3/c}{} % \skvrobustdef*\skv@foreach@makeprecode#1{% \begingroup \skv@cnta\skvz@ \def\skv@foreach@holderlist{}% \def\skv@foreach@paramlist{}% \def\skv@prevholder{}% \def\skv@tempa{#1}% \expandafter\skv@foreach@normalize\expandafter [\skv@foreach@subparser]\skv@tempa \skvtfor*\skv@prova:=\skv@tempa\do{% \ifx\skv@prova\skv@foreach@subparser \ifnum\skv@cnta=\skvz@ \skv@err{Subparser '\skvoxdetok\skv@foreach@subparser' can't come first in the list\MessageBreak of holder macros}\skv@ehd \else % Eg, if subparser is slash (/), \skv@foreach@paramlist will have % the syntax: ##1/##2/...: \edef\skv@foreach@paramlist{% \skvexpandonce\skv@foreach@paramlist\skvexpandonce\skv@prova }% \fi \else \advance\skv@cnta\@ne \edef\skv@elt{\expandafter\skvremovescape\skv@prova}% \edef\skv@foreach@precallback{% \skvexpandonce\skv@foreach@precallback % Each given item-holder macro is now defined in terms of % parameters of skv@foreach@auxcallback: \edef\skvexpandonce\skv@prova{% \noexpand\unexpanded{####\number\skv@cnta}% }% % If the current holder has no value, use the value of last holder: \ifnum\skv@cnta>\@ne \if\skv@foreach@inherit \noexpand\ifx\skvexpandonce\skv@prova\noexpand\@empty \let\skvexpandonce\skv@prova\skvexpandonce\skv@prevholder \noexpand\fi \fi \fi }% \edef\skv@foreach@holderlist{% \skvexpandonce\skv@foreach@holderlist % The \do is for the individual entries of the stack of % \skv@foreach@holderlist. It is required for stacking the % holder list: \noexpand\do\skvexpandonce\skv@prova }% \edef\skv@foreach@paramlist{% \skvexpandonce\skv@foreach@paramlist########\number\skv@cnta }% \let\skv@prevholder\skv@prova \fi }% % Add one extra parameter character to absorb extra subparsers that are % added for incomplete list items: \edef\skv@foreach@paramlist{% \skvexpandonce\skv@foreach@paramlist \skvexpandonce\skv@foreach@subparser ########\number\numexpr\skv@cnta+1\relax }% \skvexpanded{\endgroup \skvcmdexit\skv@foreach@holderlist \skvcmdexit\skv@foreach@paramlist \skvcmdexit\skv@foreach@precallback }% } % Example (*): % % This example demonstrates why \skv@foreach@continuetester must be % located delicately, at where it is currently. % % \def\ditem{D} % \newforeach [ % continue=\ifx\x\ditem\fi, remember=\x as \rx initially A % ] \x in { % B,(C1),D,E,[F1],G,H % }{% % $\overrightarrow{\rx\x}$\ifforeachlastitem.\else,\space\fi % } % % #1: callback \skvrobustdef*\skv@foreach@makeauxcallback#1{% \begingroup \def\skv@generatesubparser##1{% \ifnum##1<10 \skvexpandonce\skv@foreach@subparser \expandafter\skv@generatesubparser \expandafter{\number\numexpr##1+1\expandafter}% \fi }% % Add extra subparsers in case some items aren't subparser-complete: \edef\skv@tempa{\skv@generatesubparser{1}}% \edef\skv@foreach@callback@hiddenparameters{\unexpanded{#1}}% \let\foreacheov\relax \let\do\noexpand \skvexpanded{\endgroup \skvcmdexit\skv@foreach@callback@hiddenparameters % Define auxiliary callback: \def\do\skv@foreach@auxcallback\skv@foreach@paramlist\foreacheov{% % Holder macro assignments: \skvexpandonce\skv@foreach@precallback % User tests/tasks, eg, if requested from 'evaluate' key: \skvexpandonce\skv@foreach@afterprecallback \do\ifnum\do\foreachitemcount=\@ne \do\skv@foreach@onlyinitially \do\fi \ifx\skv@foreach@continuetester\@secondoftwo \noexpand\skv@foreach@continuetester \else % Expose the parameter characters in \skv@foreach@continuetester. % If the user wants to ignore the callback for some items, he can % use the key 'continue=': \skvexpandonce\skv@foreach@continuetester \fi {% \relax }{% \if\skv@foreach@hideparameters \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi {% \noexpand\skv@foreach@callback@hiddenparameters }{% \unexpanded{#1}% }% % User tests/tasks, eg, if requested from the keys 'remember', % 'exit when', etc: \skvexpandonce\skv@foreach@postcallback }% }% % Define the real callback: \def\do\skv@foreach@callback####1{% \do\skv@foreach@auxcallback####1\skvxonce\skv@tempa\foreacheov }% }% } \skvnewdef*\skv@ucalpha#1{% \ifcase#1\or A\or B\or C\or D\or E\or F\or G\or H\or I\or J\or K\or L\or M\or N\or O\or P\or Q\or R\or S\or T\or U\or V\or W\or X\or Y\or Z\else?\fi } \skvnewdef*\skv@lcalpha#1{% \ifcase#1\or a\or b\or c\or d\or e\or f\or g\or h\or i\or j\or k\or l\or m\or n\or o\or p\or q\or r\or s\or t\or u\or v\or w\or x\or y\or z\else?\fi } \skvnewdef*\skv@alphamap{% {A}{a}{1}{B}{b}{2}{C}{c}{3}{D}{d}{4}{E}{e}{5}{F}{f}{6}{G}{g}{7}{H}{h}{8}% {I}{i}{9}{J}{j}{10}{K}{k}{11}{L}{l}{12}{M}{m}{13}{N}{n}{14}{O}{o}{15}% {P}{p}{16}{Q}{q}{17}{R}{r}{18}{S}{s}{19}{T}{t}{20}{U}{u}{21}{V}{v}{22}% {W}{w}{23}{X}{x}{24}{Y}{y}{25}{Z}{z}{26}% } \skvrobustdef*\skv@reverselumap#1{% \def\skv@prova##1##2##3##4\skv@nil{% \ifx\@nnil##1% \expandafter\@gobble \else \expandafter\@iden \fi {\skv@prova##4\skv@nil{##1}{##2}{##3}}% }% \edef#1{\expandafter\skv@prova\skv@alphamap\@nnil{}{}\skv@nil} } \skvquickkeys.define{skeyval/autocomplete}{% .exec/\def\skv@autocomplete@parser{,}; parser/{,}/ \edef\skv@autocomplete@parser{\unexpanded{#1}} \skvstripouterbraces{2}\skv@autocomplete@parser \skvxifntypeTF{\detokenize{#1}}{% \begingroup % It is assumed that every n-type parser and subparser % must have catcode 12: \skvexpandnext{\catcode`}\skv@autocomplete@parser=12\relax \skvrescan\skv@autocomplete@parser \skvaftergroupdef\skv@autocomplete@parser\endgroup }{} ; % This default value of 'link' is required by \skvautocompletelist: .exec code/\def\skv@autocomplete@link{\@nil}; link/\@nil/ \edef\skv@prova{\unexpanded{#1}}% \ifcase0% \ifx\skv@prova\@empty 1\fi \ifx\skv@prova\@nnil 1\fi\relax \edef\skv@autocomplete@link{\unexpanded{#1}}% \skvstripouterbraces{2}\skv@autocomplete@link \fi ; grow/\@nil/ \edef\skv@prova{\unexpanded{#1}}% \ifx\skv@prova\@nnil\else \skvcsedef{skv@autocomplete@grow#1}{00} \edef\skv@prova{\skvifstrcmpTF{#1}{left}{right}{left}}% \skvcsedef{skv@autocomplete@grow\skv@prova}{01}% \fi /left,right ; .exec/ \def\skv@autocomplete@growleft{01} \def\skv@autocomplete@growright{01} ; grow left/true/ \edef\skv@autocomplete@growleft{0\skvifstrcmpTF{true}{#1}01} /true,false ; grow right/true/ \edef\skv@autocomplete@growright{0\skvifstrcmpTF{true}{#1}01} /true,false ; % Keep the decimals in rounded numbers or dimensions when list is % auto-completed. The value value of this key is 'true'. keep decimals/true/ \edef\skv@autocomplete@keepdecimals{0\skvifstrcmpTF{true}{#1}01} /true,false ; keep high decimals,keep only high decimals/true/ \edef\skv@autocomplete@keephighdecimals{0\skvifstrcmpTF{true}{#1}01} /true,false ; expand before fill,expand list before fill/true/ \edef\skv@autocomplete@expandbeforefill{0\skvifstrcmpTF{true}{#1}01} /true,false ; } % The keys 'link,grow' don't need presetting. The user must supply % values when they are called. In internal loops, their values will % have to be revised from those of the outer loop. % \skvquickkeys.preset{skeyval/autocomplete}{% parser,grow left=false,grow right=false, keep decimals=true,keep high decimals=false, expand before fill=false } % \skv@autocomplete@addtolist \skvrobustdef*\skv@autocomplete@addtolist#1#2#3{% \edef#3{\skvexpandonce#3\ifx#3\@empty\else\unexpanded{#1}\fi#2}% } % \skv@autocomplete@zerostepwarn{}{}{} \skvrobustdef*\skv@autocomplete@zerostepwarn#1#2#3{% \skv@warn{The tokens '\detokenize{#1}', '\detokenize{#2}' give nil step; '1#3' used.\MessageBreak Maybe you used the font-dependent units\MessageBreak 'ex' or 'em' \ifskv@latex before \skv@begindoctoks\fi}% } % \skvautocompletelist[]{}{} % \skvautocompletelist*[]{}{} % % 1. Parse list of type {1,2,...,n,1,...,m} for auto completion. % Return outcome in or \skvcompletedlist. % \skvrobustdef*\skvautocompletelist{\skv@teststopt\skv@autocompletelist@a{}} \skvrobustdef*\skv@autocompletelist@a[#1]#2#3{% \skv@usetempst{#2}\skv@autocomplete@userlist \skvquickkeys.set{skeyval/autocomplete}{#1}% \def\skv@inalphabetic{01}% \def\skv@isupperalpha{01}% \def\skv@preandpostdotspresent{01}% % If the list is alphabetic or numbers, original unit is nil: \def\skv@autocomplete@origunit{}% \def\skvcompletedlist{}% \skvexpandtwoargsonce \skv@autocompletelist@b\skv@autocomplete@parser\skv@autocomplete@userlist \let#3\skvcompletedlist } % \skv@autocompletelist@b{}{} \skvrobustdef*\skv@autocompletelist@b#1#2{% \edef\skv@tempa{\unexpanded{#2}}% \skv@foreach@normalize[#1]\skv@tempa \def\skv@prova##1{% \skvxifinTF{...}{\detokenize{##1}}{% \if\skv@autocomplete@expandbeforefill \edef\skv@tempa{##1}% \skv@foreach@normalize[#1]\skv@tempa \else \edef\skv@tempa{\unexpanded{##1}}% \fi \skvexpandargonce{\skv@autocompletelist@c{#1}}\skv@tempa \skv@foreach@normalize[#1]\skvcompletedlist }{% \edef\skvcompletedlist{% \skvaddlist{#1}\skvcompletedlist\skvtrimspace{##1}% }% }% }% \expandafter\skv@prova\expandafter{\skv@tempa}% } % \skv@autocompletelist@c{}{} \skvrobustdef*\skv@autocompletelist@c#1#2{% \skvxiffound{\relax...}\in{\relax\detokenize{#2}}\then \skv@err{I can't find lower limit before '...'}\skv@ehd \else \skvxiffound{\relax\detokenize{#1}...}\in{\relax\detokenize{#2}}\then \skv@err{I can't find lower limit before '...'}\skv@ehd \fi \fi % \newforeach format is '...': \skvxifinTF{\detokenize{#1...#1}}{\detokenize{#2}}{% \skv@autocomplete@splitbeforedots{#1}{#2}% \def\skv@prova##1#1##2#1...#1##3#1##4#1##5\skv@nil{% \skvifblankTF{##3}{% \skv@err{I can't find upper limit number or dimension, \MessageBreak i.e., after symbool '...'}\skv@ehd }{% % \skv@autocompletelist@b may be reentered. Hence accumulate % filled list: \skviflacus{##1}\then\else \edef\skvcompletedlist{% \skvaddlist{#1}\skvcompletedlist\unexpanded{##1}% }% \fi % Complete the list: \skv@autocompletelist@d{#1}{##1}{##2}{##3}% % In case the list is folded on ellipsis (...): \skvifblankTF{##4}{}{\skv@autocompletelist@b{#1}{##4#1##5}}% }% }% \expandafter\skv@prova\skv@tempa#1#1\skv@nil }{% \skv@autocompletelist@e{#1}{#2}% }% } % skv@autocompletelist@d{}{}{}{} % % 1. No here. % \skvrobustdef*\skv@autocompletelist@d#1#2#3#4{% \skvifxTF\skv@autocomplete@link\@nnil{% % No has been given. The list has '...' but presumably no link. % % \skv@autocompletelist@h{}{}{}{}{} \skv@autocompletelist@h{#1}{}{#2}{#3}{#4}% }{% % has been given by the user: \skv@autocomplete@splitandgrow{#1}{#2}{#3}{#4}% }% } % % \skv@autocompletelist@e{}{} % % \skv@autocompletelist@e will auto-complete this list without % knowledge of the values of the keys 'link' and 'grow'. The syntax at (*) % above isn't recognized by the auto-completion scheme of skeyval. % % skeyval formats: % % {1pt,4pt,...pt,10pt} : no additional info. required % {A_2pt,A_4pt,A_...,A_10pt} : no additional info. required % {\pi0,\pi0.5,\pi...,\pi3} : no additional info. required % {0\pi,0.5\pi,...\pi,3\pi} : no additional info. required % {1pt,4pt,...,10pt} : link = pt, grow=left, or no addit. info. % {A_2pt,A_4pt,...,A_10pt} : link =_, grow=right % % The general PGF format with left and right guides (given as 'A_' % and 'pt') in % % {A_2pt,A_4pt,A_...pt,A_10pt} % % is still legal in skeyval. % \skvrobustdef*\skv@autocompletelist@e#1#2{% \skv@autocomplete@splitbeforedots{#1}{#2}% \def\skv@checkguideinbounds##1##2{% \skv@foreach@swafalse \def\do####1{% \ifx\do####1\else \skviflacus####1\then\else \skvifinTF{##1}{####1}{}\skv@foreach@swatrue \fi \expandafter\do \fi }% \do##2\do \ifskv@foreach@swa \skv@err{Guide token '\detokenize{#1}' not found in some \MessageBreak of the elements: I can't complete \MessageBreak the current list. This may be \MessageBreak due to wrong direction of growth}\skv@ehd \fi }% \def\skv@prova##1#1##2#1##3...##4#1##5#1##6#1##7\skv@nil{% \skvifblankTF{##5}{% \skv@err{I can't find upper limit number or dimension, \MessageBreak i.e., after symbool '...'}\skv@ehd }{% % \skv@autocompletelist@b may be reentered. Hence \skviflacus{##1}\then\else \edef\skvcompletedlist{% \skvaddlist{#1}\skvcompletedlist \skvtrimspace{##1}% }% \fi \let\do\unexpanded \skvifblankTF{##3}{% \skvifblankTF{##4}{% \skv@err{No direction of growth before and/or after \MessageBreak symbol '...'}\skv@ehd }{% % Eg, {2pt_A,4pt_A,...pt_A,10pt_A}. Here ##3 is nil, grow left. \def\skv@autocomplete@growleft{00}% \def\skv@autocomplete@growright{01}% \skvexpanded{% \skv@autocompletelist@f {\do{#1}}{\do{##4}}{\do{##1}}{\do{##2}}{\do{##5}}% }% }% }{% \skvifblankTF{##4}{% % Eg, {A_2pt,A_4pt,A_...,A_10pt}. Here ##4 is nil, grow right. \def\skv@autocomplete@growright{00}% \def\skv@autocomplete@growleft{01}% \skvexpanded{% \skv@autocompletelist@f {\do{#1}}{\do{##3}}{\do{##1}}{\do{##2}}{\do{##5}}% }% }{% % Eg, {A_2pt,A_4pt,A_...pt,A_10pt}. \skvexpanded{% \skv@autocompletelist@g {\do{#1}}{\do{##3}}{\do{##4}}{\do{##1}}{\do{##2}}{\do{##5}}% }% }% }% % In case the list is folded on ellipsis (...): \skvifblankTF{##6}{}{\skv@autocompletelist@b{#1}{##6#1##7}}% }% }% \expandafter\skv@prova\skv@tempa#1#1#1\skv@nil } % \skv@autocompletelist@f % {}{}{}{}{} % % 1. Use the to get the constant and variable parts of the % elements. % 2. Use the variable parts to determine if the list is Alpah, alpha or % number type. In this format, the unit in dimension type of list may % appear in . % 3. Use the variable parts to work out the . % 4. Call the relevant macro to fill the list. % 5. has already been saved in \skvcompletedlist. % \skvrobustdef*\skv@autocompletelist@f#1#2#3#4#5{% \skv@checkguideinbounds{#2}{{#3}{#4}{#5}}% % Use the 'link' (#2) to get from {}, {} and {} % the left or right sides of the elements that should be grown: \def\skv@prova##1#2##2\skv@nil##3{% \edef##3{\if\skv@autocomplete@growleft##1\else##2\fi}% }% % is empty when there is only one element before ellipsis: \skviflacus#3\then \def\skv@tempa{}% \else \skv@prova#3\skv@nil\skv@tempa \fi \skv@prova#4\skv@nil\skv@tempb \skv@prova#5\skv@nil\skv@tempc \let\do\skvexpandonce \skvexpandsecond {\skv@autocompletelist@h{#1}{#2}}% {{\do\skv@tempa}{\do\skv@tempb}{\do\skv@tempc}}% } % \skv@autocompletelist@g % {}{}{}{}{}{} \skvrobustdef*\skv@autocompletelist@g#1#2#3#4#5#6{% \def\skv@preandpostdotspresent{00}% \skv@checkguideinbounds{#2}{{#4}{#5}{#6}}% \skv@checkguideinbounds{#3}{{#4}{#5}{#6}}% % For , and , get the tokens between % and . They are the ones to be grown. \def\skv@prova##1#2##2#3##3\skv@nil##4{% \edef##4{##2}% }% \ifx\@nnil#4\@nnil \let\skv@tempa\@empty \else \skv@prova#4\skv@nil\skv@tempa \fi \skv@prova#5\skv@nil\skv@tempb \skv@prova#6\skv@nil\skv@tempc % Pass as empty to \skv@autocompletelist@h. Through out, the only % reason for passing to \skv@autocompletelist@h is to restore % it in \skv@autocomplete@restore. But while % \skv@preandpostdotspresent is true, we won't do anything in % \skv@autocomplete@restore. \skvexpandsecond {\skv@autocompletelist@h{#1}{}}% {{\skv@tempa}{\skv@tempb}{\skv@tempc}}% % Restore and : \def\do##1#1{% \ifx\do##1\else \edef\skvcompletedlist{% \skvaddlist{#1}\skvcompletedlist \unexpanded{#2}##1\unexpanded{#3}\skv@autocomplete@origunit }% \expandafter\do \fi }% \expandafter\do\skv@completedlist@partial#1\do#1% } % \skv@autocompletelist@h{}{}{}{}{} % % 1. Use the variable parts to determine if the list is Alpah, alpha or % number type. In this format, the unit in dimension type of list may % appear in . % 2. Use the variable parts to work out the . % 3. Call the relevant macro to fill the list. % 4. has already been saved in \skvcompletedlist. % \skvrobustdef*\skv@autocompletelist@h#1#2#3#4#5{% \def\skv@completedlist@partial{}% \edef\skv@lowerlower{\ifx\@nnil#3\@nnil\else\unexpanded{#3}, \fi}% \skvifloweralpha{#4}{% \skv@foreach@swatrue \ifx\@nnil#3\@nnil\else \skvifloweralpha{#3}{}\skv@foreach@swafalse \fi \skvifloweralpha{#5}{}\skv@foreach@swafalse \ifskv@foreach@swa \ifx\@nnil#3\@nnil \def\skv@autocomplete@step{1}% \else \edef\skv@autocomplete@step{\the\numexpr\lccode`#4-\lccode`#3}% \ifnum\skv@autocomplete@step=\skvz@ \def\skv@autocomplete@step{1}% \skv@autocomplete@zerostepwarn{#3}{#4}{}% \fi \fi \def\skv@isupperalpha{01}% % \skv@autocomplete@origunit remains nil on this branch. \skv@autocomplete@fillalphabetic{#1}{#4}{#5}\skv@completedlist@partial % Also update the items already entered in \skvcompletedlist. \skv@autocomplete@restore{#1}{#2}\skv@completedlist@partial \else \skv@err{The tokens '\detokenize\expandafter{\skv@lowerlower#4, #5}' \MessageBreak aren't of the same type}\skv@ehd \fi }{% \skvifupperalpha{#4}{% \skv@foreach@swatrue \ifx\@nnil#3\@nnil\else \skvifupperalpha{#3}{}\skv@foreach@swafalse \fi \skvifupperalpha{#5}{}\skv@foreach@swafalse \ifskv@foreach@swa \ifx\@nnil#3\@nnil \def\skv@autocomplete@step{1}% \else \edef\skv@autocomplete@step{\the\numexpr\uccode`#4-\uccode`#3}% \ifnum\skv@autocomplete@step=\skvz@ \def\skv@autocomplete@step{1}% \skv@autocomplete@zerostepwarn{#3}{#4}{}% \fi \fi \def\skv@isupperalpha{00}% % \skv@autocomplete@origunit remains nil on this branch. \skv@autocomplete@fillalphabetic{#1}{#4}{#5}\skv@completedlist@partial \skv@autocomplete@restore{#1}{#2}\skv@completedlist@partial \else \skv@err{The tokens '\detokenize\expandafter{\skv@lowerlower#4, #5}' \MessageBreak aren't of the same type}\skv@ehd \fi }{% \skv@foreach@swatrue \ifx\@nnil#3\@nnil\else \skvifdimensionable{#3}{}\skv@foreach@swafalse \fi \skvifdimensionable{#4}{}\skv@foreach@swafalse \let\skv@autocomplete@origunit\skv@dimunit \skvifdimensionable{#5}{}\skv@foreach@swafalse \ifx\skv@autocomplete@origunit\skv@dimunit\else \skv@err{The units on \detokenize{'#4', '#5'} are different}\skv@ehd \fi \ifskv@foreach@swa \ifx\@nnil#3\@nnil \def\skv@autocomplete@step{1pt}% \else \edef\skv@autocomplete@step{\the\dimexpr#4-#3\relax}% \ifdim\skv@autocomplete@step=\skvz@ \def\skv@autocomplete@step{1pt}% \skv@autocomplete@zerostepwarn{#3}{#4}{pt}% \fi \fi \skvexpandsecond {\skv@autocomplete@fillnumordim{#1}}{{#4}{#5}}% \skv@completedlist@partial \skv@autocomplete@strippoint{#1}\skv@completedlist@partial % Attach the constant part to the elements of the completed list. % was saved earlier in \skv@autocompletelist@e, and % and have been saved while filling the list. % Always strip point and restore original unit here. \skv@autocomplete@restore{#1}{#2}\skv@completedlist@partial \else \skv@foreach@swatrue \ifx\@nnil#3\@nnil\else \skvifdimensionable{#3pt}{}\skv@foreach@swafalse \fi \skvifdimensionable{#4pt}{}\skv@foreach@swafalse \skvifdimensionable{#5pt}{}\skv@foreach@swafalse \ifskv@foreach@swa \ifx\@nnil#3\@nnil \def\skv@autocomplete@step{1pt}% \else \edef\skv@autocomplete@step{\the\dimexpr#4pt-#3pt\relax}% \ifdim\skv@autocomplete@step=\skvz@ \def\skv@autocomplete@step{1pt}% \skv@autocomplete@zerostepwarn{#3}{#4}{pt}% \fi \fi % \skv@autocomplete@origunit remains nil on this branch. \skvexpandsecondonce {\skv@autocomplete@fillnumordim{#1}}{{#4pt}{#5pt}}% \skv@completedlist@partial \skv@autocomplete@strippoint{#1}\skv@completedlist@partial \skv@autocomplete@restore{#1}{#2}\skv@completedlist@partial \else \skv@err{Sorry, the tokens '\detokenize\expandafter{\skv@lowerlower#4, #5}' \MessageBreak are unparsable. I have given up on them. \MessageBreak Did you miss something syntactic? \MessageBreak See manual for acceptable syntaxes}\skv@ehd \fi \fi }% }% } % \skv@autocomplete@fillnumordim \skvrobustdef*\skv@autocomplete@fillnumordim#1#2#3#4{% \begingroup \skv@autocomplete@getcomparator \if\skv@autocomplete@stepisneg \ifdim#3\skv@autocomplete@unit>#2\skv@autocomplete@unit\relax \skv@err{Step '\skv@autocomplete@step' is negative but upperbound \MessageBreak '\detokenize{#3}' is greater than lowerbound '\detokenize{#2}'}\skv@ehd \fi \else \ifdim#3\skv@autocomplete@unit<#2\skv@autocomplete@unit\relax \skv@err{Step '\skv@autocomplete@step' is nonnegative but upperbound \MessageBreak '\detokenize{#3}' is less than lowerbound '\detokenize{#2}'}\skv@ehd \fi \fi % The bounds may have decimal places. So the calculation has to be % done with \dimexpr: \edef\skv@upperlimit{\the\dimexpr#3\skv@autocomplete@unit}% \edef\skv@lowerlimit{\the\dimexpr#2\skv@autocomplete@unit}% \skv@autocomplete@addtolist{#1}\skv@lowerlimit#4% \ifdim\skv@lowerlimit\skv@comparator\skv@upperlimit\relax \def\do{% \edef\skv@lowerlimit{% \the\dimexpr\skv@lowerlimit +\skv@autocomplete@step\skv@autocomplete@unit\relax }% \ifdim\skv@lowerlimit\skv@comparator\skv@upperlimit\relax \skv@autocomplete@addtolist{#1}\skv@lowerlimit#4% \expandafter\do \fi }% \do % The last item has to in 'pt', so that 'pt' can be stripped. % Hence \dimexpr. \skv@autocomplete@addtolist{#1}\skv@upperlimit#4% \fi \skvaftergroupdef#4\endgroup } % Fill Alpha or alpha. % \skv@autocomplete@fillalphabetic \skvrobustdef*\skv@autocomplete@fillalphabetic#1#2#3#4{% \begingroup \def\skv@inalphabetic{00}% \skv@autocomplete@getcomparator \edef\skv@type{% \if\skv@isupperalpha Upper\else Lower\fi case alphabetic% }% \edef\reserved@a{\if-\skv@autocomplete@step\else\skv@autocomplete@step\fi}% \skvoifinteger\reserved@a{}{% \skv@err{List is '\skv@type' type but\MessageBreak step '\skv@autocomplete@step' isn't an integer}\skv@ehd }% \skv@autocomplete@addtolist{#1}{#2}#4% \skvifstrcmpTF{#2}{#3}{}{% \edef\skv@lowerlimit{#2}% \edef\skv@upperlimit{#3}% \skvexpandnext{\chardef\skv@lowerlimit`}\skv@lowerlimit\relax \skvexpandnext{\chardef\skv@upperlimit`}\skv@upperlimit\relax \edef\skv@lowerlimit{% \the\numexpr\skv@lowerlimit-\if\skv@isupperalpha 64\else 96\fi }% \edef\skv@upperlimit{% \the\numexpr\skv@upperlimit-\if\skv@isupperalpha 64\else 96\fi }% \edef\skv@charcase{\the\numexpr\skv@lowerlimit+\skv@autocomplete@step}% \skvrecurse \if\skv@isupperalpha \edef\skv@tempa{\skv@ucalpha\skv@charcase}% \else \edef\skv@tempa{\skv@lcalpha\skv@charcase}% \fi \skv@autocomplete@addtolist{#1}\skv@tempa#4% \edef\skv@charcase{\the\numexpr\skv@charcase+\skv@autocomplete@step}% \while \ifnum\skv@charcase\skv@comparator\skv@upperlimit\relax \fi \skv@autocomplete@addtolist{#1}{#3}#4% }% \skvaftergroupdef#4\endgroup } % % \skv@autocomplete@splitbeforedots{}{} % % Get the one or two elements before '...' or before ',...'. % % {A_2pt,A_4pt,A_...pt,A_10pt} : no additional info. required % {a^1,a^3,a^...,a^9} : no additional info. required % {A_1,B_1,..._1,E_1} : no additional info. required % {1--,4--,...--,16--} : no additional info. required % {1pt,4pt,...pt,10pt} : no additional info. required % {A_2pt,A_4pt,A_...,A_10pt} : no additional info. required % % {a^1,a^3,...,a^9} : link = ^, grow = right % {A_1,B_1,...,E_1} : link = _, grow = left % {1--,4--,...,16--} : link = --, grow = left % {1pt,4pt,...,10pt} : link = pt, grow = left, or no addit. info. % {A_2pt,A_4pt,...,A_10pt} : link = _, grow = right % % The items prior to the two before '...' or before '...' % are called 'all-before-the-two' (AB2). Collect in \skv@tempa the two % items before '...' or before '...' together with the rest of the % list. Save the AB2 items in \skvcompletedlist. % % Return \skvcompletedlist and \skv@tempa. % \skvrobustdef*\skv@autocomplete@splitbeforedots#1#2{% % First count all the elements before '...' or '...'. % We're already sure that argument #2 contains '...' % or '...'. \skvcompletedlist has been initialized before here. \begingroup \skv@cnta\skvz@ \def\do##1#1{% \skvifinTF{...}{##1}{% % Gobble the rest: \def\do####1\skv@nil{}% }{% \advance\skv@cnta\@ne }% \do }% \do#2#1\skv@nil \ifnum\skv@cnta>\tw@ \@tempcnta\m@ne \def\do##1#1{% \advance\@tempcnta\@ne \ifnum\@tempcnta=\numexpr\skv@cnta-\tw@\relax \def\do####1\skv@nil{\def\skv@tempa{##1#1####1}}% \else \edef\skvcompletedlist{% \skvaddlist{#1}\skvcompletedlist\unexpanded{##1}% }% \fi \do }% \do#2#1\skv@nil \else \ifnum\skv@cnta=\@ne % There is only one element before '...' or '...'. % Hence simply left-pad argument #2 with to give the % impression of at least 2 elements: \def\skv@tempa{#1#2}% \else \ifnum\skv@cnta=\tw@ \def\skv@tempa{#2}% \else \ifnum\skv@cnta=\skvz@ \skv@err{List <<\detokenize{#2}>>\MessageBreak contains symbol '...' but not a lowerbound}\skv@ehd \fi \fi \fi \fi \skvexpanded{\endgroup \skvcmdexit\skvcompletedlist\skvcmdexit\skv@tempa }% } % \skv@autocomplete@splitandgrow{}{}{}{} % % {0\pi,0.5\pi,...,3\pi} : link = \pi ; grow left % {1--,4--,...,10--} : link = -- ; grow left % {2pt,4pt,...,10pt} : link = pt ; grow left (or no additional info.) % {A_1,C_1,...,Q_1} : link = _ ; grow left % {2^a,2^c,...,2^q} : link = ^ ; grow right % % 1. Providing the link avoids the need to use the syntax of PGF's % \foreach, such as {0\pi,0.5\pi,...\pi,3\pi}. But skeyval can also % autocomplete lists like {0\pi,0.5\pi,...\pi,3\pi}. % 2. We already know that the key 'link' will reject empty values. % \skvrobustdef*\skv@autocomplete@splitandgrow#1#2#3#4{% \ifx\skv@autocomplete@growleft\skv@autocomplete@growright \skv@err{I can't grow the list in both directions. \MessageBreak Maybe you haven't indicated the \MessageBreak direction of growth (left or right), \MessageBreak or both directions are 'true'.} {Try one of the keys 'grow=left or right', \MessageBreak 'grow left=true or false', 'grow right=true or false'}\skv@ehd \fi \begingroup \def\skv@prova##1{% \skv@foreach@swatrue \skviflacus#2\then\else \skvifinTF{##1}{#2}{}\skv@foreach@swafalse \fi \skvifinTF{##1}{#3}{}\skv@foreach@swafalse \skvifinTF{##1}{#4}{}\skv@foreach@swafalse \ifskv@foreach@swa\else \edef\skv@provb{\ifx\@nnil#2\@nnil\else\unexpanded{#2}, \fi}% \skv@err{No link '##1' in one of '\detokenize\expandafter{\skv@provb#3, #4}'}\skv@ehd \fi \def\skv@prova####1##1####2\skv@nil{% \if\skv@autocomplete@growright \edef\skv@prova{\skvtrimspace{####1##1}}% \else \edef\skv@prova{\skvtrimspace{##1####2}}% \fi \def\do########1{{\skvtrimspace{########1}}}% % \skv@autocompletelist@f \skvexpanded{\endgroup \noexpand\skv@autocompletelist@f {\unexpanded{#1}}{\skvexpandonce\skv@prova}\do{#2}\do{#3}\do{#4}% }% }% \skv@prova#3\skv@nil }% \expandafter\skv@prova\expandafter{\skv@autocomplete@link}% } \skvrobustdef*\skv@autocomplete@getcomparator{% \begingroup % isn't required in alphabetic sequences: \if\skv@inalphabetic\else \let\skvreversedo\@iden \edef\skv@provb{\skvexpbracenext\skvreverse\skv@autocomplete@step}% \def\skv@prova##1##2##3\skv@nil{% \skvxifinTF{,\detokenize{##2##1},}{,\skvoxdetok\skv@validunit,}{% % That is, the sequence is made up of dimensions. \def\skv@autocomplete@unit{}% }{% \def\skv@autocomplete@unit{pt}% }% }% \expandafter\skv@prova\skv@provb\skv@nil \fi % You can't use \ifnum or \ifdim here, since for alphanumeric sequences % \skv@autocomplete@step isn't a dimension. \def\skv@prova##1##2\skv@nil{% \edef\skv@autocomplete@stepisneg{0\if-##10\else1\fi}% }% \expandafter\skv@prova\skv@autocomplete@step\skv@nil \edef\skv@comparator{\if\skv@autocomplete@stepisneg>\else<\fi}% \let\do\skvcmdexit \skvexpanded{\endgroup \do\skv@autocomplete@stepisneg\do\skv@comparator \if\skv@inalphabetic\else\do\skv@autocomplete@unit\fi }% } \begingroup \catcode`P=12 \lccode`P=112 \catcode`T=12 \lccode`T=116 \lowercase{\endgroup \def\skv@autocomplete@strippoint#1#2{% \def\reserved@a##1#1\relax{\def#2{##1}}% \def\do##1.##2PT#1{% \ifx\do##1\else##1% \if\skv@autocomplete@keephighdecimals \ifdim.##2pt>.5pt\relax##2\fi \else \if\skv@autocomplete@keepdecimals \ifnum##2>\skvz@.##2\fi \fi \fi \unexpanded{#1}% \expandafter\do \fi }% \edef#2{\expandafter\do#2#1\do.PT#1}% \expandafter\reserved@a#2\relax } } % \skv@autocomplete@restore{}{}{} % % Restore guide and, in the case of dimension sequences, 'original unit'. % \skvrobustdef*\skv@autocomplete@restore#1#2#3{% \if\skv@preandpostdotspresent % Leave it: and will be restored in % \skv@autocompletelist@g. \else \def\do##1#1{% \ifx\do##1\else \edef\skvcompletedlist{% \skvaddlist{#1}\skvcompletedlist \if\skv@autocomplete@growleft ##1\skv@autocomplete@origunit\unexpanded{#2}% \else \unexpanded{#2}##1\skv@autocomplete@origunit \fi }% \expandafter\do \fi }% \expandafter\do#3#1\do#1% \fi } \skv@for@restorecatcodes \endinput