我正在寻找一个如何pgfkeys
拆分选项列表的示例,以便:(1)现在处理某些选项,(2)其余选项传递给第二个宏进行进一步处理。
看来密钥过滤应该是这个问题的答案,但我不确定如何去做。
让我们开始假设某个命令,\theirmacro{...}
它的单个参数采用选项的键值列表。我知道它理解选项optA
和optB
,但它也可能接受其他选项(而且以后的更新theirpackage
甚至可能定义我目前还不知道的新选项)。此外,theirpackage
可能会或可能不会使用来实现pgfkeys
。
现在我想定义一些新的\mymacro{...}
,另外还理解optC
和optD
,并将所有其他选项传递给\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}