Editar 1

Editar 1

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 \pgfkeyscomando mostra que, após tentar anexar ao fancyestilo, o código na formatchave 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 ##1ao 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é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 \apptocmdque 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 fancyestilos, na verdade, não precisam receber nenhum argumento ( formatfaz, mas fancynão). Portanto, em vez de armazenar o código como um estilo, eu o armazeno como um valor simples regular e o expando .codepara esse valor. Mais tarde, um simples /.appendpode 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 etoolboxnã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 \edefplus toks deve ser usado:

\toks0\expandafter{\pgfkeys@global@temp}%
\edef\pgfkeys@temp##1\pgfeov{\the\toks0}%

informação relacionada