I'm using TeXShop 5.0.4 and encountering a cryptic error
! Incomplete \iffalse; all text was ignored after line 15.
<inserted text>
\fi
where my code contains no explicit "if"s.
How can I create a loop that defines various commands, each of which contains its own loop?
Explanations and solutions greatly appreciated.
Small repro:
\documentclass[11pt]{article}
\usepackage{tikz}
% given input x, define \allx as a function that consumes input list qlist and operates on the elements of qlist (here, prints "x: q", but eventually some tikz command)
% This errors out with the comprehensive error
% ! Incomplete \iffalse; all text was ignored after line 15.
% <inserted text>
% \fi
\newcommand{\allcolor}[1]{\expandafter\xdef\csname all#1\endcsname##1{\foreach \q in {##1} {#1: \q}}}
% Interestingly, the \foreach seems to cause the error. If using the command below instead, which just prints "x: qlist", LaTeX is happy.
%\newcommand{\allcolor}[1]{\expandafter\xdef\csname all#1\endcsname##1{#1: ##1}}
% Reasons for pieces of the above code:
% use \xdef instead of edef to make the new function global, since \allcolor will be called in a loop, from with edef would only define the function within the loop body
% use \xdef instead of \newcommand because of other cryptic errors with \newcommand
% use \expandafter on \xdef since we first need to form the name of the new function, "\all#1", via \csname
% given input list {x,y,z}, call \allcolor on each one, to define \allx \ally and \allz
\newcommand{\allcolors}[1]{\foreach \color in {#1} {\allcolor{\color}}}
\allcolors{orange}
\begin{document}
\allorange{ha,haa}
\end{document}
Edit: the eventual goal is to define \allorange, \allbrown, (with the ability to easily add other color commands), that each process a list of coordinate pairs, and plot points of that color within tikz.
Using egreg
's answer, I was able to do so, with the following code:
\documentclass[11pt]{article}
\usepackage{tikz}
\edef\getxnow(#1,#2){#1}
\edef\getynow(#1,#2){#2}
\newcommand*{\getx}[1]{\expandafter\getxnow#1}
\newcommand*{\gety}[1]{\expandafter\getynow#1}
\newcommand{\allcolor}[1]{%
\expandafter\gdef\csname all#1\endcsname##1{%
\foreach \pt in {##1} {\node at (\getx{\pt}, \gety{\pt})[circle, fill, inner sep=5pt, #1]{};}%
}%
}
\newcommand{\allcolors}[1]{\foreach \r in {#1} {\expandafter\allcolor\expandafter{\r}}}
% Define \allorange and \allbrown which create points of those colors
\allcolors{orange, brown}
\begin{document}
\begin{tikzpicture} {
\allorange{(0,1),(1,2),(2,3)}
\allbrown{(1,1),(2,2),(3,3)}
} \end{tikzpicture}
\end{document}
Notes for commenters:
- In the original code, I did not think anything of my local loop variable name
\color
- it was an arbitrary name, and any other name will do - It seems that
\xdef
tends to break stuff, while\gdef
ends up working. I can see from What are the differences between \def, \edef, \gdef and \xdef? that\xdef = \global\edef
expands replacement text at definition time, whilegdef = \global\def
doesn't. I'm not familiar of the inner workings of TeX replacement, so an explanation of why one succeeds while the other fails would help casual users' understanding.
Resources consulted:
- What is the difference between \def and \newcommand?
- What are the differences between \def, \edef, \gdef and \xdef?
- Undefined control sequence when using \edef with \foreach
- https://tikz.dev/pgffor
- Alternative to `foreach` loop to use an `edef`
- this comes the closest to some answer, but the solution posted there is for that specific question, and didn't have enough explanation for me to understand how to use
expl3
for any other use case
- this comes the closest to some answer, but the solution posted there is for that specific question, and didn't have enough explanation for me to understand how to use
- Defining new commands inside a for loop
- \foreach with \newcommand how to use them together?
\foreach
does assignments so can not possibly work.\foreach \color
will over-write the standard\color
command, Can you say in words what you want\allcolors{orange}
and\allorange{ha,haa}
to do?\color
is not needed inside the\foreach
-code it'll not hurt because of the implicit groups. Though it is still a bad idea.\gdef
instead of\xdef
.