Choice key handler with deferred execution of code
A feature like .is choice, but the code of the choices is executed later, and not when assigning the value
The idea is from Juan on tex.sx, so I am going to quote his explanation here (CC BY-SA):
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:
So that when I select an option
\pgfkeys{/action=jump} # remembers that I selected "jump"the corresponding code
\dojumpis 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.
Since I think that this is a very useful feature (I've missed it several times in the past) and I also think that my answer to that question (see compilable example below) is quite neat and simple, I'd like to propose including it directly into the pgfkeys package:
Usage example
\documentclass{article}
\usepackage{pgfkeys}
%%% Start of implementation
\makeatletter
\pgfkeysdef{/handlers/.deferred code}{% is called with \pgfkeyscurrentpath=/path/ChoiceKey/ChoiceValue
\pgfkeysdef{/deferred choice/code\pgfkeyscurrentpath}{#1}%
\edef\pgfkeyscurrentkey{\pgfkeyscurrentpath}\pgfkeys@split@path% now path=/path/ChoiceKey and name=ChoiceValue
\pgfkeysedef{\pgfkeyscurrentkey}{\noexpand\pgfkeyssetvalue{/deferred choice/value\pgfkeyscurrentpath}{\pgfkeyscurrentname}}%
}
\makeatother
\pgfkeysdef{/handlers/.is deferred choice}{%
\expandafter\pgfkeysedef{\pgfkeyscurrentpath/.execute}{% is called with \pgfkeyscurrentpath=/path/ChoiceKey
\noexpand\pgfkeysgetvalue{/deferred choice/value\pgfkeyscurrentpath}{\noexpand\temp}%
\noexpand\pgfkeysalso{/deferred choice/code\pgfkeyscurrentpath/\noexpand\temp={##1}}%
}
\pgfkeysalso{\pgfkeyscurrentpath/.is choice}%
\pgfkeysalso{/deferred choice/code\pgfkeyscurrentpath/.is choice}%
}
%%% End of implementation
\begin{document}
%%% Start of usage example
\pgfkeys{
/my package/.is family,
/my package,
align/.is deferred choice,
align/left/.deferred code = left:,
align/right/.deferred code = right:,
format/.is deferred choice,
format/bold/.deferred code = bold:{#1},
format/italics/.deferred code = italics:{#1},
}
\pgfkeys{/my package, align=right, format=bold}
\pgfkeys{/my package, align=left, format=italics}
%\pgfkeys{/my package, align=wrong} % Error: Choice 'wrong' unknown in choice key '/my package/align'
% Inserts "left:italics:Hello" into the document
\pgfkeys{/my package, align/.execute, format/.execute=Hello}
\end{document}
I was not sure whether immediately opening a PR was the right way, so I opened this issue first to discuss it.
What's the use-case for this within PGF? I would rather not add features to pgfkeys which is considered more or less frozen. If I could I would even remove the key filtering and put it into pgfplots because it's not used in PGF at all.
@hmenke I guess that's a tension between pgfkeys as a part of pgf and as a generic tool.
I think I (and perhaps @hmenke) could do with a more concrete example of a real-world problem this solves. (I'm thinking in terms of l3keys, but as it's inspired by pgfkeys, many similar ideas apply.)
I'm right now thinking of adding a library mechanism to pgfkeys. That way I can accept all kinds of crazy features because they won't be loaded by default.
Prototype is at https://github.com/pgf-tikz/pgf/pull/1129
The reason this does not exist is because it is kinda "anti-pattern" for pgfkeys well eventually TeX itself being a terrible language at runtime. So up to the choice I think there is no problem. You can use a choice catalogue jump, sit, run. Each will set a particular value to a common macro \actiontodo and there is a central macro to do or exec that is when run, it checks the action to do from ... \actiontodo.
So when needed it is triggered but otherwise you can select the action as many times you need in the meantime. It will be deferred anyways because the trigger is not there. This is typically how TikZ stuff is done and how generally one hacks into TikZ.
Reading the example back, I wonder why you don't just .store in then at point-of-use have a \@nameuse{...} containing the macro that is used for storage?
Reading the example back, I wonder why you don't just
.store inthen at point-of-use have a\@nameuse{...}containing the macro that is used for storage?
That is another way to achieve the same effect (of course there are always multiple ways in programming), but I like three features of this approach:
- The included error checking of
.is choice, which rejects unknown values. - The implementations of the individual choices are separated from each other.
- (nearly the same as 2.) A central point-of-use macro would probably be littered with nested
\ifconstructs or similar to distinguish the individual cases (or at least I know no better way). The.is choiceacts like an implicitswitch/caseconstruct.
However, I can accept the argument that you don't want to add unnecessary features to pgfkeys. I mean, someone could always publish it as a separate package, but that is a lot more difficult to find. A library loading mechanism like in TikZ would probably make a lot of sense.
A central point-of-use macro would probably be littered with nested \if constructs
That is pretty much the whole TikZ codebase internally.
I thought about this a bit more yesterday and realised that this is in fact already possible without any extra code.
\documentclass{article}
\usepackage{pgfkeys}
\begin{document}
\pgfkeys{
/my package/.is family,
/my package,
align/.is choice,
align/left/.style={align/.execute/.code={left:}},
align/right/.style={align/.execute/.code={right:}},
format/.is choice,
format/bold/.style={format/.execute/.code={bold:{##1}}},
format/italics/.style={format/.execute/.code={italics:{##1}}},
}
\pgfkeys{/my package, align=right, format=bold}
\pgfkeys{/my package, align=left, format=italics}
\pgfkeys{/my package, align/.execute, format/.execute=Hello}
\end{document}
Wow, that is a really neat solution (even though it took a pgf maintainer to come up with it). I still think that the explicit key names in my code make it a bit more clear what is going on (to the casual reader). But I guess that is no reason to add a new feature to pgfkeys. I'm fine if you want close this issue.
PS: Care to add your code as an answer on the TeX.SX question? ;-)
align/.execute/.code={...} mixes up normal key and key handler hence I would suggest another key name, for example align/@execute.
Closing this because it won't be implemented. The functionality can already be achieved in pgfkeys without adding extra code.