Estoy intentando crear una infraestructura de plantillas que dependa en gran medida de los estilos de pgfkeys para personalizar fácilmente la apariencia de cómo se escriben algunos fragmentos de texto en mi documento. Sin embargo, me encontré con algún problema al intentar agregar más pares clave-valor a un estilo que, como trabajo, ya define más códigos o estilos.
El siguiente ejemplo muestra el problema del que estoy hablando:
\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}
Descomentar la última línea del \pgfkeys
comando muestra que, después de intentar agregar el fancy
estilo, el código en la format
clave ha sido reemplazado por:
\textbf {\pgfkeysnovalue }
y por lo tanto no se escribe nada en el segundo format=hello
.
Entiendo (más o menos) por qué sucede esto. La misma razón por la que tuve que escribir ##1
al momento de definir el código dentro del estilo. Sin embargo, ¿existe una solución alternativa para hacer que el estilo sea lo suficientemente “robusto” como para que sea posible agregarlo sin romperlo?
Editar 1
Gracias al comentario de Joseph Wright y al intento de respuesta de percusse, descubrí que, en el nivel inferior, el problema a resolver es el siguiente: dada una macro ya definida que toma un argumento (ahora los códigos/estilos en pgfkeys son definido internamente), parchee el texto de reemplazo de la macro agregando algo más de texto.
Ahora, desde etoolbox
allíesuna macro para hacer precisamente esto: \apptocmd
. El siguiente es un ejemplo de cómo debería verse probablemente una solución que utilice esta macro:
\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}
El único problema es que el segundo intento de parcheo no funciona y etoolbox muestra lo siguiente como información de depuración:
[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
¿Sería posible tener un \apptocmd
sistema que funcione incluso con #
caracteres en el nuevo texto de reemplazo?
Descargo de responsabilidad:Ahora tengo una solución alternativa para mi caso particular, que sólo funciona porque mis fancy
estilos, de hecho, no necesitan aceptar ningún argumento ( format
lo hace, pero fancy
no lo hace). Entonces, en lugar de almacenar el código como un estilo, lo almaceno como un valor simple normal y lo expando .code
a este valor. Más adelante, /.append
se puede utilizar un sencillo para parchear el estilo “falso”.
Aún así, me gustaría mucho una solución al problema original, de modo que también se puedan agregar estilos que contengan argumentos y (llamémoslos) subargumentos. Pero no sé si esto es técnicamente posible. Entonces, este es mi trato: si alguien cree que una solución general es factible y me lo hace saber simplemente publicando un comentario,Estoy dispuesto a ofrecer una recompensa de 300 a mi representante por una solución funcional al caso general.. Sin embargo, si la gente cree que esto es demasiado difícil o técnicamente imposible (y sospecho de esto porque etoolbox
no lo implementé), entonces me contentaré con mi solución más tonta y publicaré una respuesta completa ampliandola.
Respuesta1
Esto parece un error en pgfkeys
. Si lo haces
\pgfkeys{
/my package/.cd,
fancy/.style = {
format/.code = \textbf{##1},
},
fancy/.show code,
fancy/.append style = { },
fancy/.show code
}
verás
\pgfkeysalso { format/.code = \textbf {##1}, }
la primera vez pero
\pgfkeysalso { format/.code = \textbf {#1}}\pgfkeysalso { }
la segunda vez: observe la pérdida de un #
.
El código que subyace .append style
es
\pgfkeys{/handlers/.add code/.code 2 args=%
% Find out, whether with args or not.
\pgfkeysifdefined{\pgfkeyscurrentpath/.@args}%
{% Yes, so add to body and reuse args
\pgfkeysaddvalue{\pgfkeyscurrentpath/.@body}{#1}{#2}%
% Redefine code
{%
\pgfkeysgetvalue{\pgfkeyscurrentpath/.@args}{\pgfkeys@tempargs}%
\pgfkeysgetvalue{\pgfkeyscurrentpath/.@body}{\pgfkeys@tempbody}%
\def\pgfkeys@marshal{\expandafter\gdef\expandafter\pgfkeys@global@temp\pgfkeys@tempargs}%
\expandafter\pgfkeys@marshal\expandafter{\pgfkeys@tempbody}%
}%
\pgfkeysifdefined{\pgfkeyscurrentpath/.@@body}{%
% support for \pgfkeysndefargs:
\pgfkeyslet{\pgfkeyscurrentpath/.@@body}{\pgfkeys@global@temp}%
}{%
% support for \pgfkeysdefargs:
\pgfkeyslet{\pgfkeyscurrentpath/.@cmd}{\pgfkeys@global@temp}%
}%
}%
{%
% No, so single argument (simple \pgfkeysdef). Redefine accordingly.
{%
\toks0{#1}%
\pgfkeysifdefined{\pgfkeyscurrentpath/.@cmd}%
{\pgfkeys@temptoks\expandafter\expandafter\expandafter{\csname pgfk@\pgfkeyscurrentpath/.@cmd\endcsname##1\pgfeov}}%
{\pgfkeys@temptoks{}}%
\toks1{#2}%
\xdef\pgfkeys@global@temp{\the\toks0 \the\pgfkeys@temptoks \the\toks1 }%
}%
\expandafter\def\expandafter\pgfkeys@temp\expandafter##\expandafter1\expandafter\pgfeov\expandafter{\pgfkeys@global@temp}%
\pgfkeyslet{\pgfkeyscurrentpath/.@cmd}\pgfkeys@temp%
}%
}
El problema es la línea hacia el final.
\expandafter\def\expandafter\pgfkeys@temp\expandafter##\expandafter1\expandafter\pgfeov\expandafter{\pgfkeys@global@temp}%
A medida que esto simplemente se expande \pgfkeys@global@temp
, TeX desdoblará todo #
lo que contenga. En su lugar, \edef
se debe utilizar un plus:
\toks0\expandafter{\pgfkeys@global@temp}%
\edef\pgfkeys@temp##1\pgfeov{\the\toks0}%