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.

Using pgfkeys, I would like to have a choice key which, rather than immediately executing some code when a value is selected, stores the selection somewhere and then later on demand I can execute the code associated with said option.

An example should clarify things. I would like to define some sort of handler that allows me to write something like:

\pgfkeys{
  /action/.is choice,
  /action/jump/.on exec = \dojump,
  /action/walk/.on exec = \dowalk,
  /action/run/.on exec  = \dorun
}

So that when I select an option

\pgfkeys{/action=jump} # remembers that I selected "jump"

the corresponding code \dojump is not executed just yet, but instead the selection is saved and executed only later until I actually say something like:

\pgfkeys{/action/.exec} # actually does the `\dojump`

This should allow the user to choose one option at some point, and change her mind later, and then put the option back. But nothing should be executed until I explicitly ask the code for the selected option to be executed.

Is there a simple way to add handlers to pgfkeys and achieve this? Am I doing things the right way, or I am trying to reinvent the wheel?

share|improve this question
    
I can't see what \pgfkeys@split@path is doing here, since you aren't using \pgfkeyscurrentname and \pgfkeys@case@three calls \pgfkeys@split@path. And do exec/.style={\pgfkeyscurrentpath/do exec} smacks of a cyclic call. –  Ahmed Musa Nov 2 '12 at 18:28
    
\pgfkeys@split@path splits the current key into path+name; by setting the path to the current key before calling this, effectively this moves the path “one level up”. And the “cyclic call” is no cyclic, precisely for the same reason, I do a .cd up to go one leve up before. –  Juan A. Navarro Nov 2 '12 at 23:53
add comment

2 Answers 2

Solution (2012/11/02)

I don't think we need pgfkeys for this task, but here is an attempt.

\documentclass{article}
\usepackage{pgfkeys}
\makeatletter
\def\elk@do#1{\@ifnextchar x#1#1}
\def\elk@@do#1#2#3{%
  \csname @\ifx#1#2gobble\else iden\fi\endcsname
  {#3\elk@do#1}%
}
\def\foreachelk#1#2{%
  \def\elkdo##1,{\elk@@do\elkdo{##1}{#2}}%
  \elk@do\elkdo#1,\elkdo,%
}
\def\foreachbison#1#2{%
  \def\bisondo##1/##2,{\elk@@do\bisondo{##1}{#2}}%
  \elk@do\bisondo#1,\bisondo/,%
}
\def\pgfkeys@everystartchoice{}
\def\pgfkeyseverysoc{\g@addto@macro\pgfkeys@everystartchoice}
\def\pgfkeys@everyendchoice{}
\def\pgfkeyseveryeoc{\g@addto@macro\pgfkeys@everyendchoice}
\let\nava@choicewrapper\@iden
\def\choicewrapper{\gdef\nava@choicewrapper}
\pgfkeys{
  /nava/action/.is family,
  /nava/action/.cd,
  .define choices/.code={%
    \foreachbison{#1}{%
      \pgfkeysalso{%
        /nava/action/##1/.code={%
          \ifcsname nava-##1\endcsname
            \@latexerr{Choice '##1' already defined}\@ehd
          \else
            \expandafter\edef\csname nava-##1\endcsname{%
              \unexpanded\expandafter{\pgfkeys@everystartchoice}%
              \unexpanded{\nava@choicewrapper{##2}}%
              \unexpanded\expandafter{\pgfkeys@everyendchoice}%
            }%
          \fi
        },
        /nava/action/##1,
      }%
    }%
  },
  .exec method/.code={%
    \foreachelk{#1}{\csname nava-##1\endcsname}%
  },
}
% \addnewchoices{<choice1/method1,choice2/method2,...>}
\def\addnewchoices#1{\pgfkeys{/nava/action/.define choices={#1}}}
\def\dochoicemethods#1{\pgfkeys{/nava/action/.exec method={#1}}}
\makeatother

\begin{document}
% These are optional. Insert at end of every choice:
\pgfkeyseveryeoc{.\endgraf}
% Wrap the methods for the choices:
\choicewrapper{\textit}

% Define and remember my choices:
\addnewchoices{jump/I'll jump,walk/I'll walk,run/I'm running home}

% Call my choices and execute their methods:
\dochoicemethods{jump,walk,run,run,walk}
\dochoicemethods{jump}
\end{document}
share|improve this answer
    
Sure, that is what I want to achieve. However (1) I don't want to have to invent a new name (\navaaction) for each similar option that I may want to define. It feels that something like /navarro/action/exec is already a good name that shouldn't clash with other packages. And (2) I'm lazy, if I do this over and over again, I don't want to be writing \def\navaaction all the time. That's why I think it would be better to define a handler that does all the work for me. –  Juan A. Navarro Nov 1 '12 at 20:41
    
You can get rid of the macro by writing, say, action/jump/.style = {exec/.code = \dojump}. –  Ryan Reich Nov 1 '12 at 23:09
    
And what should I use to call the last action selected by the user? –  Juan A. Navarro Nov 2 '12 at 14:44
    
@JuanA.Navarro: The last question isn't clear to me. –  Ahmed Musa Nov 2 '12 at 15:08
    
@AhmedMusa, sorry for that. I guess I could have explained myself better. Anyway, thanks for your help, now I've updated my question with something that looks like a solution to me. Would you like to comment on that? –  Juan A. Navarro Nov 2 '12 at 16:33
add comment
up vote 2 down vote accepted

After a few more iterations of my original ideas, I've implemented a solution with which I'm pretty comfortable now, and which is stable enough so that I'm happy to share it as well.

I've turned this into a small package ezkeys, which is a single file containing mostly documentation and a bit of code defining some new pgfkey handlers.

As an example usage, after setting:

\pgfkeys{
  my package/.is family,
  my package,
  align/.is code choice,
  align/left/.code   = \raggedright,
  align/center/.code = \centering,
  align/right/.code  = \raggedleft,
  format/.is code choice,
  format/bold/.code    = \textbf{#1},
  format/italics/.code = \textit{#1},
}

Options can be selected using, e.g.:

\pgfkeys{my package,align=right,format=bold}

which causes the selected options to remebered but not executed. Only later, when requesting it by explcitly evaluating

\pgfkeys{my package,align/.eval,/format/.eval=Hello}

then corresponding subkeys will be executed and expanded, in this example to

\raggedleft\textbf{Hello}
share|improve this answer
add 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.