Estou tentando criar uma infraestrutura de modelos que depende muito dos estilos do pgfkeys para personalizar facilmente a aparência de como alguns pedaços de texto são digitados em meu documento. No entanto, encontrei alguns problemas ao tentar anexar mais pares de valores-chave a um estilo que, como função, já definia mais códigos ou estilos.
O exemplo a seguir mostra o problema do qual estou falando:
\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}
Remover o comentário da última linha do \pgfkeys
comando mostra que, após tentar anexar ao fancy
estilo, o código na format
chave foi substituído por:
\textbf {\pgfkeysnovalue }
e, portanto, nada está escrito no segundo format=hello
.
Eu (mais ou menos) entendo por que isso acontece. A mesma razão pela qual tive que escrever ##1
ao definir o código dentro do estilo. No entanto, existe uma correção ou solução alternativa para tornar o estilo “robusto” o suficiente para que seja possível anexá-lo sem quebrá-lo?
Editar 1
Graças ao comentário de Joseph Wright e à tentativa de resposta de percusse, descobri que - no nível inferior - o problema a resolver é o seguinte: dada uma macro já definida que leva um argumento (agora códigos/estilos em pgfkeys são definido internamente), corrija o texto de substituição da macro anexando mais algum texto.
Agora, de etoolbox
láéuma macro para fazer exatamente isso: \apptocmd
. A seguir está um exemplo de como uma solução usando esta macro provavelmente deveria ser:
\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}
O único problema é que a segunda tentativa de patch não funciona e o etoolbox mostra o seguinte como informações de depuração:
[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
Seria possível ter um \apptocmd
que funcionasse mesmo com #
caracteres do novo texto de substituição?
Isenção de responsabilidade:Agora tenho alguma solução alternativa para meu caso específico, que só funciona porque meus fancy
estilos, na verdade, não precisam receber nenhum argumento ( format
faz, mas fancy
não). Portanto, em vez de armazenar o código como um estilo, eu o armazeno como um valor simples regular e o expando .code
para esse valor. Mais tarde, um simples /.append
pode ser usado para corrigir o estilo “falso”.
Ainda assim, eu gostaria muito de uma solução para o problema original, para que também se pudesse anexar estilos contendo argumentos e (vamos chamá-los) subargumentos. Não sei, no entanto, se isso é tecnicamente possível. Então, o meu negócio é o seguinte: se alguém acredita que uma solução geral é viável e me informa disso apenas postando um comentário,Estou disposto a abrir uma recompensa de 300 do meu representante por uma solução funcional para o caso geral. Se, no entanto, as pessoas acreditarem que isso é muito difícil ou tecnicamente impossível (e eu suspeito disso porque etoolbox
não o implementei), então ficarei satisfeito com minha solução alternativa mais tola e postarei uma resposta completa expandindo-a.
Responder1
Isso parece um bug no pgfkeys
. Se você fizer
\pgfkeys{
/my package/.cd,
fancy/.style = {
format/.code = \textbf{##1},
},
fancy/.show code,
fancy/.append style = { },
fancy/.show code
}
você vê
\pgfkeysalso { format/.code = \textbf {##1}, }
pela primeira vez, mas
\pgfkeysalso { format/.code = \textbf {#1}}\pgfkeysalso { }
pela segunda vez: observe a perda de a #
.
O código subjacente .append style
é
\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%
}%
}
A questão é a linha em direção ao fim
\expandafter\def\expandafter\pgfkeys@temp\expandafter##\expandafter1\expandafter\pgfeov\expandafter{\pgfkeys@global@temp}%
À medida que isso simplesmente se expande \pgfkeys@global@temp
, o TeX irá desdobrar tudo #
o que contém. Em vez disso, um \edef
plus toks deve ser usado:
\toks0\expandafter{\pgfkeys@global@temp}%
\edef\pgfkeys@temp##1\pgfeov{\the\toks0}%