3

I am trying to define a colour (using the xcolor package) where the colour is provided by a macro in hex HTML format. I have a macro \colorGet{#1}{#2} which takes two arguments and returns the colour in hex format, which I would like to pass to the \definecolor macro.

Unfortunately, my naïve approach of simply passing one macro as the argument of the other doesn't work, and I understand this is because of the order in which LaTeX expands the macros. However, I don't understand how to ensure they are expanded in the correct order. I have attempted to modify this answer by Heiko Oberdiek to a similar question, but was unsuccessful. I don't understand \expandafter enough to know where I'm going wrong. A minimal (non-)working example of my attempt is below.

\documentclass{article}
%
\usepackage{xcolor}
%
\newcommand{\colorGet}[2]{D3523C} % A macro which returns a different hex-code for each combination of arguments, simplified for this example.
\newcommand{\colordefine}[2]{%
    \expandafter\colordefineAux#2{#1}%
}
\newcommand{\colordefineAux}[2]{%
    \definecolor{#2}{HTML}{#1}%
}
%
\begin{document}
    \colordefine{mycolor}{\colorGet{SchemeName}{ColourName}}
\end{document}

Attempting to compile this gives the following error:

! Argument of \xs_newmacro_ has an extra }.
<inserted text>
                \par
l.14 ...rdefine{Accent2}{\colorGet{Bold}{Accent2}}

Is there a relatively simple way to do this?

EDIT: As highlighted by Phelype Oleinik, the error message above is caused by the xstring package, which was used in the original definition of \colorGet. Since asking the question, I've realised that the xstring package isn't needed.

3
  • 2
    Welcome to TeX.SX! The error message you show seems to be from the xstring package, which you don't load in your example code. The code from the post can be adapted to work, but the solution will not work with xstring, so please provide a complete example. (A side note: Heiko's answer works because the second argument of \colordefine is a single token, so \expandafter works: yours are several tokens, so you need another approach). Jun 30, 2020 at 13:11
  • Thank you, you're quite right, the actual \colorGet macro uses the xstring package for its \IfStrEqCase macro, but I've since realised that it's not actually necessary, and I've edited the question accordingly.
    – pbc
    Jun 30, 2020 at 13:44
  • @pbc The simplification makes this into an XY-question and with little sense in it, I'm afraid.
    – egreg
    Jun 30, 2020 at 14:19

2 Answers 2

4

For the MWE as given it is sufficient to first expand the \colorGet macro into a temporary command and then use that as argument for \definecolor. The solution may need to be expanded (pun intended...) if xstring is used for the \colorGet macro.

\documentclass{article}
\usepackage{xcolor}

\newcommand{\colorGet}[2]{D3523C} % A macro which returns a different hex-code for each combination of arguments, simplified for this example.
\newcommand{\colordefine}[2]{%
    \edef\tmpcolor{#2}%
    \definecolor{#1}{HTML}{\tmpcolor}%
}

\begin{document}
    \colordefine{mycolor}{\colorGet{SchemeName}{ColourName}}
    \textcolor{mycolor}{colored text}
\end{document}
0
1

With

\documentclass{article}
%
\usepackage{xcolor}
%
\newcommand{\colorGet}[2]{D3523C} % A macro which returns a different hex-code for each combination of arguments, simplified for this example.
\newcommand{\colordefine}[2]{%
    \expandafter\colordefineAux#2{#1}%
}
\newcommand{\colordefineAux}[2]{%
    \definecolor{#2}{HTML}{#1}%
}
%
\begin{document}
    \colordefine{mycolor}{\colorGet{SchemeName}{ColourName}}
\end{document}

\colordefine{mycolor}{\colorGet{SchemeName}{ColourName}} yields:

\expandafter\colordefineAux\colorGet{SchemeName}{ColourName}{mycolor}, which in turn yields:

\colordefineAux D3523C{mycolor}, which in turn yields:

\definecolor{3}{HTML}{D}523C{mycolor}

You may have realized that probably either \colorGet should return its result nested in braces or the call to \colorGet should take place nested in braces.

In any case \colorGet must be fully expandable, i.e., may itself not yield tokens that form whatsoever temporary assignments and therefore actually are not part of the HTML-color-specification.

In order to work around this restriction I suggest \colorGet to take an (optional) argument where you can specify tokens where the result is to be appended to for further processing:

\documentclass{article}
%
\usepackage{xcolor}
%
\makeatletter
\newcommand{\colorGet}[3][\@firstofone]{#1{D3523C}} % A macro which returns a different hex-code for each combination of arguments, simplified for this example.
\makeatother
\begin{document}
\colorGet[\definecolor{mycolor}{HTML}]{SchemeName}{ColourName}
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.