diff options
author | Karl Berry <karl@freefriends.org> | 2013-02-12 23:53:37 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2013-02-12 23:53:37 +0000 |
commit | b00ddd78e03236a73df3113f75cb0c607654d5a6 (patch) | |
tree | abe63d734ede6c61983c4e8ebb8175859651b1ad /Master/texmf-dist | |
parent | dcf4eb75b6ae8a7d1ebab1fc40af55709bfd8139 (diff) |
loops (12feb13)
git-svn-id: svn://tug.org/texlive/trunk@29090 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
-rw-r--r-- | Master/texmf-dist/doc/latex/loops/README | 153 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/loops/loops.sty | 678 |
2 files changed, 479 insertions, 352 deletions
diff --git a/Master/texmf-dist/doc/latex/loops/README b/Master/texmf-dist/doc/latex/loops/README index 955e90f4994..61eb1c82929 100644 --- a/Master/texmf-dist/doc/latex/loops/README +++ b/Master/texmf-dist/doc/latex/loops/README @@ -6,7 +6,7 @@ Ahmed Musa VERSION -Version 1.1, 2012/10/16. +Version 1.2, 2013/02/10. LOCATION ON CTAN @@ -14,7 +14,7 @@ macros/latex/contrib/loops/ LICENSE -Copyright (c) 2012 Ahmed Musa +Copyright (c) 2012-2013 Ahmed Musa This software is author-maintained. Permission is granted to copy, distribute and/or modify this software under the terms of the @@ -27,7 +27,7 @@ NOTE Non-LaTeX users can use the \newforeach macro (and some other looping macros) by loading the file skeyval-for.tex. These exclude -\foxloop or \foreachfox, which are available only in loops.sty. +\foreachfox, which are available only in loops.sty. SUMMARY @@ -308,15 +308,17 @@ The looping macros include: parameters/quantities. There is a long list of options/keys in <options>, available for - \newforeach and \foxloop or \foreachfox. For example, key 'reverse list' + \newforeach and \foreachfox. For example, key 'reverse list' allows users to automatically reverse their lists prior to processing. Also, there are many internal macros that can be accessed by the user. A few of them are - \interruptforeach, \foreachcurrentitem, \foreachnextitem, - \foreachitemcount, \foreachprevitem, \prependtobeginforeach, - \appendtobeginforeach, \prependtoendforeach, \appendtoendforeach, + \breaknewforeach (=\skvbreakloop), + \breakallforeachloops, \foreachcurrentitem, + \foreachnextitem, \foreachitemcount, \foreachprevitem, + \prependtobeginforeach, \appendtobeginforeach (=\atbeginforeach), + \prependtoendforeach, \appendtoendforeach (=\atendforeach), \ifforeachlastitem, \foreachnestdepth, \foreachlistremainder, \skvforeachonlyinitially. @@ -325,11 +327,11 @@ The looping macros include: number of items processed on each depth of nesting of \newforeach. On any depth, the user can say, eg, - \ifnum\foreachitemcount>10\relax\interruptforeach\fi + \ifnum\foreachitemcount>10\relax\breaknewforeach\fi or - \ifnum\foreachitemcount>10\relax\interruptloop\fi + \ifnum\foreachitemcount>10\relax\breaknewforeach\fi You can insert \listbreaker as an item in <list> or <listcmd> to terminate the list prematurely. \listpauser will pause @@ -340,8 +342,7 @@ The looping macros include: outcome-from-pgfs-foreach>. However, \newforeach itself can't be said to be bug free. - Maybe you fancy the following syntactic sugar, which PGF's - \foreach can't presently process: + Maybe you fancy the following syntactic sugar: \begingroup \catcode`\,=13 @@ -369,6 +370,25 @@ The looping macros include: \end{tikzpicture} \show\xc + \begin{document} + \begin{tikzpicture}[every node/.style=draw] + \node (A) at (0,0) {A}; + \node (B) at (1,0) {B}; + \node (C) at (2,0) {C}; + \node (D) at (3,0) {D}; + \newforeach \n [remember=\n as \lastn initially A] in {B,C,D} + \draw [->] (\lastn) -- (\n); + \end{tikzpicture} + + \foreachfox [remember=#1 as \x initially A] in {B,...,H} {% + $\overrightarrow{\x#1}$\ifforeachlastitem.\else,\space\fi + } + + \foreachfox [list type=tsv,remember=#1 as \x initially A] {B(C1)DE[F1]GH} {% + $\overrightarrow{\x#1}$\ifforeachlastitem.\else,\space\fi + } + \end{document} + % Example credit: Tom Bombadil \usetikzlibrary{arrows} \parindent-40pt @@ -398,25 +418,47 @@ The looping macros include: need to manually expand the holder macros \x,\y,\z in the callbacks, as I have seen some TikZ users do. - Here is an example that uses parameters: + Here is an example that uses parameters. + + \newforeach will not accept \skvifstreq or \skvifstrcmpTF because + they don't start with '\if'. So skeyval package cast \skvifstreq to + \ifforeachstrcmp. + + Normally, breaking an inner loop doesn't affect the continuation of + outer loops, but \breakallforeachloops will break all current inner + and outer loops. \newforeach \x [ item counter = \xc, - exit when = \ifskvstreq#1\with b\then\fi, + exit when = \ifforeachstrcmp{#1}{b}\then\fi ] in {a,b,c} do {% \newforeach [ count in = \yc all \y satisfying \ifnum\y>2\fi, loop stopper = \ifnum\y>3\fi ] \y in {1,2,3,4,5} {% - \skvcsdef{#1##1}{Items: #1, ##1}% + \typeout{Doing items: #1, ##1}% + %\ifnum\y=3 \breakallforeachloops\fi }% } \begin{document} Numbers: {\tt\string\xc}: \xc, {\tt\string\yc}: \yc - \par\skvcsuse{a1} - \par\skvcsuse{e10} \end{document} + Because of 'continue={\ifnum\y=3\fi}' item number 3 will not appear + in the log file from the following loop: + + \newforeach [ + item counter = \xc, + exit when = \ifforeachstrcmp{#1}{c}\then\fi + ] \x in {a,...,e} do {% + \newforeach \y [ + count in = \yc all \y satisfying \ifnum\y>2\fi, + continue = {\ifnum\y=3\fi} + ] in {1,...,10} {% + \typeout{Doing items: #1, ##1}% + % \ifnum\y=5 \breakallforeachloops\fi + }% + } \begin{document} \begin{tikzpicture}[scale=2] @@ -435,7 +477,7 @@ The looping macros include: \end{document} - % A complete graph + % A complete graph. % Example credit: % Quintin Jean-Noël % <http://moais.imag.fr/membres/jean-noel.quintin/> @@ -466,60 +508,60 @@ The looping macros include: \end{tikzpicture} -\foxloop or \foreachfox: +\foreachfox: - \foxloop[<options>]{<list>}{<parametered.callback>} - \foxloop*[<options>]{<listcmd>}{<parametered.callback>} + \foreachfox[<options>]{<list>}{<parametered.callback>} + \foreachfox*[<options>]{<listcmd>}{<parametered.callback>} - \foxloop does everything that \newforeach does, but, in addition, - it can process nsv/tsv (non-separated, tokenwise, lists). It can + \foreachfox does everything that \newforeach does, but, in addition, + it can process nsv/tsv (non-separated, tokenwise lists). It can auto-complete ellipsis lists (ie, lists with '...'), but this feature is available only for csv lists and not for tsv lists. - 1. One important characteristic of \foxloop is that it doesn't use + 1. One important characteristic of \foreachfox is that it doesn't use holder macros (eg, \x/\y), but instead it uses parameter characters directly. So it doesn't accept/expect holder macros. 2. That means that if the argument isn't simple (ie, if it isn't #1), then it has to be specified as the value of the key/option 'arg' (eg, arg=#1/#2). - 3. Note that \foxloop doesn't expect any optional 'in' or 'do' in the + 3. Note that \foreachfox doesn't expect any optional 'in' or 'do' in the argument list. - 4. Unlike \newforeach, \foxloop doesn't recognize the semicolon - (;) as a callback terminator. In fact, the callback for \foxloop + 4. Unlike \newforeach, \foreachfox doesn't recognize the semicolon + (;) as a callback terminator. In fact, the callback for \foreachfox should ideally be always enclosed in balanced braces. PGF often uses the semicolon as the callback terminator. \newforeach supports that feature. The following macros are available to the user: - \breakfoxloop, \interruptloop, \foxloopdepth, \foxcount, - \previousfox, \currentfox, \nextfox, \iflastfox, - \foxlistremainder, \prependtobeginfoxloop, \appendtobeginfoxloop, - \prependtoendfoxloop, \appendtoendfoxloop. + \breakforeachfox, \foreachnestdepth, \foreachitemcount, \foreachprevitem, + \foreachcurrentitem, \foreachnextitem, \ifforeachlastitem, \foreachlistremainder, + \prependtobeginforeach, \appendtobeginforeach (=\atbeginforeachfox), + \prependtoendforeach, \appendtoendforeach (=\atendforeachfox). Examples: - \foxloop [ + \foreachfox [ remember=#1 as \x initially A ] {B,...,H} {% - $\overrightarrow{\x#1}$\iflastfox.\else,\space\fi + $\overrightarrow{\x#1}$\ifforeachlastitem.\else,\space\fi } This is equivalent to: - \foxloop [ + \foreachfox [ list type=tsv, remember=#1 as \x initially A - ] {BCDEFGH} {% - $\overrightarrow{\x#1}$\iflastfox.\else,\space\fi + ] in {BCDEFGH} {% + $\overrightarrow{\x#1}$\ifforeachlastitem.\else,\space\fi } \usepackage{multicol} \begin{document} \begin{multicols}{2} - \foxloop [count=\nchar] {a,...,f} { - \foxloop [ + \foreachfox [count=\nchar] {a,...,f} { + \foreachfox [ evaluate=##1 as \xe using \numexpr##1*20, evaluate=##1 as \hx using \pgfmathparse{##1 mm*5}, evaluate=##1 as \vx using \pgfmathparse{##1 mm*1.5}, @@ -556,7 +598,7 @@ The looping macros include: \node at (0,0) {% \let\do\global \do\DimWD\z@\do\DimHT\z@\do\DimDP\z@ - \foxloop* [arg=##1/##2,parser={#1}] #2 {% + \foreachfox* [arg=##1/##2,parser={#1}] #2 {% \sbox0{#3}% \ifdim\wd0>\DimWD\global\DimWD=\wd0\fi \ifdim\ht0>\DimHT\global\DimHT=\ht0\fi @@ -570,16 +612,45 @@ The looping macros include: \def\bluelist{a/b,b/c,c/d,d/e,e/f,f/g,g/h,h/a} \begin{tikzpicture}[scale=1.2,auto=left,every node/.style={circle,thick}] \DimMeasure{;}{\yellowlist}{#1} - \foxloop* [arg=#1/#2,parser={;},count=\xc] \yellowlist { + \foreachfox* [arg=#1/#2,parser={;},count=\xc] \yellowlist { \node (#1) at (#2) [fill=blue!20,draw=yellow] {\DimBox{#1}}; } \DimMeasure{,}{\bluelist}{#1--#2} - \foxloop* [arg=#1/#2] \bluelist { + \foreachfox* [arg=#1/#2] \bluelist { \draw [->] (#1) -- (#2) node [midway,fill=red!20,draw=blue]{\DimBox{#1--#2}}; } \end{tikzpicture} \end{document} + \foreachfox [ + item counter = \xc, + exit when = \ifforeachstrcmp{#1}{c}\then\fi + ] {a,b,c,d} {% + \foreachfox [ + count in = \yc all ##1 satisfying \ifnum##1>2\fi, + ignore callback = {\ifnum##1=3\fi} + ] {1,...,10} {% + \typeout{Doing items: #1, ##1}% + \ifnum##1=8 \breakforeachfox\fi + }% + } + %\show\xc + \show\yc + +* Unfortunately, for drawing instructions like + + \draw[blue] (p) \newforeach \p in {1,...,8}{...}; + + (ie, when \draw precedes \newforeach), both \newforeach and \foreachfox + will not work, because of the way TikZ hardwires \foreach for this type + of task. The tack that loops package resorts to in this situation is + simply to replace \newforeach and \foreachfox with \foreach. The fact + here is that in this case, both \newforeach and \foreachfox will not work + but leave everything for \foreach. This can be a problem when \newforeach + or \foreachfox is called to avoid a known bug in \foreach, such as at + + <http://tex.stackexchange.com/questions/79586/foreach-has-a-% + problem-with-initially-argument-in-remember-part/79644#79644> -% End of readme file of loops.sty
\ No newline at end of file +% End of readme file of loops package diff --git a/Master/texmf-dist/tex/latex/loops/loops.sty b/Master/texmf-dist/tex/latex/loops/loops.sty index 351205fdd4e..bd11a44a18f 100644 --- a/Master/texmf-dist/tex/latex/loops/loops.sty +++ b/Master/texmf-dist/tex/latex/loops/loops.sty @@ -1,5 +1,5 @@ %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% -% This is file 'loops.sty', version 1.1, 2012/10/16. % +% This is file 'loops.sty', version 1.2, 2013/02/10. % % % % This package and accompanying files may be distributed and/or % % modified under the conditions of the LaTeX Project Public License, % @@ -15,7 +15,7 @@ % implied warranties of merchantability and fitness for a particular % % purpose. % % % -% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). % +% Copyright (c) 2012-2013 Ahmed Musa (amusa22@gmail.com). % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \begingroup @@ -53,7 +53,7 @@ \do 032=10,033=12,036=03,038=04,040=12,041=12,042=12,043=12,% 059=12,045=12,047=12,058=12,063=12,091=12,093=12,126=13,\do=,% -\ProvidesPackage{loops}[2012/10/16 v1.1 Loops and list processors (AM)] +\ProvidesPackage{loops}[2013/02/10 v1.2 Loops and list processors (AM)] \NeedsTeXFormat{LaTeX2e}[2011/06/27] % This is the way to load 'skeyval-for-core' here, otherwise we @@ -66,45 +66,81 @@ \directkeys*{ .every unknown option={ - \PackageWarning{loops}{Unknown option '\CurrentOption' ignored}% + \@onelevel@sanitize\CurrentOption + \PackageWarning{loops}{Unknown option '\CurrentOption' ignored} }, - .prefix=SKV, - .family=loops, + .path=SKV/loops, .holder prefix=lps@, .initialize keys after define, .new options={ .bool/verbose/true/\iflps@verbose\skv@verbosetrue\fi, }, - .copy class options and process options, + .copy class options and process options } -% \skvusetwoprev{<parser>}{<list>}{<target.item>}{<do.on.target>} -% -% Example: -% -% \skvusetwoprev{,}{a,b,c,d,e,f}{e}{} -% -\skvrobustdef*\skvusetwoprev#1#2#3#4{% - \skvifinTF{#1#3#1}{#1#2#1}{}{% - \skv@err{There is not '\detokenize{#3}' in the list}\@ehd +% \lpsdocsvlist{<parser>}{<list>}{<callback>} +% +% Execute <callback> on each item of <list>. The user has access to +% \firstprevitem, \secondprevitem, \currentitem, \firstnextitem, +% \secondnextitem (some of which may be empty), and \iflpslastitem. +% +% Examples: +% +% \def\aitems{} +% \lpsdocsvlist{,}{a,b,c,d,e,f}{% +% \def\do##1{\ifx##1\@empty\let##1\@gobble\fi}% +% \do\secondprevitem\do\firstprevitem\do\firstnextitem +% \edef\aitems{% +% \skvexpandonce\aitems\ifx\aitems\@empty\else,\fi +% \secondprevitem,\firstprevitem,\currentitem,% +% \firstnextitem,\secondnextitem +% }% +% } +% +\skvnewregister\bool{\iflpslastitem} +\skvnewlet\lpsbreakloop\skvbreaklooptrue +\skvrobustdef*\lpsdocsvlist#1#2#3{% + \skvpushfunctions\lpsdocsvlist{% + \do\lpsuserlist\do\firstprevitem\do\secondprevitem\do\currentitem + \do\firstnextitem\do\secondnextitem\do\lps@do\do\skv@callback + }\skv@csvdepth + \let\firstprevitem\@empty + \let\secondprevitem\@empty + \edef\lpsuserlist{\unexpanded{#2}}% + \edef\skv@callback{\unexpanded{#3}}% + \skvcsvnormalize[#1]\lpsuserlist + \def\lps@do##1#1##2#1##3#1{% + \edef\currentitem{\unexpanded{##1}}% + \skvifxTF\currentitem\skv@nnil{% + \skvbreakloopfalse + }{% + \skvifdefboolTF{skvbreakloop}{% + \skvbreakloopfalse + \def\lps@do####1\skv@nil#1\skv@nil#1\skv@nil#1{% + \edef\lpsremainder{\unexpanded{####1}}% + }% + }{% + \edef\firstnextitem{\unexpanded{##2}}% + \ifx\firstnextitem\skv@nnil + \lpslastitemtrue + \let\firstnextitem\@empty + \fi + \edef\secondnextitem{\unexpanded{##3}}% + \ifx\secondnextitem\skv@nnil + \let\secondnextitem\@empty + \fi + \lps@callback\relax + \let\secondprevitem\firstprevitem + \let\firstprevitem\currentitem + }% + \lps@do##2#1##3#1% + }% }% - \let\firstprev\@empty - \let\secondprev\@empty - \def\skv@tempa{#3}% - \def\skv@do##1#1{% - \ifx\skv@nnil##1\else - \def\current{##1}% - \ifx\current\skv@tempa - #4\relax - \def\skv@do####1\skv@nnil#1{}% - \else - \let\secondprev\firstprev - \let\firstprev\current - \fi - \expandafter\skv@do - \fi + \skvbreakloopfalse + \skvifemptyTF\lpsuserlist{}{% + \expandafter\lps@do\lpsuserlist#1\skv@nil#1\skv@nil#1\skv@nil#1% }% - \skv@do#2#1\skv@nnil#1% + \skvpopfunctions\lpsdocsvlist\skv@csvdepth } % Remove one element from a list. Only the first occurence of the @@ -112,7 +148,10 @@ % % \lpsremovefromlist<parser>{<element to remove>}<listcmd> % -% Eg, \def\x{1,2,3,4} \lpsremovefromlist{,}7\x +% Example: +% +% \def\x{1,2,3,4} +% \lpsremovefromlist{,}7\x % \skvrobustdef\lpsremovefromlist#1#2#3{% \begingroup @@ -180,7 +219,7 @@ % \if... % \repeat % -\skvnewregister\toks\skv@aktertoks +\skvnewregister\toks{\skv@aktertoks} \skvnewdef*\skv@aktercnt{0} \skvrobustdef*\skv@akter@defloop{% \def\skv@tempa##1##2##3{% @@ -236,7 +275,7 @@ }% }{% \skvifstrcmpTF{#1}{EOF}{% - \skv@err{'\string\repeat' not found: endless loop}\@ehd + \skv@err{'\string\repeat' not found: endless loop}\skv@ehd }{% \skvifxTF\next\@sptoken{% \skv@aktertoks\expandafter @@ -252,17 +291,17 @@ % Expandable comma loop. List is not normalized prior to parsing, and % it is not possible to terminate the loop prematurely. % -% \skvfor{<list>}<callback.macro> +% \lpsfor{<list>}<callback.macro> % % Example: % -% \skvnewregister\count\nr\nr=\tw@ +% \skvnewregister\count{\nr}\nr=\tw@ % \def\do#1{% % \let\noexpand#1% % \expandafter\noexpand\csname\skvremovescape{#1}@% % \romannumeral\nr\endcsname % } -% \edef\x{\skvfor{\cmda,\cmdb}\do} +% \edef\x{\lpsfor{\cmda,\cmdb}\do} % \show\x -> \let\cmda\cmda@ii \let\cmdb\cmdb@ii % \skvnewdef\skvfor#1#2{\skv@for@a{#2}#1,\skv@for@nil,} @@ -273,8 +312,9 @@ \skvifstrcmpTF{#2}\skv@for@nil{}{#1{#2}\skv@for@a{#1}}% }% } - -% Process non-separated (token-wise) list: +\skvnewlet\lpsfor\skvfor +% Process non-separated (token-wise) list. \ayeloop is like \skvtfor +% but uses parameter characters directly, instead of a holder macro. % % \ayeloop{<list>}\do{<1.parameter.callback>} % \ayeloop*{<listcmd>}\do{<1.parameter.callback>} @@ -288,9 +328,6 @@ % }% % }% % -% \ayeloop is like \skvtfor but uses parameter characters directly, -% instead of a holder macro. -% \skvrobustdef*\ayeloop{\skv@testst\skv@ayeloop} \skvrobustdef*\skv@ayeloop#1\do#2{% \skv@usetempst{#1}\skv@tempa @@ -317,7 +354,7 @@ } % Robust, outer-brace-preserving, multi-level, general-purpose -% non-separated values list (nsv) processor. +% non-separated values list (nsv/tsv) processor. % % \sifakaloop{<list>}{<1.parameter.callback>} % \sifakaloop*{<listcmd>}{<1.parameter.callback>} @@ -385,20 +422,20 @@ }% } -% Processing both csv and tsv/nsv lists with \foxloop. +% Processing both csv and tsv/nsv lists with \foreachfox. % -% \foxloop[<options>]{<list>}{<parametered.callback>} -% \foxloop*[<options>]{<listcmd>}{<parametered.callback>} +% \foreachfox[<options>]{<list>}{<parametered.callback>} +% \foreachfox*[<options>]{<listcmd>}{<parametered.callback>} % % 1. The <callback> is at least a one-parameter token list. % -% 2. \breakfoxloop can be used to break out of the loop. +% 2. \breakforeachfox can be used to break out of the current nest loop. +% \breakallforeachloops can be used to break out of all current loops. % % 3. When the argument is more than one (say, #1#2), the last one % must be delimited by the user-suggested <arg delimiter>. % -% 4. To permit nesting we use a stack involving the counter \foreachdepth, -% with alias \foxloopdepth. +% 4. To permit nesting we use a stack involving the counter \foreachnestdepth. % % 5. \subcallback is meant for callbacks with hash characters that may be % confused with the parameters of the main <callback>. It can be defined @@ -406,41 +443,37 @@ % % 6. Outer braces around the list items are preserved in the parsing. % -% 7. 'fox' is used here to represent an item. Eg, \currentfox, \nextfox, -% \foxcount. -% -\skvnewdef*\skv@foxloop@nnil{\skv@foxloop@nil} -\skvnewbools{lastfox} -\skvnewlet\breakfoxloop\skvbreaklooptrue -\skvnewdef*\foxloopdepth{\foreachdepth} -\skvnewdef*\foxcount{\foreachitemcount} -\skvnewdef*\currentfox{\foreachcurrentitem} -\skvnewdef*\nextfox{\foreachnextitem} -\skvnewdef*\previousfox{\foreachprevitem} -\skvnewdef*\foxlistremainder{\foreachlistremainder} -\skvnewdef*\prependtobeginfoxloop{\prependtobeginforeach} -\skvnewdef*\appendtobeginfoxloop{\appendtobeginforeach} -\skvnewdef*\prependtoendfoxloop{\prependtoendforeach} -\skvnewdef*\appendtoendfoxloop{\appendtoendforeach} +% 7. The following are available here, as in \newforeach: +% +% \foreachcurrentitem, \foreachnextitem, \foreachitemcount, +% \foreachcurrentitem, \foreachnextitem, \foreachitemcount, +% \foreachprevitem, \prependtobeginforeach, \appendtobeginforeach +% (=\atbeginforeach), \prependtoendforeach, \appendtoendforeach +% (=\atendforeach), \ifforeachlastitem, \foreachnestdepth, +% \foreachlistremainder, \skvforeachonlyinitially. +% +\skvnewregisters\bool{\iflastfox} +\skvnewlet\breakforeachfox\skvbreaklooptrue +% \atbeginforeachfox[<depth>]{<code>} +\skvnewlet\atbeginforeachfox\atbeginforeach +% \atendforeachfox[<depth>]{<code>} +\skvnewlet\atendforeachfox\atendforeach -% Define \foxloop keys. Name all the macros with 'foreach' prefix so +% Define \foreachfox keys. Name all the macros with 'foreach' prefix so % that we can avoid new command names and use the list auto-completion % scheme of \newforeach. -\quickkeys.define{loops/foxloop}{% +\quickkeys.define{loops/foreachfox}{% parser/{,}/ \def\skv@foreach@parser{#1} \skvstripouterbraces{2}\skv@foreach@parser ; - list type/csv/ - \def\skv@foreach@listtype{#1} - /csv,kv,tsv,nsv - ; + list type/csv/\def\skv@foreach@listtype{#1}/csv,kv,tsv,nsv; arg,args,arg pattern/##1/ \edef\skv@foreach@paramlist{\unexpanded{#1}} \skvstripouterbraces{1}\skv@foreach@paramlist ; - list breaker/\listbreaker/\def\skv@listbreakertoks{#1}; - list pauser/\listpauser/\def\skv@listpausertoks{#1}; + list breaker/\skvlistbreaker/\def\skv@listbreakertoks{#1}; + list pauser/\skvlistpauser/\def\skv@listpausertoks{#1}; normalize list/true/ \edef\skv@foreach@normalizelist{0\skvifstrcmpTF{#1}{true}01} /true,false @@ -449,42 +482,50 @@ \edef\skv@foreach@useempty{0\skvifstrcmpTF{#1}{true}01} /true,false ; - .exec/ - \let\skv@foreach@exittester\@secondoftwo + .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 ; - loop stopper,exit when/\if01\fi/ - \ifskvindef\else - \edef\skv@tempa{\unexpanded{#1}} - \skvstripouterbraces{2}\skv@tempa - \expandafter\skv@foreach@maketester\expandafter - {\skv@tempa}\skv@foreach@exittester - \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@ ; - item counter,counter/\@nil/ - \def\skv@foreach@itemcounter{#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 + }% + ; + 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 ; % This default value of 'link' is required by \skv@foreach@filllist: .exec/\def\skv@foreach@link{\@nil}; link/\@nil/ - \ifskvindef\else + \edef\skv@prova{\unexpanded{#1}} + \ifx\skv@prova\@nnil\else \edef\skv@foreach@link{\unexpanded{#1}} \skvstripouterbraces{2}\skv@foreach@link - \ifnum0>\numexpr0\ifx\skv@foreach@link\@empty-1\else - \ifx\skv@foreach@link\@nnil-1\else+0\fi\fi\relax\relax - \skv@err{The key 'link' doesn't accept empty/blank values}\@ehd - \fi \fi ; grow/\@nil/ - \ifskvindef\else - \edef\skv@prova{\unexpanded{#1}}% - \ifx\skv@prova\@nnil - \skv@err{Value required for key 'grow'}\@ehd - \else - \skvcsedef{skv@foreach@grow#1}{00}% - \edef\skv@prova{\skvifstrcmpTF{#1}{left}{right}{left}}% - \skvcsedef{skv@foreach@grow\skv@prova}{01}% - \fi + \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 ; @@ -493,17 +534,13 @@ \def\skv@foreach@growright{01}% ; grow left/true/ - \ifskvindef\else - \edef\skv@foreach@growleft{0\skvifstrcmpTF{true}{#1}01}% - \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}10}% - \fi + \edef\skv@foreach@growleft{0\skvifstrcmpTF{true}{#1}01}% + \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}10}% /true,false ; grow right/true/ - \ifskvindef\else - \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}01}% - \edef\skv@foreach@growleft{0\skvifstrcmpTF{true}{#1}10}% - \fi + \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}01}% + \edef\skv@foreach@growleft{0\skvifstrcmpTF{true}{#1}10}% /true,false ; % Keep the decimals in rounded numbers or dimensions when list is @@ -535,10 +572,10 @@ ; % Eg, 'evaluate = #1 as \x using \numexpr#1*2'. % Since the parameters haven't assumed arguments, we defer the - % call to \skv@foxloop@parseevaluate until the arguments are known. + % call to \skv@foreachfox@parseevaluate until the arguments are known. evaluate/\@nil/ \skv@foreach@ifacceptkv{#1}{% - \skv@foxloop@parseevaluate{#1}% + \skv@foreachfox@parseevaluate{#1}% }% ; % Eg, @@ -546,13 +583,13 @@ % 'count in = \p all #1 satisfying \ifnum#1>4\fi' count in,count/\@nil/ \skv@foreach@ifacceptkv{#1}{% - \skv@foxloop@parsecountin{#1}% + \skv@foreachfox@parsecountin{#1}% }% ; % Eg, remember=#1 as \y initially A remember/\@nil/ \skv@foreach@ifacceptkv{#1}{% - \skv@foxloop@parseremember{#1}% + \skv@foreachfox@parseremember{#1}% }% ; reverse list,reverse,reflect/true/ @@ -560,22 +597,12 @@ /true,false ; } - -% Set up \foxloop defaults: -\quickkeys.set{loops/foxloop}{% - parser={,}, - list type=csv, - arg=#1, - list breaker=\listbreaker, - list pauser=\listpauser, - normalize list=true, - use empty=false, - keep decimals=true, - keep high decimals=false, - expand before fill=false, - reverse list=false, - expand list once=false, - expand list twice=false, +\quickkeys.preset{loops/foreachfox}{% + parser={,},list type=csv,arg=#1,loop stopper, + list breaker=\skvlistbreaker,list pauser=\skvlistpauser, + normalize list=true,use empty=false,keep decimals=true, + keep high decimals=false,expand before fill=false, + reverse list=false,expand list once=false,expand list twice=false, expand list fully=false, } @@ -583,10 +610,10 @@ % % Eg, 'evaluate = #1 as \x using \numexpr#1*2'. % -% \skv@foxloop@parseevaluate differs from \skv@foreach@parseevaluate +% \skv@foreachfox@parseevaluate differs from \skv@foreach@parseevaluate % because #1 here is likely to be a non-macro. % -\skvrobustdef*\skv@foxloop@parseevaluate#1{% +\skvrobustdef*\skv@foreachfox@parseevaluate#1{% \begingroup \def\skv@tempxifin##1##2{% \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% @@ -599,19 +626,19 @@ \edef\skv@provc{\skvtrimspace{##3}}% \ifx\skv@prova\@empty \skv@err{Value of key 'evaluate': - \MessageBreak no quantity to evaluate}\@ehd + \MessageBreak no quantity to evaluate}\skv@ehd \fi \ifx\skv@provb\@empty \skv@err{Value of key 'evaluate' has no receiving macro, - \MessageBreak i.e., after 'as'}\@ehd + \MessageBreak i.e., after 'as'}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@provb}{}{% \skv@err{Value of key 'evaluate': receiving macro - \MessageBreak \skvoxdetok\skv@provb not escaped}\@ehd + \MessageBreak \skvoxdetok\skv@provb not escaped}\skv@ehd }% \fi \ifx\skv@provc\@empty - \skv@err{Value of key 'evaluate' has no formula}\@ehd + \skv@err{Value of key 'evaluate' has no formula}\skv@ehd \fi \skv@tempxifin{\pgfmathparse}{##3}{% \def\skv@tempc####1\pgfmathparse####2\skv@nil{% @@ -620,11 +647,11 @@ \skv@foreach@swatrue \else \skv@err{\noexpand\pgfmathparse isn't defined; - \MessageBreak maybe 'pgfmath' isn't loaded}\@ehd + \MessageBreak maybe 'pgfmath' isn't loaded}\skv@ehd \fi \else \skv@err{Invalid token \detokenize{####1} - \MessageBreak before \string\pgfmathparse}\@ehd + \MessageBreak before \string\pgfmathparse}\skv@ehd \fi }% \expandafter\skv@tempc\skv@provc\skv@nil @@ -648,7 +675,7 @@ \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'evaluate': - \MessageBreak there is 'using', but no 'as'}\@ehd + \MessageBreak there is 'using', but no 'as'}\skv@ehd }% }{% % No formula given: @@ -657,10 +684,10 @@ \def\skv@tempb##1as##2##3\skv@nil{% \ifx\@nnil##1\@nnil \skv@err{Value of key 'evaluate' has no - \MessageBreak quantity to evaluate}\@ehd + \MessageBreak quantity to evaluate}\skv@ehd \else \ifx\@nnil##2% - \skv@err{Value of key 'evaluate' has no receiving macro}\@ehd + \skv@err{Value of key 'evaluate' has no receiving macro}\skv@ehd \else \skv@tempa##1as##2using##1\skv@nil \fi @@ -668,14 +695,14 @@ }% \skv@tempb#1{\@nnil}\skv@nil }{% - % No 'as' or 'using'. In \foxloop, #1 is not guaranteed + % No 'as' or 'using'. In \foreachfox, #1 is not guaranteed % to be a macro. Hence raise error here: - \skv@err{Value of key 'evaluate' has no 'as'}\@ehd + \skv@err{Value of key 'evaluate' has no 'as'}\skv@ehd }% }% \skv@foreach@addtocallback{pre}{% \ifskv@foreach@swa - % Here, <formula> may have the syntax \pgfmathresult{<token>}. + % Here, <formula> may have the syntax \pgfmathparse{<token>}. \skvexpandonce\skv@provc \let\skvexpandonce\skv@provb\noexpand\pgfmathresult \else @@ -704,15 +731,15 @@ % % '\foreach \x [count=\xi from 2] in {a,...,e}'. % -% Generic counting is available in \foxloop by default, without -% user request. The macros \currentfox, \foxcount, \nextfox are -% always available on each nesting level. The boolean \iflastfox -% is also always available, to indicate when the last item of -% the list has been reached: +% Generic counting is available in \foreachfox 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: % -% \iflastfox\typeout{Processing last entry of the list} \fi +% \ifforeachlastitem\typeout{Processing last entry of the list} \fi % -\skvrobustdef*\skv@foxloop@parsecountin#1{% +\skvrobustdef*\skv@foreachfox@parsecountin#1{% \begingroup \def\skv@tempxifin##1##2{% \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% @@ -730,11 +757,11 @@ \edef\skv@provc{\skvtrimspace{##3}}% \edef\skv@provd{\skvtrimspace{##4}}% \ifx\skv@prova\@empty - \skv@err{Value of key 'count' has no counter macro}\@ehd + \skv@err{Value of key 'count' has no counter macro}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@prova}{}{% \skv@err{Value of key 'count':\MessageBreak - counter macro \skvoxdetok\skv@prova not escaped}\@ehd + counter macro \skvoxdetok\skv@prova not escaped}\skv@ehd }% \fi \ifx\skv@provd\@empty @@ -744,7 +771,7 @@ \expandafter\let\skv@prova\skv@provd }{% \skv@err{Value of key 'count':\MessageBreak - initial \skvoxdetok\skv@provd not an integer}\@ehd + initial \skvoxdetok\skv@provd not an integer}\skv@ehd }% \fi \skv@foreach@swafalse @@ -758,7 +785,7 @@ \skv@foreach@swatrue % \skv@tester is the second argument of \skv@foreach@maketester, % which is used below: - \skvexpbracenext\skv@foreach@maketester\skv@provc\skv@tester + \skvexpbracenext\skv@foreach@maketester\skv@provc\skv@tester\skvz@ \fi \fi }% @@ -768,7 +795,7 @@ \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'count': - \MessageBreak there is 'satisfying', but no 'all'}\@ehd + \MessageBreak there is 'satisfying', but no 'all'}\skv@ehd }% }{% \skv@tempxifin{all}{#1}{% @@ -776,14 +803,14 @@ }{% % No 'all' and 'satisfying': #1 should be only the counter macro: \ifx\@nnil#1\@nnil - \skv@err{Value of key 'count': no counter macro}\@ehd + \skv@err{Value of key 'count': 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}\@ehd + \MessageBreak I can't find counter macro}\skv@ehd }% \fi }% @@ -809,7 +836,7 @@ % remember=<holder.macro> as <child.macro> initially <value> % -\skvrobustdef*\skv@foxloop@parseremember#1{% +\skvrobustdef*\skv@foreachfox@parseremember#1{% \begingroup \def\skv@tempxifin##1##2{% \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% @@ -817,7 +844,7 @@ \skv@tempxifin{(}{#1}{% \skv@err{Value of key 'remember': '(' found. \MessageBreak I don't accept this PGF format. - \MessageBreak remove the parenthesis '()'}\@ehd + \MessageBreak Remove the parenthesis around '(<your input>)'}\skv@ehd }{}% \def\skv@tempa##1as##2initially##3\skv@nil{% \edef\skv@prova{\skvtrimspace{##1}}% @@ -825,17 +852,17 @@ \edef\skv@provc{\skvtrimspace{##3}}% \skv@foreach@swafalse \ifx\skv@prova\@empty - \skv@err{Value of key 'remember' has no value to remember}\@ehd + \skv@err{Value of key 'remember' has no value to remember}\skv@ehd \fi \ifx\skv@provb\@empty \skv@err{Value of key 'remember' has no child macro; - \MessageBreak i.e., no macro after 'as'}\@ehd + \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}\@ehd + \MessageBreak child \skvoxdetok\skv@provb not escaped}\skv@ehd }% \fi }% @@ -844,7 +871,7 @@ \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'remember': - \MessageBreak there is 'initially', but no 'as'}\@ehd + \MessageBreak there is 'initially', but no 'as'}\skv@ehd }% }{% \skv@tempxifin{as}{#1}{% @@ -853,9 +880,9 @@ % No 'as' and 'initially': \ifx\@nnil#1\@nnil\else % Unlike in \newforeach, we can't create an automatic retainer - % macro here, since \foxloop uses parameters instead of + % macro here, since \foreachfox uses parameters instead of % holder macros. - \skv@err{Value of key 'remember' is incomplete: no 'as'}\@ehd + \skv@err{Value of key 'remember' is incomplete: no 'as'}\skv@ehd \fi }% }% @@ -884,40 +911,62 @@ }% } -\skvnewdef*\skv@foxloop@kvlist{} -% \setupfoxloop{<kvlist>} -\skvrobustdef*\setupfoxloop#1{% +\skvnewdef*\skv@foreachfox@kvlist{} +% \setupforeachfox{<kvlist>} +\skvrobustdef*\setupforeachfox#1{% \skvifblankTF{#1}{}{% - \skvaddtolist\skv@foxloop@kvlist{#1}% + \skvaddtolist\skv@foreachfox@kvlist{#1}% }% } -\skvrobustdef*\skv@foxloop@setkeys#1{% - \def\reserved@a{\quickkeys.set{loops/foxloop}}% - \expandafter\reserved@a\expandafter{\skv@foxloop@kvlist,#1}% +\skvrobustdef*\skv@foreachfox@setkeys#1{% + \def\reserved@a{\quickkeys.set{loops/foreachfox}}% + \expandafter\reserved@a\expandafter{\skv@foreachfox@kvlist,#1}% } - -% \atbeginfoxloop[<depth>]{<code>} -\skvnewlet\atbeginfoxloop\atbeginforeach -% \atendfoxloop[<depth>]{<code>} -\skvnewlet\atendfoxloop\atendforeach - -\skvrobustdef*\foxloop{\skv@teststopt\skv@foxloop{}} -\skvnewlet\foreachfox\foxloop -\skvrobustdef*\skv@foxloop[#1]#2#3{% +\skvrobustdef*\foreachfox{% + \skvifnextchar i{% + \skv@foreachfox@prescan@a + }{% + \skv@teststopt\skv@foreachfox@prescan@b{}% + }% +} +\skvrobustdef*\skv@foreachfox@prescan@a#1#2{% + \skvifstrcmpTF{#1#2}{in}{% + \skv@teststopt\skv@foreachfox@prescan@b{}% + }{% + \skv@err{I have found 'i' before opening brace or + \MessageBreak bracket, but no 'in'}\skv@ehd + }% +} +\skvrobustdef*\skv@foreachfox@prescan@b[#1]{% + \skvifnextchar i{% + \skv@foreachfox@prescan@c[#1]% + }{% + \skv@foreachfox@a[#1]% + }% +} +\skvrobustdef*\skv@foreachfox@prescan@c[#1]#2#3{% + \skvifstrcmpTF{#2#3}{in}{% + \skv@foreachfox@a[#1]% + }{% + \skv@err{I have found 'i' after '[]', but no 'in'}\skv@ehd + }% +} +\skvrobustdef*\skv@foreachfox@a[#1]#2#3{% \edef\skv@foreach@seenstar{0\ifskv@tempst0\else1\fi}% \skv@foreach@pushstate \skv@foreach@latehookerr \def\foreachitemcount{0}% - \def\skv@foreach@callback{}% - \def\skv@foreach@afterprecallback{}% - \def\skv@foreach@precallback{}% - \def\skv@foreach@postcallback{}% - \def\skv@foreach@onlyinitially{}% - \skv@foxloop@setkeys{#1}% + \def\do##1{\def##1{}}% + \do\skv@foreach@itemcounter\do\skv@foreach@processupto + \do\skv@foreach@callback\do\skv@foreach@auxcallback + \do\skv@foreach@precallback\do\skv@foreach@afterprecallback + \do\skv@foreach@postcallback\do\skv@foreach@onlyinitially + \skv@foreachfox@setkeys{#1}% \if\skv@foreach@seenstar \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 @@ -928,8 +977,7 @@ \ifskv@verbose \skv@warn{One-item list '\detokenize{#2}' is a macro. \MessageBreak If your list is indeed a macro, you can - \MessageBreak either put star (*) after - \detokenize{\foxloop or \foreachfox} + \MessageBreak either put star (*) after \noexpand\foreachfox \MessageBreak or use the key 'expand list once' \MessageBreak or 'expand list twice' or 'list is a macro', etc}% \fi @@ -953,7 +1001,9 @@ \fi {#2}% }% - \skvcsuse{skv@foreach@atbeginhook@\skvrom\foreachdepth}% + \skvcsuse{skv@foreach@atbeginhook@\skvrom\foreachnestdepth}% + \skvifdefTF\foreachprevitem{}{\def\foreachprevitem{}}% + % Define the loop callback: \edef\reserved@a{% \skvexpandonce\skv@foreach@precallback \ifx\skv@foreach@onlyinitially\@empty\else @@ -961,10 +1011,18 @@ \skvexpandonce\skv@foreach@onlyinitially \noexpand\fi \fi - \unexpanded{#3}% - \skvexpandonce\skv@foreach@postcallback + \ifx\skv@foreach@continuetester\@secondoftwo + \noexpand\skv@foreach@continuetester + \else + % We want to expose the parameter characters in + % \skv@foreach@continuetester: + \skvexpandonce\skv@foreach@continuetester + \fi + {}{% + \unexpanded{#3}% + \skvexpandonce\skv@foreach@postcallback + }% }% - % Define the user callback: \edef\reserved@b{% \def\noexpand\skv@foreach@callback\skvexpandonce \skv@foreach@paramlist\noexpand\foreacheov @@ -972,18 +1030,21 @@ \expandafter\reserved@b\expandafter{\reserved@a}% \skvxifstrcmpTF\skv@foreach@listtype{csv}{% \def\skv@foreach@lookahead@a##1{% - \def\skv@foreach@continue{##1.}% + \def\skv@foreach@picknext{##1.}% \futurelet\skv@foreach@next\skv@foreach@lookahead@b }% - \def\skv@foreach@lookahead@c[##1]{\skv@foreach@continue[{##1}]}% - \def\skv@foreach@lookahead@d(##1){\skv@foreach@continue({##1})}% + \def\skv@foreach@lookahead@c[##1]{\skv@foreach@picknext[{##1}]}% + \def\skv@foreach@lookahead@d(##1){\skv@foreach@picknext({##1})}% }{% + % Token list (nsv/tsv): \def\skv@foreach@lookahead@a##1{% - \let\skv@foreach@continue##1% + \let\skv@foreach@picknext##1% \futurelet\skv@foreach@next\skv@foreach@lookahead@b }% - \def\skv@foreach@lookahead@c[##1]{\skv@foreach@continue{[##1]}}% - \def\skv@foreach@lookahead@d(##1){\skv@foreach@continue{(##1)}}% + % These \skv@foreach@lookahead@c and \skv@foreach@lookahead@d + % differ from those for 'csv' list (above): + \def\skv@foreach@lookahead@c[##1]{\skv@foreach@picknext{[##1]}}% + \def\skv@foreach@lookahead@d(##1){\skv@foreach@picknext{(##1)}}% }% \def\skv@foreach@lookahead@b{% \skvifxTF\skv@foreach@next[{% @@ -992,20 +1053,23 @@ \skvifxTF\skv@foreach@next({% \skv@foreach@parenthtrue\skv@foreach@lookahead@d }{% - \skv@foreach@parenthfalse\skv@foreach@continue + \skv@foreach@parenthfalse\skv@foreach@picknext }% }% }% - \skvbreakloopfalse\lastfoxfalse + \ifnum\foreachnestdepth=\skvz@ + \breakallforeachloopsfalse + \fi + \skvbreakloopfalse\foreachlastitemfalse\lastfoxfalse \def\reserved@a##1{% \skv@setupgetnextfox{##1}% \skvxifstrcmpTF\skv@foreach@listtype{csv}{% \if\skv@foreach@normalizelist \skv@foreach@normalize[##1]\skv@foreach@userlist \fi - \def\skv@foreach@do####1##1####2\skv@foxloop@stop{% - \edef\currentfox{\skvexpandonce{\@gobble####1}}% - \skv@foxloop@a{##1}{####2}{csv}% + \def\skv@foreach@do@a####1##1####2\skv@foreach@stop{% + \edef\foreachcurrentitem{\skvexpandonce{\@gobble####1}}% + \skv@foreachfox@b{##1}{####2}{csv}% }% \skvifemptyTF\skv@foreach@userlist{}{% \expandafter\skv@foreach@filllist\expandafter @@ -1015,135 +1079,141 @@ {\skv@foreach@parser}\skv@foreach@userlist \fi }% - % If \skv@foreach@userlist is empty, \currentfox in - % \skv@foxloop@b will terminate the loop. - \expandafter\skv@foreach@lookahead@a\expandafter\skv@foreach@do - \skv@foreach@userlist##1\skv@foxloop@nil##1\skv@foxloop@stop + % If \skv@foreach@userlist is empty, \foreachcurrentitem in + % \skv@foreachfox@c will terminate the loop. + \expandafter\skv@foreach@lookahead@a\expandafter\skv@foreach@do@a + \skv@foreach@userlist##1\skv@foreach@nil##1\skv@foreach@stop }{% - \if\skv@foreach@normalizelist + \if\skv@foreach@normalizelist\skvafterfi \edef\skv@foreach@userlist{% \skvexpbracenext\skvtsvnormalize\skv@foreach@userlist }% \fi - \def\skv@foreach@do{% + \def\skv@foreach@do@a{% \let\bgroup\relax - \futurelet\skv@foreach@next\skv@foreach@do@a + \futurelet\skv@foreach@next\skv@foreach@do@b }% - \def\skv@foreach@do@a####1####2\skv@foxloop@stop{% + \def\skv@foreach@do@b####1####2\skv@foreach@stop{% \let\bgroup\skv@orig@bgroup \ifskv@foreach@parenth - \edef\currentfox{\unexpanded{####1}}% + \edef\foreachcurrentitem{\unexpanded{####1}}% \else \skvifxTF\skv@foreach@next\bgroup{% - \edef\currentfox{{\unexpanded{####1}}}% + \edef\foreachcurrentitem{{\unexpanded{####1}}}% }{% - \edef\currentfox{\unexpanded{####1}}% + \edef\foreachcurrentitem{\unexpanded{####1}}% }% \fi - \skv@foxloop@a{}{####2}{tsv}% + \skv@foreachfox@b{}{####2}{tsv}% }% - \expandafter\skv@foreach@lookahead@a\expandafter\skv@foreach@do - \skv@foreach@userlist\skv@foxloop@nil\skv@foxloop@stop + \expandafter\skv@foreach@lookahead@a\expandafter\skv@foreach@do@a + \skv@foreach@userlist\skv@foreach@nil\skv@foreach@stop }% }% \expandafter\reserved@a\expandafter{\skv@foreach@parser}% - \skvcsuse{skv@foreach@atendhook@\romannumeral\foreachdepth}% + \skvcsuse{skv@foreach@atendhook@\romannumeral\foreachnestdepth}% \skv@foreach@popstate } % \skv@setupgetnextfox<parser> \skvrobustdef*\skv@setupgetnextfox#1{% \skvxifstrcmpTF\skv@foreach@listtype{csv}{% - \def\skv@foreach@getnext##1#1##2\skv@foxloop@stop{% - \edef\nextfox{\skvexpandonce{\@gobble##1}}% - % See \skv@foxloop@b for \lastfoxtrue. + \def\skv@foreach@getnext##1#1##2\skv@foreach@stop{% + \edef\foreachnextitem{\skvexpandonce{\@gobble##1}}% + % See \skv@foreachfox@c for \foreachlastitemtrue. }% }{% \def\skv@foreach@getnext{% - \begingroup \let\bgroup\relax \futurelet\skv@foreach@next\skv@foreach@g@tnext }% - \def\skv@foreach@g@tnext##1##2\skv@foxloop@stop{% + \def\skv@foreach@g@tnext##1##2\skv@foreach@stop{% \let\bgroup\skv@orig@bgroup \ifskv@foreach@parenth - \edef\nextfox{\unexpanded{##1}}% + \edef\foreachnextitem{\unexpanded{##1}}% \else \skvifxTF\skv@foreach@next\bgroup{% - \edef\nextfox{{\unexpanded{##1}}}% + \edef\foreachnextitem{{\unexpanded{##1}}}% }{% - \edef\nextfox{\unexpanded{##1}}% + \edef\foreachnextitem{\unexpanded{##1}}% }% \fi }% }% } -% \skv@foxloop@a<parser><remainder><list.type> -\skvrobustdef*\skv@foxloop@a#1#2#3{% - \skvifxTF\currentfox\skv@foxloop@nnil{% - \skvbreakloopfalse\lastfoxfalse +% \skv@foreachfox@b<parser><remainder><list.type> +\skvrobustdef*\skv@foreachfox@b#1#2#3{% + \skvifxTF\foreachcurrentitem\skv@foreach@nnil{% + \skvbreakloopfalse\foreachlastitemfalse\lastfoxfalse }{% - \skvifxTF\currentfox\skv@listbreakertoks{% - \skv@foxloop@getrm{#1}{#2}% + \skvifxTF\foreachcurrentitem\skv@listbreakertoks{% + \skv@foreachfox@getrm{#1}{#2}% }{% - \skvifxTF\currentfox\skv@listpausertoks{% + \skvifxTF\foreachcurrentitem\skv@listpausertoks{% \message{^^J! List pause: ^^JType x or X to quit, or <RETURN> to proceed^^J}% \bgroup\endlinechar\m@ne\global\read-1 to\@gtempa\egroup \skvexpandarg\lowercase{\def\noexpand\@gtempa{\@gtempa}}% \skvxifstrcmpTF\@gtempa{x}{% - \skv@foxloop@getrm{#1}{#2}% + \skv@foreachfox@getrm{#1}{#2}% }{% - \skv@foxloop@b{#1}{#2}{#3}% + \skv@foreachfox@c{#1}{#2}{#3}% }% }{% - \skv@foxloop@b{#1}{#2}{#3}% + \skv@foreachfox@c{#1}{#2}{#3}% }% }% }% } -% \skv@foxloop@b<parser><remainder><list.type> -\skvrobustdef*\skv@foxloop@b#1#2#3{% - \skv@foreach@lookahead@a\skv@foreach@getnext#2\skv@foxloop@stop - \ifx\nextfox\skv@foxloop@nnil - \lastfoxtrue\def\nextfox{}% +% \skv@foreachfox@c<parser><remainder><list.type> +\skvrobustdef*\skv@foreachfox@c#1#2#3{% + \skv@foreach@lookahead@a\skv@foreach@getnext#2\skv@foreach@stop + \ifx\foreachnextitem\skv@foreach@nnil + \foreachlastitemtrue\lastfoxtrue + \def\foreachnextitem{}% \fi \edef\foreachitemcount{\the\numexpr\foreachitemcount+1}% - \ifnum0=\numexpr - \ifx\skv@foreach@itemcounter\@undefined-1\else+0\fi - \ifx\skv@foreach@itemcounter\@empty-1\else+0\fi - \ifx\skv@foreach@itemcounter\@nnil-1\else+0\fi\relax\relax - \expandafter\let\skv@foreach@itemcounter\foreachitemcount + \ifx\skv@foreach@itemcounter\@empty\else + \expandafter\let\skv@foreach@itemcounter\foreachitemcount \fi - \skvifemptyTF\currentfox{% - \if\skv@foreach@useempty - \expandafter\skv@foreach@callback\expandafter\foreacheov + \skvifemptyTF\foreachcurrentitem{% + \if\skv@foreach@useempty\skvafterfi + \skv@foreach@callback\foreacheov \fi }{% - % Tes for \listpauser, in case the user decides to continue - % after \listpauser has been picked: - \skvifxTF\currentfox\skv@listpausertoks{}{% + % Test for \skvlistpauser, in case the user decides to continue + % after \skvlistpauser has been picked: + \skvifxTF\foreachcurrentitem\skv@listpausertoks{}{% \skvifxTF\skv@foreach@paramlist\skv@simplearg{% - \expandafter\skv@foreach@callback\expandafter - {\currentfox}\foreacheov + \skvexpbracenext\skv@foreach@callback\foreachcurrentitem\foreacheov }{% - \expandafter\skv@foreach@callback\currentfox\foreacheov + % Incomplete items like 3 in {1/a,2/b,3} can't be handled by + % \foreachfox; see \newforeach. + \expandafter\skv@foreach@callback\foreachcurrentitem\foreacheov }% + \let\foreachprevitem\foreachcurrentitem }% }% - \skv@foreach@exittester{\skvbreakloop}{}% + \ifx\skv@foreach@processupto\@empty\else + \ifnum\foreachitemcount<\skv@foreach@processupto\relax\else + \skvbreakloop + \fi + \fi \skvifdefboolTF{skvbreakloop}{% - \skvbreakloopfalse\lastfoxfalse - \skv@foxloop@getrm{#1}{#2}% + \ifbreakallforeachloops\else + \skvbreakloopfalse + \fi + \foreachlastitemfalse\lastfoxfalse + \skv@foreachfox@getrm{#1}{#2}% }{% - \skv@foreach@lookahead@a\skv@foreach@do#2\skv@foxloop@stop + \skv@foreach@lookahead@a\skv@foreach@do@a#2\skv@foreach@stop }% } -% \skv@foxloop@getrm<parser><remaining.items> -\skvrobustdef*\skv@foxloop@getrm#1#2{% +% \skv@foreachfox@getrm<parser><remaining.items> +\skvrobustdef*\skv@foreachfox@getrm#1#2{% \begingroup - \def\reserved@a##1\skv@foxloop@nil#1{% + \def\reserved@a##1\skv@foreach@nil#1{% \endgroup - \edef\foxlistremainder{\unexpanded{##1}}% + \edef\foreachlistremainder{\unexpanded{##1}}% }% \reserved@a#2% } @@ -1222,7 +1292,7 @@ \skvbreakloopfalse\lastcicadafalse }{% \edef\cicadacount{\the\numexpr\cicadacount+1}% - \skv@cicada@lookahead\skv@cicada@getnext##2\skv@cicada@stop + \skv@cicada@lookahead@a\skv@cicada@getnext##2\skv@cicada@stop \skvexpandbracenext\skv@cicada@callback\currentcicada\relax \skvifcondFT#3\fi{}\skvbreakloop \skvifdefboolTF{skvbreakloop}{% @@ -1235,33 +1305,33 @@ \skv@prova##2% }{% \let\lastcicada\currentcicada - \skv@cicada@lookahead\skv@cicada@do##2\skv@cicada@stop + \skv@cicada@lookahead@a\skv@cicada@do##2\skv@cicada@stop }% }% }% }% - \def\skv@cicada@lookahead##1{% - \def\skv@cicada@continue{##1.}% - \futurelet\skv@next\skv@cicada@lookahead@a + \def\skv@cicada@lookahead@a##1{% + \def\skv@cicada@picknext{##1.}% + \futurelet\skv@next\skv@cicada@lookahead@b }% - \def\skv@cicada@lookahead@a{% + \def\skv@cicada@lookahead@b{% \ifx\skv@next[% - \expandafter\skv@cicada@lookahead@b + \expandafter\skv@cicada@lookahead@c \else \ifx\skv@next(% - \expandafter\expandafter\expandafter\skv@cicada@lookahead@c + \expandafter\expandafter\expandafter\skv@cicada@lookahead@d \else - \expandafter\expandafter\expandafter\skv@cicada@continue + \expandafter\expandafter\expandafter\skv@cicada@picknext \fi \fi }% - \def\skv@cicada@lookahead@b[##1]{\skv@cicada@continue[{##1}]}% - \def\skv@cicada@lookahead@c(##1){\skv@cicada@continue({##1})}% + \def\skv@cicada@lookahead@c[##1]{\skv@cicada@picknext[{##1}]}% + \def\skv@cicada@lookahead@d(##1){\skv@cicada@picknext({##1})}% \skvbreakloopfalse\lastcicadafalse \skvifxTF\skv@cicada@userlist\@empty{% \ifskvprocessempty\skv@cicada@callback{}\fi }{% - \skvexpandnext{\skv@cicada@lookahead\skv@cicada@do}% + \skvexpandnext{\skv@cicada@lookahead@a\skv@cicada@do}% \skv@cicada@userlist#1\skv@cicada@nil#1\skv@cicada@stop }% \skvpopstate\skv@cicada@state\cicadaloopdepth @@ -1270,11 +1340,12 @@ % \cicadiloop[<parser>]{<list>}<\if...>\fi{<ini-code>}{<1.parameter.code>} % \cicadiloop*[<parser>]{<listcmd>}<\if...>\fi{<ini-code>}{<1.parameter.code>} % -% It is easy to forget to turn conditional #3 off before commencing +% It is easy to forget to turn conditional <\if...> off before commencing % the loop, especially if it is a boolean. The conditional might have % been set true before calling \cicadaloop, and this may invalidate -% later tests to terminate the loop prematurely. #4 can be used to turn -% the condtional off before commencing the loop. +% later tests to terminate the loop prematurely. <ini-code> can be used +% to turn the condtional off before commencing the loop. This forces the +% user to heed this term. % \skvrobustdef*\cicadiloop{\skv@teststopt\skv@cicadiloop,} \skvrobustdef*\skv@cicadiloop[#1]#2#3\fi#4{% @@ -1306,7 +1377,7 @@ % % \lpsdeclarelistnormalizer<normalizer.cmd>{<parser>} % -% Eg, +% Example: % % \lpsdeclarelistnormalizer\lpscommanormalize{,} % @@ -1314,7 +1385,7 @@ % \skvrobustdef*\lpsdeclarelistnormalizer#1#2{% \skvifescapedTF{#1}{}{% - \skv@err{Token \detokenize{#1} isn't escaped}\@ehd + \skv@err{Token \detokenize{#1} isn't escaped}\skv@ehd }% \def\reserved@a{\lps@declarelistnormalizer{#1}}% \expandafter\reserved@a\expandafter{\string#2}% @@ -1355,14 +1426,16 @@ \lpsdeclarelistnormalizer\lpsslashnormalize{/} % Declare an expandable csv list parser. No premature stopping of the loop -% is possible by this scheme. To use, first do +% is possible by this scheme. To use this scheme, first do % % \lpsdeclareexpandablelistparser<processor.cmd><processor.func>{<parser>} -% \def<processor.function>{<1-parameter callback>} +% \def<processor.func>{<1-parameter callback>} % % and then call % -% <processor.cmd><list> or <processor.cmd>*<listcmd>. +% <processor.cmd><list> or <processor.cmd>*<listcmd> +% +% <list> or <listcmd> will be normalized before being parsed. % % Example: % @@ -1399,38 +1472,21 @@ }% }% } - -\skvrobustdef*\lpsAtBeginEnvironment#1{% - \skvaftercs\skvappendtomacro{lps@atbegin@#1@hook}% -} -\skvrobustdef*\lpsAtEndEnvironment#1{% - \skvaftercs\skvappendtomacro{lps@atend@#1@hook}% -} - -\skvpatchcmd\begin - {\csname#1\endcsname} - {\skvcsuse{lps@atbegin@#1@hook}\csname#1\endcsname} - {} - {\skv@err{Patching '\string\begin' failed!\MessageBreak - '\string\lpsAtBeginEnvironment' will not work\@gobble}\@ehd - } - -\skvpatchcmd\end - {\csname end#1\endcsname} - {\skvcsuse{lps@atend@#1@hook}\csname end#1\endcsname} - {} - {\skv@err{Patching '\string\end' failed!\MessageBreak - '\string\lpsAtEndEnvironment' will not work\@gobble}\@ehd - } - -% Without the following patch, drawing intructions like +% Unfortunately, without the following patch, drawing instructions like +% +% \draw[blue] (p) \newforeach \p in {1,...,8}{...}; +% +% will not work, because of the way TikZ hardwires \foreach for this type +% of task (ie, when \draw precedes \newforeach or \foreachfox). The fact +% here is that in this case, both \newforeach and \foreachfox can't work +% but leave everything for \foreach. This can be a problem when \newforeach +% or \foreachfox is called to avoid a known bug in \foreach, such as at % -% \draw[blue] (p) \newforeach \p in {1,...,8}{...}; +% <http://tex.stackexchange.com/questions/79586/foreach-has-a-problem% +% -with-initially-argument-in-remember-part/79644#79644> % -% will not work, because of the way tikZ hardwires \foreach -% for this type of task. % -\lpsAtBeginEnvironment{tikzpicture}{% +\skvAtBeginEnvironment{tikzpicture}{% \def\tikz@handle@more{% \ifx\@let@token a\let\@next=\tikz@arcA\else \ifx\@let@token e\let\@next=\tikz@e@char\else |