使用 pgfkeys 进行过滤选项

使用 pgfkeys 进行过滤选项

我正在寻找一个如何pgfkeys拆分选项列表的示例,以便:(1)现在处理某些选项,(2)其余选项传递给第二个宏进行进一步处理。

看来密钥过滤应该是这个问题的答案,但我不确定如何去做。

让我们开始假设某个命令,\theirmacro{...}它的单个参数采用选项的键值列表。我知道它理解选项optAoptB,但它也可能接受其他选项(而且以后的更新theirpackage甚至可能定义我目前还不知道的新选项)。此外,theirpackage可能会或可能不会使用来实现pgfkeys

现在我想定义一些新的\mymacro{...},另外还理解optCoptD,并将所有其他选项传递给\theirmacro

也就是说,调用\mymacro{optA=1,optC=2}应该:(1)对 optC 的值执行某些操作,并在内部调用\theirmacro{optA=1}来处理其余选项。

答案1

根据我的问题的一些提示和评论,以及在传递未知密钥到其他环境——我能够构建以下实现。

\documentclass{article}
\usepackage{pgfkeys}
\usepackage{etoolbox}

% A mock-up implementation of \theirmacro on `their package`
\pgfkeys{
  /their package/.cd,
  optA/.code = {(A:#1)},
  optB/.code = {(B:#1)}
}

\newcommand\theirmacro[1]{\pgfqkeys{/their package}{#1}}

% my proposed code for unknown option collecting
\pgfkeys{
  /handlers/.collect unknowns/.style = {
    unknown options/.initial = {},
    .unknown/.code = {%
      % Edit by EM:
      \letcs\reserved{pgfk@\pgfkeyscurrentpath/unknown options}%
      \csedef{pgfk@\pgfkeyscurrentpath/unknown options}{%
        \ifx\reserved\empty\else\expandonce\reserved,\fi
        \expandonce\pgfkeyscurrentname
        \ifx\pgfkeysnovalue##1\else=\expandonce\pgfkeyscurrentvalue\fi
      }%
    }
  }
}

% the implementation of \mymacro on `my package`
\pgfkeys{
  /my package/.cd,
  optC/.code = {(C:#1)},
  optD/.code = {(D:#1)},
}

\newcommand\mymacro[1]{%
  I process options:
  \pgfqkeys{/my package}{
    .collect unknowns,%
    #1,
    unknown options/.get = \myunknowns
  }\par
  They process options:
  \expandafter\theirmacro\expandafter{\myunknowns}
}

\begin{document}

\mymacro{optA=3,optC=2,optD=4,optB=4}

\end{document}

这似乎和我预期的一样。但我对宏扩展黑客技术并不在行(请注意,我不得不依赖 etoolbox,否则我不知道如何实现这些功能),所以我想知道是否有任何关于如何改进此实现的进一步提示或意见。

另一方面,我仍然感到困惑和好奇,如何使用 pgfkey 过滤器实现类似的事情。

答案2

这是另一个解决方案。处理程序.save unknowns允许我们为未知密钥提交并初始化存储宏。

\documentclass{article}
\usepackage{pgfkeys}
\makeatletter
\def\emexpandonce#1{\unexpanded\expandafter{#1}}

\pgfqkeys{/their package}{
  optA/.code = {(A:#1)}, optB/.code = {(B:#1)},
  optA2/.code = {(A2-#1)}, optB2/.code = {(B2-#1)}
}
\newcommand*\theirmacro{%
  \begingroup
  \edef\x{\endgroup
    \noexpand\pgfqkeys{/their package}{\emexpandonce\unknownkeys}}\x
}

\pgfqkeys{/my package}{
  optC/.code = {(C:#1)}, optD/.code = {(D:#1)},
  optC2/.code = {(C2-#1)}, optD2/.code = {(D2-#1)}
}
\newcommand*\mymacro[1]{%
  I processed options:
  \pgfqkeys{/my package}{.save unknowns=\unknownkeys,#1}\endgraf
  They processed options:
  \theirmacro
}

\pgfkeys{
  /handlers/.save unknowns/.code={
    \edef\reserved{\expandafter\@car\string#1\@nil}%
    \ifx\reserved\@backslashchar
      \def#1{}%
    \else
      \@latexerr{'\detokenize{#1}' is not escaped; maybe not a macro}\@ehd
    \fi
    \pgfkeysalso{
      \pgfkeyscurrentpath/.unknown/.code={%
        \edef#1{%
          \ifx#1\empty\else\emexpandonce#1,\fi
          \emexpandonce\pgfkeyscurrentname
          \ifx\pgfkeysnovalue##1\else=\emexpandonce\pgfkeyscurrentvalue\fi
        }%
      }
    }
  }
}
\makeatother

\begin{document}
\mymacro{optA=3,optC=2,optD=4,optB=4}
\par
\mymacro{optA2=3,optC2=2,optD2=4,optB2=4}
\end{document}

相关内容