編集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 }

したがって、 2 番目には何もタイプセットされませんformat=hello

なぜこのようなことが起こるのかは(ある程度)理解しています。##1スタイル内でコードを定義するときに記述しなければならなかったのと同じ理由です。しかし、スタイルを「堅牢」にして、それを壊さずに追加できるようにする修正や回避策はありますか?


編集1

Joseph Wright からのコメントと percusse からの回答のおかげで、低レベルでは、解決すべき問題が次のとおりであることがわかりました。1 つの引数を取る定義済みのマクロ (これは現在、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}

唯一の問題は、2 回目のパッチ適用の試行が機能せず、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 { }

2 回目: が失われていることに注意してください#

基礎となるコード.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}%

関連情報