I'm trying to create some templating infrastructure that heavily depends on pgfkeys' styles to easily customise the appearance of how some bits of text are typeset on my document. However, I've run into some problem when trying to append more key-value pairs to a style that, as its job, already defined more codes or styles.
The following example shows the problem I'm talking about:
\documentclass{minimal}
\usepackage{pgfkeys}
\begin{document}
\pgfkeys{
/my package/.cd,
fancy/.style = {
format/.code = \textbf{##1},
},
fancy,
format=hello, % typesets `hello' in boldface
fancy/.append style = { },
fancy,
format=hello, % nothing is typeset
% format/.show code, % uncomment to see the definition of format
}
\end{document}
Uncommenting the last line in the \pgfkeys
command shows that, after trying to append to the fancy
style, the code in the format
key has been replaced by:
\textbf {\pgfkeysnovalue }
and thus nothing is typeset on the second format=hello
.
I (sort of) understand why this happens. The same reason why I had to write ##1
when defining the code within the style. However, is there a fix or workaround to make the style “robust” enough so that it is possible to append to it without breaking it?
Edit 1
Thanks to the comment from Joseph Wright and attempted answer from percusse, I figured out that—at the lower level—the problem to solve is the following: given an already defined macro which takes one argument (this is now codes/styles in pgfkeys are internally defined), patch the replacement text of the macro by appending some more text.
Now, from etoolbox
, there is a macro for doing just this: \apptocmd
. The following is an example of how a solution using this macro should probably look like:
\documentclass{minimal}
\usepackage{etoolbox}
\tracingpatches
\begin{document}
\ttfamily
\def\fancy#1\pgfeov{\pgfkeysalso{format/.code=\textbf{##1}}}
\meaning\fancy\par
\apptocmd\fancy{\pgfkeysalso{color=red}}{Ok!}{Fail.}\par
\meaning\fancy\par
\apptocmd\fancy{\pgfkeysalso{format/.code=\textit{##1}}}{Ok!}{Fail.}\par
\meaning\fancy\par
\end{document}
The only problem is that the second patching attempt doesn't work, and etoolbox shows the following as debug information:
[debug] tracing \apptocmd on input line 10
[debug] analyzing '\fancy'
[debug] ++ control sequence is defined
[debug] ++ control sequence is a macro
[debug] ++ control sequence is a macro with parameters
[debug] -- nested patching command and parameters in patch
[debug] -> the patching command seems to be nested in the
[debug] argument to some other command
[debug] -> the patch text seems to contain # characters
[debug] -> either avoid nesting or use # characters with
[debug] category code 12 in the patch text
[debug] -> simply doubling the # characters will not work
Would it be possible to have an \apptocmd
that works even with #
characters in the new replacement text?
Disclaimer: I do now have some workaround for my particular case, which only works because my fancy
styles in fact do not need to take any arguments (format
does, but fancy
doesn't). So, instead of storing the code as a style, I store it as a regular plain value, and make .code
expand to this value. Later, a simple /.append
can be used to patch the “fake” style.
Still, I would very much like a solution to the original problem, so that one can also append to styles containing both arguments and (let's call them) sub-arguments. I don't know, however, if this is technically possible. So, this is my deal: If someone believes that a general solution is feasible, and lets me know this by just posting a comment, I'm willing to open a 300 bounty of my rep for a working solution to the general case. If, however, people believe that this is either just too difficult or technically impossible (and I suspect of this because etoolbox
did not implement it) then I'll just be content with my sillier workaround and post a full answer expanding on it.
pgfkeys
: if you tryfancy/.show code
you get\pgfkeysalso { format/.code = \textbf {##1}, }
to begin with but\pgfkeysalso { format/.code = \textbf {#1}}\pgfkeysalso { }
later, with the loss of a#
.