編輯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應該使用 plus toks:

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

相關內容