Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like to use pgfkeys in a macro. One key contains a foreach statement which handles a variable number of values. I have some problems concerning the right order of the output. Here a simplified example:

\documentclass[article]{memoir}
\usepackage[latin]{babel}
\usepackage{algpseudocode}
\usepackage{pgfkeys}

\pgfkeys{%
/test/.is family,
/test/.cd,
    key a/.store in = \keyA,
    key a print/.code = \texttt{\keyA},
    key b/.code = {\foreach \x in {#1}{\textbf{\x}--}}
}%

\newcommand\mymacro[1]{\pgfkeys{/test, #1, key a print}}

\begin{document}
\mymacro{key a = valueKeyA, key b = {valueKeyB1, valueKeyB2, valueKeyB3}}
\end{document}

The order of the output is: valueKeyB1–valueKeyB2–valueKeyB3–valueKeyA

How can I achieve that valueKeyA is typeset first? If I put #1 at the end of the key list in my example code I get an error message. If I place it at the end of the key list in my actual code the values of the first keys are missing. I guess it has either something to do with the order in which the values are stored and the keys are executed or my use of #1 is mixed up.

I am using pgfkeys for a short time and would be glad if someone could give me a hint.

share|improve this question
add comment

1 Answer

up vote 8 down vote accepted

At the moment, the keys are executed in the following order:

  1. key a = valueKeyA. This stores valueKeyA in the macro \keyA.
  2. key b = {valueKeyB1, valueKeyB2, valueKeyB3}. This prints out valueKeyB1--valueKeyB2--valueKeyB3-- (ignoring formatting)
  3. key a print. This prints out \keyA which expands to valueKeyA.

So the problem is that for key a, the processing is split into two parts: storing and printing, whilst for key b this is all done in one step. The order in which you call things means that the two steps for a are split by the one step for b. There are a variety of ways to fix this depending on what you want to achieve.

Before giving some, let me explain why putting #1 at the end doesn't work. This is because that puts step 3 above first, whereupon it tries to print out the value of \keyA which hasn't been set yet.

As I said, how to fix this depends on what you want to do in your real code. Here are a couple.

  1. Put the key a print inside the argument to \mymacro in the right place, so we have:

    \newcommand\mymacro[1]{\pgfkeys{/test, #1}}
    
    \begin{document}
    \mymacro{key a = valueKeyA, key a print, key b = {valueKeyB1, valueKeyB2, valueKeyB3}}
    
  2. Make the key a step both store and print its value, something like:

    \pgfkeys{/test/.cd, key a/.code={\def\keyA{#1}\texttt{#1}}}
    

    Then remove key a print from everywhere.

  3. Make the key b step store its result in a macro to be printed out later. Something like:

    \pgfkeys{/test/.cd, key b/.code={\def\keyB{}\foreach \x in {#1}{\expandafter\gdef\expandafter\keyB\expandafter{\keyB\textbf{\x}--}}}, key b print/.code={\keyB}}
    

    Then add key b print after key a print (or do a combined print all keys).

There are probably more - even if those don't prove to be useful they should help you figure out what features of a solution you would like.


(Edit: 2013-06-20)

The third solution has a little issue with expansion. The \x needs to be expanded at least once within the definition of \keyB. If everything can be expanded at definition time, then this can be achieved with a \protected@xdef instead of the \gdef. If not, then it's a slew of \expandafters.

Seriously, LaTeX3 is so much easier for this sort of thing, so I've added a LaTeX3 version that keeps pretty close to the PGF foreach one (the minor difference being that I iterate over the key list at display time not at definition time). I would probably do it slightly differently in that I wouldn't bother having the key a print and key b print as keys but just as commands. But I'm staying close to your code so that you can see the similarities and differences.

The following all produce:

valueKeyAvalueKeyB1--valueKeyB2--valueKeyB3

\documentclass[article]{memoir}
%\url{http://tex.stackexchange.com/q/54533/86}
\usepackage[latin]{babel}
\usepackage{algpseudocode}
\usepackage{pgfkeys}
\usepackage{pgffor}
\usepackage{xparse,expl3}

\pgfkeys{%
/test/.is family,
/test/.cd,
    key a/.store in = \keyA,
    key a print/.code = \texttt{\keyA},
    key b/.code = {%
      \let\keyB=\relax%
      \foreach \x in {#1} {%
        \ifx\keyB\relax
        \expandafter\gdef\expandafter\keyB\expandafter{\expandafter\textbf\expandafter{\x}}%
        \else
        \expandafter\expandafter\expandafter\gdef\expandafter\expandafter\expandafter\keyB\expandafter\expandafter\expandafter{%
          \expandafter\keyB\expandafter-\expandafter-\expandafter\textbf\expandafter{\x}%
        }%
        \fi
      }%
    },
    key b print/.code={\keyB}
}%

\makeatletter
\pgfkeys{%
/xtest/.is family,
/xtest/.cd,
    key a/.store in = \keyA,
    key a print/.code = \texttt{\keyA},
    key b/.code = {%
      \let\keyB=\relax%
      \foreach \x in {#1} {%
        \ifx\keyB\relax
        \protected@xdef\keyB{\protect\textbf{\x}}%
        \else
        \protected@xdef\keyB{%
          \keyB--\protect\textbf{\x}%
        }%
        \fi
      }%
    },
    key b print/.code={\keyB}
}%
\makeatother

\ExplSyntaxOn

\tl_new:N \l__aik_keya_tl
\clist_new:N \l__aik_keyb_clist
\keys_define:nn {3test}
{
  key~ a .tl_set:N = \l__aik_keya_tl,
  key~ b .clist_set:N = \l__aik_keyb_clist,
  key~ a~ print .code:n = {
    \texttt{\tl_use:N \l__aik_keya_tl}
  },
  key~ b~ print .code:n = {
    \tl_clear:N \l_tmpa_tl
    \clist_map_inline:Nn \l__aik_keyb_clist
    {
      \tl_use:N \l_tmpa_tl \textbf{##1}
      \tl_set:Nn \l_tmpa_tl {--}
    }
  }
}

\NewDocumentCommand \mytmacro {m}
{
  \keys_set:nn {3test} {#1, key~ a~ print, key~ b~ print}
}

\ExplSyntaxOff

\newcommand\mymacro[1]{\pgfkeys{/test, #1, key a print, key b print}}
\newcommand\myxmacro[1]{\pgfkeys{/xtest, #1, key a print, key b print}}

\begin{document}
\mymacro{key a = valueKeyA, key b = {valueKeyB1, valueKeyB2, valueKeyB3}}

\myxmacro{key a = valueKeyA, key b = {valueKeyB1, valueKeyB2, valueKeyB3}}

\mytmacro{key a = valueKeyA, key b = {valueKeyB1, valueKeyB2, valueKeyB3}}

\end{document}
share|improve this answer
    
Thanks for your help! The order in which the different steps are achieved is quiet what I expected. I did even try something like you suggest in your third solution, but obviously I made a mistake. The second way works fine for me and keeps everything simple, which is a good thing... –  Aik May 7 '12 at 13:47
    
In case the value stored in \keyA is used in the code of several keys which are supposed to deliver different outputs, the third solution would be better. So out of interest i tried to solve the problem this way, too. If I use the code of your third suggestion a long dash (for the three en dashes in the example) is printed, but the values (valueKeyB1-3) are missing. Do you know why the values are not printed? I roughly understand your trick but not well enough to fix this. –  Aik May 7 '12 at 20:27
    
@Aik I will confess to posting this without actually trying out the code. I will take another look at the third version and see what went wrong. –  Andrew Stacey May 7 '12 at 20:33
    
It has been a while since I posted this question and I really want to accept your answer. It would be nice if you find the time to take a look at the third solution. You are doing great work here at TeX SE! –  Aik Jun 19 '13 at 17:17
    
@Aik My apologies! I appear to have completely forgotten this. I hope that my update goes some way to mitigate this. –  Andrew Stacey Jun 20 '13 at 10:27
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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