4

I am trying to make this loop work:

\foreach \name/\col in {first/{204, 0, 0},%
                       second/{0, 102, 0},%
                        third/{0, 0, 153}}{%
    \definecolor{\name}{RGB}{\col} % buggish line
    \expandafter\xdef\csname\name\endcsname##1{\noexpand\textcolor{\name}{##1}}
    % + more convenience utilities..
}

.. but the colors seems not to be defined, since I get

! Package xcolor Error: Undefined color `first'.

When I try to use them. I have try to fiddle-faddle with many combinations of \expandafter, \noexpand, \relax etc. with no success and no real strategy. What is the reasoning to get them right?

In the end, I expect:

here is a \first{custom}-\second{colored} \third{text}

to produce:

enter image description here

0

2 Answers 2

7

For the same reason you need \xdef, you need \xglobal\definecolor (section 2.5.5 in the manual of xcolor).

\documentclass{article}
\usepackage{xcolor,pgffor}

\foreach \name/\col in {%
  first/{204, 0, 0},%
  second/{0, 102, 0},%
  third/{0, 0, 153}%
}{%
  \xglobal\definecolor{\name}{RGB}{\col} % buggish line
  \expandafter\xdef\csname\name\endcsname##1{\noexpand\textcolor{\name}{##1}}
  % + more convenience utilities..
}

\begin{document}

here is a \first{custom}-\second{colored} \third{text}

\end{document}

enter image description here

I'd be wary about using such an approach, because you risk to overwrite commands, with possibly disastrous effects.

Here's code that's free of that problem (colors are silently overridden, though):

\documentclass{article}
\usepackage{xcolor,xparse}

\ExplSyntaxOn
\NewDocumentCommand{\definebunchofcolors}{m}
 {
  \clist_map_inline:nn { #1 }
   {
    \iagolito_define_color:n { ##1 }
   }
 }
\cs_new_protected:Nn \iagolito_define_color:n
 {
  \__iagolito_define_color_aux:nn #1
 }
\cs_new_protected:Nn \__iagolito_define_color_aux:nn
 {
  \definecolor{#1}{RGB}{#2}
  \cs_new:cpn { #1 } ##1 { \textcolor{#1}{##1} }
 }
\ExplSyntaxOff

\definebunchofcolors{
  {first}{204, 0, 0},
  {second}{0, 102, 0},
  {third}{0, 0, 153}
}

\begin{document}

here is a \first{custom}-\second{colored} \third{text}

\end{document}

However, you don't gain much with this approach: it's simpler to do one declaration at a time.

\documentclass{article}
\usepackage{xcolor,xparse}

\ExplSyntaxOn
\NewDocumentCommand{\setupcolor}{mO{RGB}m}
 {
  \definecolor{#1}{#2}{#3}
  \cs_new:cpn { #1 } ##1 { \textcolor{#1}{##1} }
 }
\ExplSyntaxOff

\setupcolor{first}{204, 0, 0}
\setupcolor{second}{0, 102, 0}
\setupcolor{third}[rgb]{0, 0, 0.6}

\begin{document}

here is a \first{custom}-\second{colored} \third{text}

\end{document}
1
  • Neat, clear and perfect. Cheers :)
    – iago-lito
    Mar 26, 2017 at 20:05
9

Definitions in a \foreach loop are local (unless made global), so the definitions of the colors with \definecolor are unknown outside, in particular when you try to access them with your \textcolor command.

Why do you use a loop? I see no advantage of \foreach \x in {a,b,c} {\dosomething{\x}} over \dosomething{a}\dosomething{b}\dosomething{c}.

\documentclass{article}
\usepackage{xcolor}
\newcommand\newcolor[2]%
  {\definecolor{#1}{RGB}{#2}%
   \expandafter\newcommand\csname#1\endcsname[1]{\textcolor{#1}{##1}}%
   % + more convenience utilities..
  }
\newcolor{first}{204, 0, 0}
\newcolor{second}{0, 102, 0}
\newcolor{third}{0, 0, 153}
\begin{document}
here is a \first{custom}-\second{colored} \third{text}
\end{document}
2
  • Yaï! This is much, much neater indeed. Cheers for that :)
    – iago-lito
    Mar 26, 2017 at 12:20
  • One (very very slight) downside: I need to define a new command and pick up a name for it, whereas I do not need that with a \foreach loop. However, I like the way it is much more easy to deal with \csname etc. with your strategy. I will accept egreg's answer because it is closer from OP, but I'll still use your solution in this case :) Thanks again!
    – iago-lito
    Mar 26, 2017 at 20:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .