编辑1

编辑1

我正在尝试创建一些模板基础结构,这些基础结构严重依赖 pgfkeys 的样式,以便轻松自定义文档中某些文本的排版外观。但是,当我尝试将更多键值对附加到样式时遇到了一些问题,因为样式的工作已经定义了更多代码或样式。

下面的例子显示了我正在谈论的问题:

\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}

取消注释命令中的最后一行\pgfkeys表明,在尝试附加到样式后fancy,键中的代码format已被替换为:

\textbf {\pgfkeysnovalue }

因此第二个上没有任何排版format=hello

我(有点)理解为什么会发生这种情况。这与我##1在样式中定义代码时必须编写的原因相同。但是,是否有修复或解决方法可以使样式足够“健壮”,以便可以在不破坏样式的情况下对其进行附加?


编辑1

感谢 Joseph Wright 的评论和 percusse 的尝试回答,我发现 - 在较低层次上 - 要解决的问题如下:给定一个已经定义的带有一个参数的宏(现在 pgfkeys 中的代码/样式是内部定义的),通过附加一些文本来修补宏的替换文本。

现在,从etoolbox那里一个宏可以完成这个任务:\apptocmd。下面是一个使用此宏的解决方案可能的样子:

\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}

唯一的问题是第二次修补尝试不起作用,并且 etoolbox 显示以下内容作为调试信息:

[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

是否有可能使它即使使用新替换文本中的字符\apptocmd也能正常工作?#

免责声明:我现在确实有一些针对我特定情况的解决方法,这只因为我的fancy样式实际上不需要接受任何参数(format需要,但fancy不接受)。因此,我没有将代码存储为样式,而是将其存储为常规纯值,并使其.code扩展为该值。稍后,/.append可以使用一个简单的方法来修补“假”样式。

尽管如此,我还是非常希望找到原始问题的解决方案,这样人们也可以将包含参数和(我们称之为)子参数的样式附加到其中。但是,我不知道这在技术上是否可行。所以,这是我的交易:如果有人认为通用解决方案是可行的,并且只需发表评论让我知道这一点,我愿意为解决一般问题提供 300 点悬赏。但是,如果人们认为这太难或从技术上讲不可能(我怀疑这是因为etoolbox没有实现它),那么我将满足于我的愚蠢的解决方法,并发布一个完整的答案来扩展它。

答案1

这看起来像是一个错误pgfkeys。如果你这样做

\pgfkeys{
  /my package/.cd,
  fancy/.style = {
    format/.code = \textbf{##1},
  },
  fancy/.show code,
  fancy/.append style = { },
  fancy/.show code
}

你看

\pgfkeysalso { format/.code = \textbf {##1}, }

第一次,但是

\pgfkeysalso { format/.code = \textbf {#1}}\pgfkeysalso { }

第二次:注意丢失了a #

底层代码.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%
  }%
}

问题在于结尾处的线条

\expandafter\def\expandafter\pgfkeys@temp\expandafter##\expandafter1\expandafter\pgfeov\expandafter{\pgfkeys@global@temp}%

由于这只是扩展\pgfkeys@global@temp,TeX 将取消#其包含的任何内容的双重化。相反,\edef应该使用加号 toks:

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

相关内容