From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/latex/contrib/loops/README | 663 +++++++++ macros/latex/contrib/loops/doc/loops-pokayoke1.tex | 133 ++ macros/latex/contrib/loops/tex/loops.sty | 1528 ++++++++++++++++++++ 3 files changed, 2324 insertions(+) create mode 100644 macros/latex/contrib/loops/README create mode 100644 macros/latex/contrib/loops/doc/loops-pokayoke1.tex create mode 100644 macros/latex/contrib/loops/tex/loops.sty (limited to 'macros/latex/contrib/loops') diff --git a/macros/latex/contrib/loops/README b/macros/latex/contrib/loops/README new file mode 100644 index 0000000000..a6a81632b5 --- /dev/null +++ b/macros/latex/contrib/loops/README @@ -0,0 +1,663 @@ +This is the README file for the 'loops' package. + +AUTHOR + +Ahmed Musa + +VERSION + +Version 1.3, 2013/05/15. + +LOCATION ON CTAN + +macros/latex/contrib/loops/ + + +The package provides efficient looping macros for processing both +csv (separated-values) and nsv/tsv (non-separated values) lists. +Csv lists that have associated arbitrary list-separators may be +processed with the tools of the package. + + +LICENSE + +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 +LaTeX Project Public License, version 1.3 or higher. 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 any particular purpose. + +NOTE + +Non-LaTeX users can use the \newforeach macro (and some other +looping macros) by loading the file skeyval-for.tex. These exclude +\foreachfox, which are available only in loops.sty. + +SUMMARY + +The 'loops' package provides efficient looping macros for processing +both csv (separated-values) and nsv/tsv (non-separated values) lists. +csv lists having arbitrary parsers, and even active parsers, can +be processed with the tools of this package. + +All our loops can be safely nested. Breaking the inner loop doesn't +affect the continuation of the outer loop. + +The looping macros include: + +\skvrecurse: + + \skvrecurse{}\while<\if...>\fi + + A variant of D.E. Knuth's \loop macro. + + \@tempcnta\z@ + \skvrecurse{ + \advance\@tempcnta\@ne + \@tempcntb\z@ + \skvrecurse + \advance\@tempcntb\@ne + \typeout{Doing \the\@tempcnta,\the\@tempcntb} + \while + \ifnum\@tempcntb<3\relax + \fi + } + \while + \ifnum\@tempcnta<4\relax + \fi + + +\carlisleloop: + + \carlisleloop{}<\if...>\repeat + + A nesting version of D.E. Knuth's \loop macro, + adapted from the original macros of David Carlisle. + + \skvnewcounts{rowcnt,colcnt,maxrow,maxcol} + \maxrow4 \maxcol3\relax + \def\entries{} + \let\xp\skvexpandonce + \def\generate{% + \advance\colcnt\@ne + \edef\entries{\xp\entries\the\numexpr\rowcnt*\colcnt\relax}% + \ifnum\colcnt<\numexpr\maxcol+1\relax\relax + \edef\entries{\xp\entries\noexpand&}% + } + \def\generateentries{% + \carlisleloop\a + \advance\rowcnt\@ne\colcnt\z@ + \carlisleloop\b + \generate + \repeat\b + \ifnum\rowcnt<\numexpr\maxrow+1\relax\relax + \edef\entries{\xp\entries\noexpand\cr}% + \repeat\a + \edef\entries{\xp\entries\noexpand\crcr}% + } + \begin{document} + \generateentries + $$\vbox{\halign{&\ \hfil#\hfil\strut\cr\entries}}$$ + \end{document} + + +\akterloop: + + \akterloop{}<\if...>\repeat + + A generalized and naturally nesting version of D.E. Knuth's + \loop macro. No nesting brace is required, unlike in \skvrecurse. + No is required, unlike in \carlisleloop. + + \def\generateentries{% + \akterloop + \advance\rowcnt\@ne\colcnt\z@ + \akterloop + \generate + \repeat + \ifnum\rowcnt<\numexpr\maxrow+1\relax\relax + \edef\entries{\xp\entries\noexpand\cr}% + \repeat + \edef\entries{\xp\entries\noexpand\crcr}% + } + \begin{document} + \generateentries + $$\vbox{\halign{&\ \hfil#\hfil\strut\cr\entries}}$$ + \end{document} + + +\skvtfor: + + \skvtfor:={}\do{} + \skvtfor*:={}\do{} + + A variant of LaTeX kernel's \@tfor that has a different + approach to breaking the loop prematurely. + + \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 + }% + } + + +\ayeloop: + + \ayeloop{}\do{<1.parameter.callback>} + \ayeloop*{}\do{<1.parameter.callback>} + + A variant of \skvtfor that uses parameter characters + directly, instead of a holder macro. + + \ayeloop abcd\do{% + \def\nr{0}% + \ayeloop 12345\do{% + \typeout{Doing #1--##1}% + \skvpushnumber\nr + \ifnum\nr>3\relax\skvbreakloop\fi + }% + } + + +\sifakaloop: + + \sifakaloop{}{<1.parameter.callback>} + \sifakaloop*{}{<1.parameter.callback>} + + \sifakaloop is as \ayeloop but will first normalize the list + using \skvtsvnormalize before parsing. Unlike all the + other nsv/tsv loops, it preserves outer braces in the + arguments. Hence, it is costlier. You can insert \foreachlistbreaker + as a token in or to terminate the list prematurely. + + +\skvfor: + + \skvfor{}<1.parameter.callback.macro> + + \skvfor is an expandable comma loop. The list is not + normalized prior to parsing, and it is not possible to + terminate the loop prematurely (ie, before exhausting + the list). + + \newcount\nr\nr=\tw@ + \def\do#1{% + \let\noexpand#1% + \expandafter\noexpand\csname\skvremovescape{#1}@% + \romannumeral\nr\endcsname + } + \edef\x{\skvfor{\cmda,\cmdb}\do} + \show\x -> \let\cmda\cmda@ii \let\cmdb\cmdb@ii + + +\skvgenloop: + + \skvgenloop{}{}{<1.parameter.callback>} + + \skvgenloop is non-expandable but it takes any arbitrary + list separator (parser). In the case of non-separated (nsv/tsv) + lists, can be empty. The list is not normalized prior to + parsing, and it is not possible to terminate the loop prematurely + (ie, before exhausting the list). + + Here, <1.parameter.callback> is not a macro, unlike the + <1.parameter.callback.macro> for \skvfor. + + \newcount\nr\nr=\tw@ + \def\stack{} + \skvgenloop{,}{\cmda,\cmdb}{% + \edef\stack{% + \unexpanded\expandafter{\stack}% + \let\noexpand#1% + \expandafter\noexpand\csname\skvremovescape{#1}@% + \romannumeral\nr\endcsname + }% + } + \show\stack + + +\skvcommaloop, \skvecommaloop, \skvcommaparse, \skvkvparse: + + \skvcommaloop{}{} + \skvcommaloop*{}{} + + All these have the same syntax. \skvecommaloop is as + \skvcommaloop but will execute once when + is empty. This is needed for processing empty key families. + + \skvcommaparse is as \skvcommaloop but will first normalize + using \skvcsvnormalize. \skvkvparse is as \skvcommaloop + but will first normalize using \skvkvnormalize. + \skvkvparse is meant for processing key-value lists. + + +\skvdolist and \skvparselist: + + \skvparselist{}{}{} + \skvparselist*{}{}{} + + These can process lists with arbitrary parsers/list + separators, including non-separated lists. The only difference + between \skvdolist and \skvparselist is that \skvparselist will + first normalize the list before parsing. + + +\cicadaloop: + + \cicadaloop[]{}<\if...>\fi{} + \cicadaloop*[]{}<\if...>\fi{} + + \cicadaloop will terminate prematurely on the current depth + whenever the condition specified by <\if...> is true. + is the regular code, to be executed + for every item of the list before the loop is terminated. + + Some internal macros are accessible by the user: \iflastcicada, + \currentcicada, \nextcicada, \lastcicada, \cicadacount. + \cicadacount is depth-dependent. + + You can insert \foreachlistbreaker as an item in or + to terminate the list prematurely. Note: Unlike \newforeach and \foreachfox, + \foreachlistpauser isn't recognized by \cicadaloop. + + \let\romn\romannumeral + \@tempcnta\z@ + \def\blist{{X};{Y};Z;\fi} + \def\stack{} + \cicadaloop{{a},{b},c,\if}\if01\fi{% + \advance\@tempcnta\@ne + \@tempcntb\z@ + \@tempswafalse + \cicadaloop*[;]\blist\if@tempswa\fi{% + \advance\@tempcntb\@ne + \typeout{Doing \romn\@tempcnta,\romn\@tempcntb: + \detokenize{#1,##1}}% + \edef\stack{% + \unexpanded\expandafter{\stack}\noexpand\do + {\romn\@tempcnta,\romn\@tempcntb}{\unexpanded{#1;##1}}% + }% + \ifnum\@tempcntb>\@ne + \@tempswatrue + \skvcsedef{cmd@\romn\cicadanestdepth}{\lastcicada,\cicadacount}% + \fi + }% + } + \show\stack + + +\newforeach: + + \newforeach[]{} + {}{}{} + \newforeach[]{} + {}{}{} + + The star (*) form of \newforeach is equivalent to declaring + the option 'list is a macro' in . + + \newforeach is a more versatile and robust version of the popular + \foreach macro of the PGF bundle. The macro accepts arbitrary list + parsers and sub-parsers, including active list separators. + When needed, parameters corresponding to the holder macros can + be used directly in the callback. \newforeach does everything + that PGF's \foreach does. It doesn't automatically scope + calculations as \foreach does. Automatically creating local + groups for computations has been a problem for some users + of \foreach. Instead, \newforeach uses stacks to save and + restore the values of holder macros and some other internal + parameters/quantities. + + There is a long list of options/keys in , available for + \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 + + \breaknewforeach (=\skvbreakloop), + \breakallforeachloops, \foreachcurrentitem, + \foreachnextitem, \foreachitemcount, \foreachprevitem, + \prependtobeginforeach, \appendtobeginforeach (=\atbeginforeach), + \prependtoendforeach, \appendtoendforeach (=\atendforeach), + \ifforeachlastitem, \foreachnestdepth, \foreachlistremainder, + \skvforeachonlyinitially. + + \foreachitemcount counts the items as the loop progresses. + It is depth dependent, ie, it can be called to access the + number of items processed on each depth of nesting of + \newforeach. On any depth, the user can say, eg, + + \ifnum\foreachitemcount>10\relax\breaknewforeach\fi + + or + + \ifnum\foreachitemcount>10\relax\breaknewforeach\fi + + You can insert \foreachlistbreaker as an item in or + to terminate the list prematurely. \foreachlistpauser will pause + the processing for user action. + + \newforeach found a bug in PGF's \foreach, as reported at + . However, \newforeach itself + can't be said to be bug free. + + Maybe you fancy the following syntactic sugar: + + \begingroup + \catcode`\,=13 + \gdef\alist{1,2,...,5,7,8,...,12} + \endgroup + \parindent-20pt + \begin{tikzpicture} + \draw[step=.5cm,blue!65,very thin] (0,0) grid (13,6); + \newforeach \x [ + expand list once, + count in=\xc all \x satisfying \ifnum\x>5\fi + ] in \alist { + \newforeach [ + parser={;}, + subparser=:, + evaluate=\y as \ye using \numexpr\y*10 + ] + \y:\z in {1:red; 2:green; 3:blue; 4:brown; 5:purple} do { + \draw [fill=\z\ifnum\x>5!\ye\fi] (\x,\y) +(-.5,-.5) + rectangle ++(.5,.5); + \draw (\x,\y) node {\x,\y}; + } + } + \global\let\xc\xc + \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 + \begin{tikzpicture} + % You may fix \pgfmathsetseed to get a constant output: + % \pgfmathsetseed{42} + \newforeach \y [count=\yc] in {-0.5,-1,...,-2.5} {% + \node[right] at (15.2,\y+0.1) {\scriptsize Subject \yc}; + \newforeach \x in {1,...,300}{% + \pgfmathtruncatemacro{\drawbool}{rand-0.7 > 0 ? 1 : 0}% + \ifnum\drawbool=1\relax + \fill (\x/20,\y) rectangle (\x/20+0.05,\y+0.3); + \fi + }% + }% + \draw[-stealth] (0,0) -- (15.5,0); + \node[right] at (15.5,0.2) {t in ms}; + \newforeach \x [ + pgf evaluate=\x as \xv using int(20*\x) + ] in {0,...,15} {% + \draw (\x,-0.05) -- (\x,0.05) node[above] {\xv}; + } + \end{tikzpicture} + + Here, it is possible to use #1, ##1, ##2 in the callback to + refer to \x, y, \z, respectively. This relieves the user of the + 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. + + \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 = \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} {% + \typeout{Doing items: #1, ##1}% + %\ifnum\y=3 \breakallforeachloops\fi + }% + } + \begin{document} + Numbers: {\tt\string\xc}: \xc, {\tt\string\yc}: \yc + \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] + \let\pgftrun\pgfmathtruncatemacro + \newforeach [count=\ic] \x/\y in {1/.5,1/1,0/1,0/0,1/0,1/-1,0/-1,0/-.5,0/0} + \coordinate (p\ic) at (\x,\y); + \draw[line width=1pt,blue] (p1) \newforeach \p in {2,...,8} {-- (p\p)}; + \newforeach \q in {1,...,7} {% + \pgftrun{\qa}{\q+1}\pgftrun{\qb}{\q+2}\pgftrun{\ind}{2*\q-1}% + \pgftrun{\next}{2*\q}% + \coordinate (n\ind) at (barycentric cs:p\q=0.5,p\qa=0.5); + \coordinate (n\next) at (barycentric cs:p\q=0.125,p\qa=0.75,p\qb=0.125); + } + \draw[line width=2pt,red] (n1)\newforeach \q in {2,...,13}{--(n\q)}; + \end{tikzpicture} + \end{document} + + + % A complete graph. + % Example credit: + % Quintin Jean-Noël + % + \usepackage[active,tightpage]{preview} + \PreviewEnvironment{tikzpicture} + \setlength\PreviewBorder{5pt}% + \usetikzlibrary[topaths] + \newcount\mycount + \begin{document} + \begin{tikzpicture}[transform shape] + \newforeach \nr in {1,...,8}{ + \mycount=\numexpr(\nr-1)*45\relax + \node[draw,circle,inner sep=0.25cm] (N-\nr) at + (\the\mycount:5.4cm) {}; + } + \newforeach \nr in {9,...,16}{ + \mycount=\numexpr(\nr-1)*45+22\relax + \node[draw,circle,inner sep=0.25cm] (N-\nr) at + (\the\mycount:5.4cm) {}; + } + \newforeach \nr in {1,...,15}{ + \mycount=\numexpr\nr+1\relax + \newforeach \nra in {\the\mycount,...,16}{ + \path (N-\nr) edge[->,bend right=3] (N-\nra) + edge[<-,bend left=3](N-\nra); + } + } + \end{tikzpicture} + + +\foreachfox: + + \foreachfox[]{}{} + \foreachfox*[]{}{} + + \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 \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 \foreachfox doesn't expect any optional 'in' or 'do' in the + argument list. + 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: + + \breakforeachfox, \foreachnestdepth, \foreachitemcount, \foreachprevitem, + \foreachcurrentitem, \foreachnextitem, \ifforeachlastitem, \foreachlistremainder, + \prependtobeginforeach, \appendtobeginforeach (=\atbeginforeachfox), + \prependtoendforeach, \appendtoendforeach (=\atendforeachfox). + + + Examples: + + \foreachfox [ + remember=#1 as \x initially A + ] {B,...,H} {% + $\overrightarrow{\x#1}$\ifforeachlastitem.\else,\space\fi + } + + This is equivalent to: + + \foreachfox [ + list type=tsv, + remember=#1 as \x initially A + ] in {BCDEFGH} {% + $\overrightarrow{\x#1}$\ifforeachlastitem.\else,\space\fi + } + + \usepackage{multicol} + \begin{document} + \begin{multicols}{2} + \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}, + count in= \ci all ##1 satisfying \ifnum##1<4\fi initially 2, + count in= \di all ##1 satisfying \ifnum##1>2\fi, + ] {1,...,6} { + \endgraf + Doing: #1, ##1, \nchar, \ci, \di + \endgraf + \ifnum\nchar>3\relax + \vskip-\vx pt\relax + \fi + \hskip\hx pt\relax + \tikz[rounded corners,ultra thick]{ + \shade[ball color=red!\xe!blue] (0,0) circle (.25cm); + \node[white,font=\large] (0,0) {#1}; + }% + }% + } + \end{multicols} + \end{document} + + + % Example credit: Heiko Oberdiek. + \makeatletter + \let\do\newdimen\do\DimWD\do\DimHT\do\DimDP + \newcommand*{\DimBox}[1]{% + \begingroup + \sbox0{\makebox[\DimWD]{#1}}% + \ht0=\DimHT\dp0=\DimDP\usebox\z@ + \endgroup + } + \newcommand*{\DimMeasure}[3]{% + \node at (0,0) {% + \let\do\global + \do\DimWD\z@\do\DimHT\z@\do\DimDP\z@ + \foreachfox* [arg=##1/##2,parser={#1}] #2 {% + \sbox0{#3}% + \ifdim\wd0>\DimWD\global\DimWD=\wd0\fi + \ifdim\ht0>\DimHT\global\DimHT=\ht0\fi + \ifdim\dp0>\DimDP\global\DimDP=\dp0\fi + }% + };% + } + \makeatother + \begin{document} + \def\yellowlist{a/-1,-2;b/1,-2;c/2,-1;d/2,1;e/1,2;f/-1,2;g/-2,1;h/-2,-1} + \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} + \foreachfox* [arg=#1/#2,parser={;},count=\xc] \yellowlist { + \node (#1) at (#2) [fill=blue!20,draw=yellow] {\DimBox{#1}}; + } + \DimMeasure{,}{\bluelist}{#1--#2} + \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 + + + +% End of readme file of loops.sty diff --git a/macros/latex/contrib/loops/doc/loops-pokayoke1.tex b/macros/latex/contrib/loops/doc/loops-pokayoke1.tex new file mode 100644 index 0000000000..26f9145ee6 --- /dev/null +++ b/macros/latex/contrib/loops/doc/loops-pokayoke1.tex @@ -0,0 +1,133 @@ +%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% +% This is file 'loops-pokayoke1.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 loops bundle and must be % +% distributed as a whole: % +% % +% README, loops.sty, loops-pokayoke1. % +% % +% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). % +%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% + +\documentclass{article} +\usepackage{tikz} +\usepackage{loops} + +% See the README file for more examples. + +%++++++++++++++++++++++++++ Examples +++++++++++++++++++++++++% + +% There are two types of sequences in the following list, i.e., +% {\pi0,\pi0.5,\pi...,\pi3} and {0\pi,0.5\pi,...\pi,3\pi} +% +\newforeach\x in {\pi0,\pi0.5,\pi...,\pi3,0\pi,0.5\pi,...\pi,3\pi}{% + \edef\y{\skvexpandonce\x}% +} + + +\begin{document} +\begin{tikzpicture}[every node/.style=draw] +\node (A) at (0,0) {A}; +\node (B) at (2,0) {B}; +\node (C) at (4,0) {C}; +\node (D) at (6,0) {D}; +\newforeach \n [remember=\n as \lastn initially A] in {B,C,D} + \draw [->] (\lastn) -- (\n); +\end{tikzpicture} + +\par\bigskip + +\foreachfox [remember=#1 as \x initially A] {B,C,D,E,F,G,H} {% + $\overrightarrow{\x#1}$\iflastfox.\else,\space\fi +} + +\foreachfox [remember=#1 as \x initially A] {B,...,H} {% + $\overrightarrow{\x#1}$\iflastfox.\else,\space\fi +} + +% (C1) and [F1] will be picked as single elements: +\foreachfox [list type=tsv,remember=#1 as \x initially A] {B(C1)DE[F1]GH} {% + $\overrightarrow{\x#1}$\iflastfox.\else,\space\fi +} + +\end{document} + + +%++++++++++++++++++++++++++ Examples +++++++++++++++++++++++++% + +\documentclass{article} +\usepackage{tikz,loops} +\usetikzlibrary{arrows,shapes,backgrounds,fit} +\usepackage{tkz-graph} + +\begin{document} +\begin{tikzpicture} +\SetVertexNormal[Shape=rectangle,FillColor=lightgray,LineWidth=2pt] +\SetUpEdge[lw=1.5pt,color=black] +\foreach \y in {1,2,3,4} { + \foreach \x / \a in {1/a,2/b,3/c,4/d} { + \Vertex[L=\y \a,x=2*\x,y=2*\y]{\x\y} + } +} +\newforeach \x/\y/\z/\s in { + 11/23/32/,14/33/22/,41/33/22/,44/44/23/,21/33/42/13, + 24/12/32/43,31/12/23/43,34/13/22/42,12/33//,22/43//, + 32/13//,42/23// +}{ + \Edge(\x)(\y) + \ifx\z\empty\else\Edge(\x)(\z)\fi + \ifx\s\empty\else\Edge(\x)(\s)\fi +} +\end{tikzpicture} +\end{document} + +\def\alist{} +\newforeach\x in {% + 2pt_A,4pt_A,...pt_A,10pt_A +}{% + \xdef\alist{\alist\ifx\alist\@empty\else,\fi\x}% +} +\show\alist + +\let\alist\@gobble +\newforeach\x in {% + A_2pt,A_4pt,A_...pt,A_10pt, A_20pt,A_24pt,A_...pt,A_40pt +}{% + \xdef\alist{\alist,\x}% +} +\show\alist + +\let\alist\@gobble +\foreachfox {% + A_2pt,A_4pt,A_...pt,A_10pt, A_20pt,A_24pt,A_...pt,A_40pt% +}{% + \xdef\alist{\alist,#1}% +} +\show\alist + +\let\alist\@gobble +% The key 'hide parameters' makes it possible to use parameter +% characters in the callback without doubling them. +\newforeach[hide parameters] \x in {1,...,10} do {% + \edef\cmda#1{\x*#1}% + \newforeach[hide parameters] \y in {A,...,M} do {% + \xdef\alist{\alist,\x(\y)}% + \edef\cmdb#1{\x*\y*#1}% + }% +} +\show\alist + diff --git a/macros/latex/contrib/loops/tex/loops.sty b/macros/latex/contrib/loops/tex/loops.sty new file mode 100644 index 0000000000..533c51b319 --- /dev/null +++ b/macros/latex/contrib/loops/tex/loops.sty @@ -0,0 +1,1528 @@ +%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% +% This is file 'loops.sty', 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 loops bundle and must be % +% distributed as a whole: % +% % +% README, loops.sty, loops-pokayoke1. % +% % +% Copyright (c) 2012-2013 Ahmed Musa (amusa22@gmail.com). % +%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% + +\begingroup +\catcode035 06 % # +\catcode064 11 % @ +\catcode123 01 % { +\catcode125 02 % } +\catcode044 12 % , +\def\skv@prova{\endgroup + \def\do##1,{% + \ifx\do##1\else + \catcode##1\string=\the\catcode##1\relax + \expandafter\do + \fi + }% + \edef\loops@restorecodes{\do035,064,123,125,061,059,\do,}% +} +\skv@prova +\catcode035 06 % # +\catcode064 11 % @ +\catcode123 01 % { +\catcode125 02 % } +\catcode061 12 % = +\catcode044 12 % , +\def\do#1=#2,{% + \ifx#1\do\else + \edef\loops@restorecodes{% + \loops@restorecodes + \catcode#1=\the\catcode#1\relax + }% + \catcode#1=#2\relax + \expandafter\do + \fi +} +\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}[2013/05/15 v1.3 Loops and list processors (AM)] +\NeedsTeXFormat{LaTeX2e}[2011/06/27] + +% This is the way to load 'skeyval-for-core' here, otherwise we +% can't access some of the needed commands from 'skeyval-core': + +\@ifpackageloaded{skeyval}{}{\RequirePackage{skeyval}} + +\skvnewlet\ltxkernelfor\@for +\skvnewlet\ltxkerneltfor\@tfor + +\directkeys*{ + .every unknown option={ + \@onelevel@sanitize\CurrentOption + \PackageWarning{loops}{Unknown option '\CurrentOption' ignored} + }, + .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 +} + +% \lpsdocsvlist{}{}{} +% +% Execute on each item of . 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% + }% + }% + \skvbreakloopfalse + \skvifemptyTF\lpsuserlist{}{% + \expandafter\lps@do\lpsuserlist#1\skv@nil#1\skv@nil#1\skv@nil#1% + }% + \skvpopfunctions\lpsdocsvlist\skv@csvdepth +} + +% Remove one element from a list. Only the first occurence of the +% element will be removed. This is fast. +% +% \lpsremovefromlist{} +% +% Example: +% +% \def\x{1,2,3,4} +% \lpsremovefromlist{,}7\x +% +\skvrobustdef\lpsremovefromlist#1#2#3{% + \begingroup + \def\lps@remove@a##1\lps@nil{##1}% + \def\lps@remove@b##1\lps@nil{}% + \def\lps@remove@c##1#1#2##2\lps@nil##3\lps@nil##4\lps@nnil{% + \expandafter\endgroup##3\def#3{##1##2}\lps@nil + }% + \expandafter\lps@remove@c\expandafter#1#3\lps@nil + \lps@remove@a\lps@nil#1#2\lps@nil\lps@remove@b\lps@nil\lps@nnil +} + +% Expandable version of D.E. Knuth's \loop: +% +\skvnewdef\dekloop#1\repeat{\skv@dekloop{#1}} +\skvnewdef\skv@dekloop#1{% + #1% + \expandafter\skv@dekloop + \else + \expandafter\@gobble + \fi + {#1}% +} + +\skvnewdef\lpswhilecondition#1\do#2{% + \csname @#1firstofone\else gobble\fi\endcsname + {#2\lpswhilecondition{#1}\do{#2}}% +} + +% A version of D.E. Knuth's \loop that can be nested. +% Credit: David P. Carlisle. +% +% \carlisleloop\a +% \carlisleloop\b +% ... +% \if... +% \repeat\b +% ... +% \if... +% \repeat\a +% +\let\repeat\fi +\skvrobustdef*\carlisleloop#1{% + \long\def\skv@carlisleloop##1##2\repeat#1{% + \long\def##1{##2\relax\expandafter##1\fi}% + ##1\let##1\relax + }% + \expandafter\skv@carlisleloop + \csname skv@carlisleloop@\string#1\endcsname +} + +% A version of D.E.Knuth's \loop that can be nested naturally. +% +% 1. As a design constraint, this doesn't accept \par. +% +% 2. ak=Wilhelm Ackermann, ter=Rózsa Péter; in honour of these +% mathematicians. +% +% \akterloop +% \akterloop +% ... +% \if... +% \repeat +% ... +% \if... +% \repeat +% +\skvnewregister\toks{\skv@aktertoks} +\skvnewdef*\skv@aktercnt{0} +\skvrobustdef*\skv@akter@defloop{% + \def\skv@tempa##1##2##3{% + \def\skv@tempa{##1}% + \def\skv@tempb{##2}% + \let##2\fi + \gdef##1####1##2{% + \def##3{####1\relax\expandafter##3\fi}% + ##3\let##3\relax + }% + }% + \def\x##1{% + \skvnoexpandcs{skv@akter@##1@\skvrom\skv@aktercnt}% + }% + \edef\x{\x{loop}\x{repeat}\x{iterate}}% + \expandafter\skv@tempa\x +} +\skvrobustdef*\akterloop{% + \begingroup + \everyeof{EOF}\def\skv@aktercnt{0}% + \skv@aktertoks{\dekloop}% + \skv@akterpush +} +\skvrobustdef*\skv@akterpush{\futurelet\next\skv@akterpush@a} +% Use star variant of \skvrobustdef here, to catch \par: +\skvrobustdef*\skv@akterpush@a#1{% + \skvifntypeTF{#1}{% + \skvifxTF{#1}\akterloop{% + \skvadvanceno\skv@aktercnt\@ne + \skv@akter@defloop + \skv@aktertoks\expandafter + {\the\expandafter\skv@aktertoks\skv@tempa}% + \skv@akterpush + }{% + \skvifstrcmpTF{#1}\repeat{% + \skvifnumTF\skv@aktercnt=\skvz@{% + \expandafter\endgroup\the\skv@aktertoks\repeat + }{% + \skv@aktertoks\expandafter + {\the\expandafter\skv@aktertoks\skv@tempb}% + \skvadvanceno\skv@aktercnt\m@ne + \skv@akterpush + }% + }{% + \skvifxTF\next\@sptoken{% + \skv@aktertoks\expandafter + {\the\expandafter\skv@aktertoks\@space#1}% + }{% + \skv@aktertoks\expandafter{\the\skv@aktertoks#1}% + }% + \skv@akterpush + }% + }% + }{% + \skvifstrcmpTF{#1}{EOF}{% + \skv@err{'\string\repeat' not found: endless loop}\skv@ehd + }{% + \skvifxTF\next\@sptoken{% + \skv@aktertoks\expandafter + {\the\expandafter\skv@aktertoks\space{#1}}% + }{% + \skv@aktertoks\expandafter{\the\skv@aktertoks{#1}}% + }% + \skv@akterpush + }% + }% +} + +% Expandable comma loop. List is not normalized prior to parsing, and +% it is not possible to terminate the loop prematurely. +% +% \lpsfor{} +% +% Example: +% +% \skvnewregister\count{\nr}\nr=\tw@ +% \def\do#1{% +% \let\noexpand#1% +% \expandafter\noexpand\csname\skvremovescape{#1}@% +% \romannumeral\nr\endcsname +% } +% \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,} +\skvnewdef\skv@for@a#1#2,{% + \skvifblankTF{#2}{% + \skv@for@a{#1}% + }{% + \skvifstrcmpTF{#2}\skv@for@nil{}{#1{#2}\skv@for@a{#1}}% + }% +} +\skvnewlet\lpsfor\skvfor +% Process non-separated (token-wise) list. \ayeloop is like \skvtfor +% but uses parameter characters directly, instead of a holder macro. +% +% \ayeloop{}\do{<1.parameter.callback>} +% \ayeloop*{}\do{<1.parameter.callback>} +% +% \ayeloop abcd\do{% +% \def\nr{0}% +% \ayeloop 12345\do{% +% \typeout{Doing #1--##1}% +% \skvpushnumber\nr +% \ifnum\nr>3\relax\skvbreakloop\fi +% }% +% }% +% +\skvrobustdef*\ayeloop{\skv@testst\skv@ayeloop} +\skvrobustdef*\skv@ayeloop#1\do#2{% + \skv@usetempst{#1}\skv@tempa + \skvsavestate\ayeloop{\do\skv@ayeloop}\skv@csvdepth + \def\skv@ayeloop##1{% + \skvifstrcmpTF{##1}\skv@tfor@nil{% + \skvbreakloopfalse + }{% + #2\relax + \ifskvbreakloop + \skvbreakloopfalse + \begingroup + \def\skv@ayeloop####1\skv@tfor@nil{% + \endgroup + \edef\skvremainder{\unexpanded{####1}}% + }% + \fi + \skv@ayeloop + }% + }% + \skvbreakloopfalse + \expandafter\skv@ayeloop\skv@tempa\skv@tfor@nil + \skvrestorestate\ayeloop\skv@csvdepth +} + +% Robust, outer-brace-preserving, multi-level, general-purpose +% non-separated values list (nsv/tsv) processor. +% +% \sifakaloop{}{<1.parameter.callback>} +% \sifakaloop*{}{<1.parameter.callback>} +% +\skvnewdef*\skv@tsvnil{\skv@tsvnil} +\skvrobustdef*\sifakaloop{\skv@testst\skv@sifakaparse@a} +\skvrobustdef*\skv@sifakaparse@a#1#2{% + \skv@usetempst{#1}\skv@sifakaarg + \skvsavestate\sifakaloop{\do\skv@user@do}\skv@csvdepth + \def\skv@user@do##1{#2}% + \edef\skv@sifakaarg{% + \expandafter\skvtsvnormalize\expandafter{\skv@sifakaarg}% + }% + \skvbreakloopfalse + \skvifemptyTF\skv@sifakaarg{% + \ifskvprocessempty\skv@user@do{}\fi + }{% + \expandafter\skv@sifakaparse@b\skv@sifakaarg\skv@tsvnil + }% + \skvrestorestate\sifakaloop\skv@csvdepth + \ifnum\skv@csvdepth=\skvz@\skvundef\skv@user@do\fi +} +\skvrobustdef*\skv@sifakaparse@b{% + \begingroup + \let\bgroup\relax + \skvifnextchar\skv@orig@bgroup{% + \let\skv@next\skv@orig@bgroup + \skv@sifakaparse@c + }{% + \let\skv@next\relax + \skv@sifakaparse@c + }% +} +\skvrobustdef*\skv@sifakaparse@c#1{% + \skvifxTF\skv@next\skv@orig@bgroup{% + \endgroup + \edef\skv@sifakaarg{{\unexpanded{#1}}}% + }{% + \endgroup + \edef\skv@sifakaarg{\unexpanded{#1}}% + }% + \skvifxTF\skv@sifakaarg\skv@tsvnil{% + \skvbreakloopfalse + }{% + \skvifxTF\skv@sifakaarg\skv@listbreakertoks{% + \skvbreakloop + }{% + \skvifemptyTF\skv@sifakaarg{% + \ifskvprocessempty\skv@user@do{}\fi + }{% + \expandafter\skv@user@do\expandafter{\skv@sifakaarg}\relax + }% + \skvifdefboolTF{skvbreakloop}{% + \skvbreakloopfalse + \begingroup + \def\skv@prova##1\skv@tsvnil{% + \endgroup + \edef\skvremainder{\unexpanded{##1}}% + }% + \skv@prova + }{% + \skv@sifakaparse@b + }% + }% + }% +} + +% Processing both csv and tsv/nsv lists with \foreachfox. +% +% \foreachfox[]{}{} +% \foreachfox*[]{}{} +% +% 1. The is at least a one-parameter token list. +% +% 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 . +% +% 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 . It can be defined +% outside and called within . +% +% 6. Outer braces around the list items are preserved in the parsing. +% +% 7. The following are available here, as in \newforeach: +% +% \foreachcurrentitem, \foreachnextitem, \foreachitemcount, +% \foreachprevitem, \prependtobeginforeach, \appendtobeginforeach +% (=\atbeginforeach), \prependtoendforeach, \appendtoendforeach +% (=\atendforeach), \ifforeachlastitem, \foreachnestdepth, +% \foreachlistremainder, \skvforeachonlyinitially. +% +\skvnewregisters\bool{\iflastfox} +\skvnewlet\breakforeachfox\skvbreaklooptrue +% \atbeginforeachfox[]{} +\skvnewlet\atbeginforeachfox\atbeginforeach +% \atendforeachfox[]{} +\skvnewlet\atendforeachfox\atendforeach + +% 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. +\skvquickkeys.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; + arg,args,arg pattern/##1/ + \edef\skv@foreach@paramlist{\unexpanded{#1}} + \skvstripouterbraces{1}\skv@foreach@paramlist + ; + list breaker/\foreachlistbreaker/\def\skv@listbreakertoks{#1}; + list pauser/\foreachlistpauser/\def\skv@listpausertoks{#1}; + normalize list/true/ + \edef\skv@foreach@normalizelist{0\skvifstrcmpTF{#1}{true}01} + /true,false + ; + use empty,use empty items/true/ + \edef\skv@foreach@useempty{0\skvifstrcmpTF{#1}{true}01} + /true,false + ; + .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 + ; + .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/\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 \skvautocompletelist: + .exec/\def\skv@foreach@link{\@nil}; + link/\@nil/ + \edef\skv@prova{\unexpanded{#1}} + \ifx\skv@prova\@nnil\else + \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}% + \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}10}% + /true,false + ; + grow right/true/ + \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 + % 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 + ; + expand before fill,expand list before fill/true/ + \edef\skv@foreach@expandbeforefill{0\skvifstrcmpTF{true}{#1}01}% + /true,false + ; + expand list once,*,list is a macro,macro list/true/ + \edef\skv@foreach@expandlistonce{0\skvifstrcmpTF{true}{#1}01}% + /true,false + ; + expand list twice/true/ + \edef\skv@foreach@expandlisttwice{0\skvifstrcmpTF{true}{#1}01}% + /true,false + ; + % Don't use 'expand' for the key 'expand list': + expand list,fully expand list,expand list fully/true/ + \edef\skv@foreach@expandlistfully{0\skvifstrcmpTF{true}{#1}01}% + /true,false + ; + % Eg, 'evaluate = #1 as \x using \numexpr#1*2'. + % Since the parameters haven't assumed arguments, we defer the + % call to \skv@foreachfox@parseevaluate until the arguments are known. + evaluate/\@nil/ + \skv@foreach@ifacceptkv{#1}{% + \skv@foreachfox@parseevaluate{#1}% + }% + ; + % Eg, + % 'count in = \p all #1 satisfying \ifnum#1>4\fi initially 2' + % 'count in = \p all #1 satisfying \ifnum#1>4\fi' + count in,count/\@nil/ + \skv@foreach@ifacceptkv{#1}{% + \skv@foreachfox@parsecountin{#1}% + }% + ; + % Eg, remember=#1 as \y initially A + remember/\@nil/ + \skv@foreach@ifacceptkv{#1}{% + \skv@foreachfox@parseremember{#1}% + }% + ; + reverse list,reverse,reflect/true/ + \edef\skv@foreach@reverselist{0\skvifstrcmpTF{true}{#1}01}% + /true,false + ; +} +\skvquickkeys.preset{loops/foreachfox}{% + parser={,},list type=csv,arg=#1,loop stopper, + list breaker=\foreachlistbreaker,list pauser=\foreachlistpauser, + 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, +} + +% Parser for 'evaluate' key: +% +% Eg, 'evaluate = #1 as \x using \numexpr#1*2'. +% +% \skv@foreachfox@parseevaluate differs from \skv@foreach@parseevaluate +% because #1 here is likely to be a non-macro. +% +\skvrobustdef*\skv@foreachfox@parseevaluate#1{% + \begingroup + \def\skv@tempxifin##1##2{% + \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% + }% + \def\skv@tempd{}% + % #3 can be empty. So we don't test for its emptiness here. + \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': + \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'}\skv@ehd + \else + \expandafter\skvifescapedTF\expandafter{\skv@provb}{}{% + \skv@err{Value of key 'evaluate': receiving macro + \MessageBreak \skvoxdetok\skv@provb not escaped}\skv@ehd + }% + \fi + \ifx\skv@provc\@empty + \skv@err{Value of key 'evaluate' has no formula}\skv@ehd + \fi + \skv@tempxifin{\pgfmathparse}{##3}{% + \def\skv@tempc####1\pgfmathparse####2\skv@nil{% + \ifx\@nnil####1\@nnil + \ifdefined\pgfmathparse + \skv@foreach@swatrue + \else + \skv@err{\noexpand\pgfmathparse isn't defined; + \MessageBreak maybe 'pgfmath' isn't loaded}\skv@ehd + \fi + \else + \skv@err{Invalid token \detokenize{####1} + \MessageBreak before \string\pgfmathparse}\skv@ehd + \fi + }% + \expandafter\skv@tempc\skv@provc\skv@nil + }{% + \skv@foreach@swafalse + \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: 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: + \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 + \MessageBreak quantity to evaluate}\skv@ehd + \else + \ifx\@nnil##2% + \skv@err{Value of key 'evaluate' has no receiving macro}\skv@ehd + \else + \skv@tempa##1as##2using##1\skv@nil + \fi + \fi + }% + \skv@tempb#1{\@nnil}\skv@nil + }{% + % 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'}\skv@ehd + }% + }% + \skv@foreach@addtocallback{pre}{% + \ifskv@foreach@swa + % Here, may have the syntax \pgfmathparse{}. + \skvexpandonce\skv@provc + \let\skvexpandonce\skv@provb\noexpand\pgfmathresult + \else + % Here, may have the syntax \numexpr\x*2 or \dimexpr\x*2. + \edef\skvexpandonce\skv@provb{% + \ifskv@foreach@swb\noexpand\the\fi + \skvexpandonce\skv@provc\skvexpandonce\skv@tempd + }% + \fi + }% + \skvaftergroupdef\skv@foreach@precallback\endgroup +} + +% Eg, 'count in \y all #1 satisfying \ifnum#1>2\fi initially 0'. +% +% 1. must be a balanced and valid TeX or LaTeX (2-fork) +% 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 from 2] in {a,...,e}'. +% +% 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: +% +% \ifforeachlastitem\typeout{Processing last entry of the list} \fi +% +\skvrobustdef*\skv@foreachfox@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}{}{% + \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 quantity to test. The quantity, + % on its own, isn't sufficient to conduct a test: + \let\skv@foreach@itemcounter\skv@prova + \else + % If there isn't a quantity to test, then no test is possible: + \ifx\skv@provb\@empty\else + \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\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' and 'satisfying': #1 should be only the counter macro: + \ifx\@nnil#1\@nnil + \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}\skv@ehd + }% + \fi + }% + }% + \ifskv@foreach@swa + \skv@foreach@addtocallback{pre}{% + \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@precallback + \else + \skvcmdexit\skv@foreach@itemcounter + \fi + }% +} + +% remember= as initially +% +\skvrobustdef*\skv@foreachfox@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 around '()'}\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 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'}\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': + \ifx\@nnil#1\@nnil\else + % Unlike in \newforeach, we can't create an automatic retainer + % macro here, since \foreachfox uses parameters instead of + % holder macros. + \skv@err{Value of key 'remember' is incomplete: no 'as'}\skv@ehd + \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}{% + \edef\skvexpandonce\skv@provb{% + \noexpand\unexpanded{\skvexpandonce\skv@prova}% + }% + }% + \fi + \skvexpanded{\endgroup + \ifskv@foreach@swa + \skvcmdexit\skv@foreach@precallback + \skvcmdexit\skv@foreach@postcallback + \fi + }% +} + +\skvnewdef*\skv@foreachfox@kvlist{} +% \setupforeachfox{} +\skvrobustdef*\setupforeachfox#1{% + \skvifblankTF{#1}{}{% + \skvaddtolist\skv@foreachfox@kvlist{#1}% + }% +} +\skvrobustdef*\skv@foreachfox@setkeys#1{% + \def\reserved@a{\skvquickkeys.set{loops/foreachfox}}% + \expandafter\reserved@a\expandafter{\skv@foreachfox@kvlist,#1}% +} +\skvrobustdef*\foreachfox{% + \skv@inforeachtrue + \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@starform{0\ifskv@tempst0\else1\fi}% + \skv@foreach@pushstate + \skv@foreach@latehookerr + \def\foreachitemcount{0}% + \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@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}% + \skvifmacroFT{#2}{}{% + \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 \noexpand\foreachfox + \MessageBreak or use the key 'expand list once' + \MessageBreak or 'expand list twice' or 'list is a macro', etc}% + \fi + }% + \fi + \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}% + }% + \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 + \noexpand\ifnum\noexpand\foreachitemcount=\@ne + \skvexpandonce\skv@foreach@onlyinitially + \noexpand\fi + \fi + \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 + }% + }% + \edef\reserved@b{% + \def\noexpand\skv@foreach@callback\skvexpandonce + \skv@foreach@paramlist\noexpand\foreacheov + }% + \expandafter\reserved@b\expandafter{\reserved@a}% + \skvxifstrcmpTF\skv@foreach@listtype{csv}{% + \def\skv@foreach@lookahead@a##1{% + \def\skv@foreach@picknext{##1.}% + \futurelet\skv@foreach@next\skv@foreach@lookahead@b + }% + \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@picknext##1% + \futurelet\skv@foreach@next\skv@foreach@lookahead@b + }% + % 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[{% + \skv@foreach@parenthesistrue\skv@foreach@lookahead@c + }{% + \skvifxTF\skv@foreach@next({% + \skv@foreach@parenthesistrue\skv@foreach@lookahead@d + }{% + \skv@foreach@parenthesisfalse\skv@foreach@picknext + }% + }% + }% + \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@a####1##1####2\skv@foreach@stop{% + \edef\foreachcurrentitem{\skvexpandonce{\@gobble####1}}% + \skv@foreachfox@b{##1}{####2}{csv}% + }% + \skvifemptyTF\skv@foreach@userlist{}{% + \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. + 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 + \expandafter\skv@foreach@doreverselist\expandafter + {\skv@foreach@parser}\skv@foreach@userlist + \fi + }% + % 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\skvafterfi + \edef\skv@foreach@userlist{% + \skvexpbracenext\skvtsvnormalize\skv@foreach@userlist + }% + \fi + \def\skv@foreach@do@a{% + \let\bgroup\relax + \futurelet\skv@foreach@next\skv@foreach@do@b + }% + \def\skv@foreach@do@b####1####2\skv@foreach@stop{% + \let\bgroup\skv@orig@bgroup + \ifskv@foreach@parenthesis + \edef\foreachcurrentitem{\unexpanded{####1}}% + \else + \skvifxTF\skv@foreach@next\bgroup{% + \edef\foreachcurrentitem{{\unexpanded{####1}}}% + }{% + \edef\foreachcurrentitem{\unexpanded{####1}}% + }% + \fi + \skv@foreachfox@b{}{####2}{tsv}% + }% + \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\foreachnestdepth}% + \skv@foreach@popstate + \skv@inforeachfalse +} +% \skv@setupgetnextfox +\skvrobustdef*\skv@setupgetnextfox#1{% + \skvxifstrcmpTF\skv@foreach@listtype{csv}{% + \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{% + \let\bgroup\relax + \futurelet\skv@foreach@next\skv@foreach@g@tnext + }% + \def\skv@foreach@g@tnext##1##2\skv@foreach@stop{% + \let\bgroup\skv@orig@bgroup + \ifskv@foreach@parenthesis + \edef\foreachnextitem{\unexpanded{##1}}% + \else + \skvifxTF\skv@foreach@next\bgroup{% + \edef\foreachnextitem{{\unexpanded{##1}}}% + }{% + \edef\foreachnextitem{\unexpanded{##1}}% + }% + \fi + }% + }% +} +% \skv@foreachfox@b +\skvrobustdef*\skv@foreachfox@b#1#2#3{% + \skvifxTF\foreachcurrentitem\skv@foreach@nnil{% + \skvbreakloopfalse\foreachlastitemfalse\lastfoxfalse + }{% + \skvifxTF\foreachcurrentitem\skv@listbreakertoks{% + \skv@foreachfox@getrm{#1}{#2}% + }{% + \skvifxTF\foreachcurrentitem\skv@listpausertoks{% + \message{^^J! List pause: + ^^JType x or X to quit, or to proceed^^J}% + \bgroup\endlinechar\m@ne\global\read-1 to\@gtempa\egroup + \skvexpandarg\lowercase{\def\noexpand\@gtempa{\@gtempa}}% + \skvxifstrcmpTF\@gtempa{x}{% + \skv@foreachfox@getrm{#1}{#2}% + }{% + \skv@foreachfox@c{#1}{#2}{#3}% + }% + }{% + \skv@foreachfox@c{#1}{#2}{#3}% + }% + }% + }% +} +% \skv@foreachfox@c +\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}% + \ifx\skv@foreach@itemcounter\@empty\else + \expandafter\let\skv@foreach@itemcounter\foreachitemcount + \fi + \skvifemptyTF\foreachcurrentitem{% + \if\skv@foreach@useempty\skvafterfi + \skv@foreach@callback\foreacheov + \fi + }{% + % Test for \foreachlistpauser, in case the user decides to continue + % after \foreachlistpauser has been picked: + \skvifxTF\foreachcurrentitem\skv@listpausertoks{}{% + \skvifxTF\skv@foreach@paramlist\skv@simplearg{% + \skvexpbracenext\skv@foreach@callback\foreachcurrentitem\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 + }% + }% + \ifx\skv@foreach@processupto\@empty\else + \ifnum\foreachitemcount<\skv@foreach@processupto\relax\else + \skvbreakloop + \fi + \fi + \skvifdefboolTF{skvbreakloop}{% + \ifbreakallforeachloops\else + \skvbreakloopfalse + \fi + \foreachlastitemfalse\lastfoxfalse + \skv@foreachfox@getrm{#1}{#2}% + }{% + \skv@foreach@lookahead@a\skv@foreach@do@a#2\skv@foreach@stop + }% +} +% \skv@foreachfox@getrm +\skvrobustdef*\skv@foreachfox@getrm#1#2{% + \begingroup + \def\reserved@a##1\skv@foreach@nil#1{% + \endgroup + \edef\foreachlistremainder{\unexpanded{##1}}% + }% + \reserved@a#2% +} + +% \cicadaloop[]{}<\if...>\fi{<1.parameter.code>} +% \cicadaloop*[]{}<\if...>\fi{<1.parameter.code>} +% +% 1. When the conditional <\if...> isn't true, the regular code +% will be executed for every member of the list. +% 3. \ifskvbreakloop may be used as the conditional in <\if...>. +% 5. The boolean \iflastcicada is available for accessing the last item +% of the list. There are also the macros \currentcicada, \lastcicada, +% \cicadacount, and the counter \cicadanestdepth. +% 6. \cicadaloop can be nested. +% +% Example: +% +% \let\romn\romannumeral +% \@tempcnta\z@ +% \def\blist{{X};{Y};Z;\fi} +% \def\stack{} +% \cicadaloop{{a},{b},c,\if}\if01\fi{% +% \advance\@tempcnta\@ne +% \@tempcntb\z@ +% \@tempswafalse +% \cicadaloop*[;]\blist\if@tempswa\fi{% +% \advance\@tempcntb\@ne +% \typeout{Doing \romn\@tempcnta,\romn\@tempcntb: \detokenize{#1,##1}}% +% \edef\stack{% +% \unexpanded\expandafter{\stack}\noexpand\do +% {\romn\@tempcnta,\romn\@tempcntb}{\unexpanded{#1;##1}}% +% }% +% \ifnum\@tempcntb>\@ne +% \@tempswatrue +% \skvcsedef{cmd@\romn\cicadanestdepth}{\lastcicada,\cicadacount}% +% \fi +% }% +% } +% \show\stack +% +\skvnewregisters\bool{\iflastcicada} +\skvbuildmacrostack\skv@cicada@state{% + \do\skv@cicada@do\do\skv@cicada@userlist\do\currentcicada + \do\nextcicada\do\cicadacount\do\lastcicada\do\skv@cicada@callback + \do\skv@cicada@getnext\do\ifskvprocessempty +}\skv@stackdepthlimit + +\skvnewnumbers{cicadaloopdepth} +\skvnewlet\skv@cicada@nil\relax +\skvnewdef*\skv@cicada@nnil{\skv@cicada@nil} +\skvnewlet\breakcicada\skvbreakloop + +\skvrobustdef*\cicadaloop{\skv@teststopt\skv@cicadaloop,} +\skvrobustdef*\skv@cicadaloop[#1]#2#3\fi#4{% + \let\if@cicada@st\ifskv@tempst + \skvpushstate\skv@cicada@state\cicadanestdepth + \let\ifskv@tempst\if@cicada@st + \skv@usetempst{#2}\skv@cicada@userlist + \skv@foreach@normalize[#1]\skv@cicada@userlist + \def\skv@cicada@callback##1{#4}% + \def\lastcicada{}% + \def\skv@cicada@getnext##1#1##2\skv@cicada@stop{% + \edef\nextcicada{\skvexpandonce{\@gobble##1}}% + \ifx\nextcicada\skv@cicada@nnil + \lastcicadatrue + \def\nextcicada{}% + \fi + }% + \chardef\cicadacount\skvz@ + \def\skv@cicada@do##1#1##2\skv@cicada@stop{% + \edef\currentcicada{\skvexpandonce{\@gobble##1}}% + \skvifxTF\currentcicada\skv@cicada@nnil{% + \skvbreakloopfalse\lastcicadafalse + }{% + \skvifxTF\currentcicada\skv@listbreakertoks{% + \skvbreakloopfalse\lastcicadafalse + }{% + \edef\cicadacount{\the\numexpr\cicadacount+1}% + \skv@cicada@lookahead@a\skv@cicada@getnext##2\skv@cicada@stop + \skvexpandbracenext\skv@cicada@callback\currentcicada\relax + \skvifcondFT#3\fi{}\skvbreakloop + \skvifdefboolTF{skvbreakloop}{% + \skvbreakloopfalse\lastcicadafalse + \begingroup + \def\skv@prova####1\skv@cicada@nil#1{% + \endgroup + \edef\skvremainder{\unexpanded{####1}}% + }% + \skv@prova##2% + }{% + \let\lastcicada\currentcicada + \skv@cicada@lookahead@a\skv@cicada@do##2\skv@cicada@stop + }% + }% + }% + }% + \def\skv@cicada@lookahead@a##1{% + \def\skv@cicada@picknext{##1.}% + \futurelet\skv@next\skv@cicada@lookahead@b + }% + \def\skv@cicada@lookahead@b{% + \ifx\skv@next[% + \expandafter\skv@cicada@lookahead@c + \else + \ifx\skv@next(% + \expandafter\expandafter\expandafter\skv@cicada@lookahead@d + \else + \expandafter\expandafter\expandafter\skv@cicada@picknext + \fi + \fi + }% + \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@a\skv@cicada@do}% + \skv@cicada@userlist#1\skv@cicada@nil#1\skv@cicada@stop + }% + \skvpopstate\skv@cicada@state\cicadanestdepth +} + +% \cicadiloop[]{}<\if...>\fi{}{<1.parameter.code>} +% \cicadiloop*[]{}<\if...>\fi{}{<1.parameter.code>} +% +% 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. 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{% + \skvexpandsecond + {#4\relax\skv@cicadiloop}{\ifskv@tempst*\fi}% + [#1]{#2}#3\fi +} + +% Change the list separator of a given list. +% +% \lpschangelistseparator +% {}{}{}{} +% +% Example: +% \def\alist{{a/1,a/2};b;c} +% \lpschangelistseparator{;}\alist{,}\blist +% +\skvrobustdef*\lpschangelistseparator#1#2#3#4{% + \def#4{}% + \cicadaloop*[#1]{#2}\if01\fi{% + \edef#4{% + \skvexpandonce#4{\unexpanded{##1}}% + \iflastcicada\else#3\fi + }% + }% +} + +% Declare a list normalizer command for an arbitrary parser. +% +% \lpsdeclarelistnormalizer{} +% +% Example: +% +% \lpsdeclarelistnormalizer\lpscommanormalize{,} +% +% \lpscommanormalize is defined later. +% +\skvrobustdef*\lpsdeclarelistnormalizer#1#2{% + \skvifescapedTF{#1}{}{% + \skv@err{Token \detokenize{#1} isn't escaped}\skv@ehd + }% + \def\reserved@a{\lps@declarelistnormalizer{#1}}% + \expandafter\reserved@a\expandafter{\string#2}% +} +\skvrobustdef*\lps@declarelistnormalizer#1#2{% + \begingroup + \lccode`\~=`#2 % + \lowercase{\endgroup + \skvnewdef#1##1{% + \unexpanded\expandafter{\romannumeral-`\q + \skvcsuse{\skvremovescape#1@activeparser}#2##1#2~\normal@nil}% + }% + \long\skvcsdef{\skvremovescape#1@activeparser}##1~##2\normal@nil{% + \skvifblankTF{##2} + {\skvcsuse{\skvremovescape#1@spaceparser}##1 #2\normal@nil} + {\skvcsuse{\skvremovescape#1@activeparser}##1#2##2\normal@nil}% + }% + }% + \long\skvcsdef{\skvremovescape#1@spaceparser}##1 #2##2\normal@nil{% + \skvifblankTF{##2} + {\skvcsuse{\skvremovescape#1@parserspace}##1#2 \normal@nil} + {\skvcsuse{\skvremovescape#1@spaceparser}##1#2##2\normal@nil}% + }% + \long\skvcsdef{\skvremovescape#1@parserspace}##1#2 ##2\normal@nil{% + \skvifblankTF{##2} + {\skvcsuse{\skvremovescape#1@doubleparser}##1#2#2\normal@nil} + {\skvcsuse{\skvremovescape#1@parserspace}##1#2##2\normal@nil}% + }% + \long\skvcsdef{\skvremovescape#1@doubleparser}##1#2#2##2\normal@nil{% + \skvifblankTF{##2} + {\skvifblankTF{##1}{}{\expandafter\expandafter\expandafter + \space\expandafter\noexpand\@gobble##1}}% + {\skvcsuse{\skvremovescape#1@doubleparser}##1#2##2\normal@nil}% + }% +} + +\lpsdeclarelistnormalizer\lpscommanormalize{,} +\lpsdeclarelistnormalizer\lpsslashnormalize{/} + +% Declare an expandable csv list parser. No premature stopping of the loop +% is possible by this scheme. To use this scheme, first do +% +% \lpsdeclareexpandablelistparser{} +% \def{<1-parameter callback>} +% +% and then call +% +% or * +% +% or will be normalized before being parsed. +% +% Example: +% +% \lpsdeclareexpandablelistparser\myloop\do{,} +% +% \def\x{a,\if,b} +% \def\do#1{\unexpanded{{#1}}} +% \edef\x{\myloop*\x} +% +\skvrobustdef*\lpsdeclareexpandablelistparser#1#2#3{% + % No need to save the processor.cmd and processor.function in a list. + \skvaftercs\lpsdeclarelistnormalizer{\skvremovescape#1@normalizer}{#3}% + \begingroup + \let\x\skvnoexpandcs + \skvexpanded{\endgroup + \skvnewdef*\noexpand#1{% + \noexpand\skvxifnextchar*% + {\x{lps@parse@\skvremovescape#1@a}{\noexpand\@firstoftwo}} + {\x{lps@parse@\skvremovescape#1@a}{\noexpand\@secondoftwo}}% + }% + \def\x{lps@parse@\skvremovescape#1@a}####1####2{% + \noexpand\expandafter\x{lps@parse@\skvremovescape#1@b}% + \unexpanded{\romannumeral-`\q}####1{% + \noexpand\expandafter\x{\skvremovescape#1@normalizer}% + \noexpand\expandafter{####2}% + }{% + \x{\skvremovescape#1@normalizer}{####2}% + }% + #3\noexpand#1#3% + }% + \def\x{lps@parse@\skvremovescape#1@b}####1#3{% + \noexpand\skvifxTF{\noexpand#1}{####1}% + {}{\noexpand#2{####1}\x{lps@parse@\skvremovescape#1@b}}% + }% + }% +} +% 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 +% +% +% +% +\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 + \ifx\@let@token g\let\@next=\tikz@g@char\else + \ifx\@let@token s\let\@next=\tikz@schar\else + \ifx\@let@token |\let\@next=\tikz@vh@lineto\else + \ifx\@let@token p\let\@next=\tikz@pchar\pgfsetmovetofirstplotpoint + \else\ifx\@let@token t\let\@next=\tikz@to\else + \ifx\@let@token\pgfextra\let\@next=\tikz@extra\else + \ifx\@let@token\foreach\let\@next=\tikz@foreach\else + \ifx\@let@token\newforeach\let\@next=\tikz@foreach\else + \ifx\@let@token\pgf@stop\let\@next=\relax\else + \ifx\@let@token\par\let\@next=\tikz@scan@next@command\else + \ifx\@let@token d\let\@next=\tikz@decoration\else + \ifx\@let@token l\let\@next=\tikz@l@char\else + \let\@next=\tikz@expand\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \fi\fi\fi\fi\@next + }% +} + +\loops@restorecodes +\endinput -- cgit v1.2.3