我正在使用它pgfopts
来创建自己的包和处理选项。.family
并.cd
可以用来将包选项组合在一起,但我不确定是否理解每种方法的优缺点,以及在哪种具体情况下我会使用其中一种而不是另一种。
问题:更具体地说,以下三种方法之间有哪些实际区别,在什么情况下使用其中一种方法比使用另外两种方法更好(或更差)?
[方法 1].family
\pgfkeys{
/mypackage/.is family,
/mypackage,
myoption/.store in = \mypackage@myoption,
myoption = ,
}
[方法2].cd
\pgfkeys{
/mypackage/.cd,
myoption/.store in = \mypackage@myoption,
myoption = ,
}
[方法 3].family 和 .cd (不确定是否可能)
\pgfkeys{
/mypackage/.is family,
/mypackage/.cd,
myoption/.store in = \mypackage@myoption,
myoption = ,
}
笔记:我本质上是在寻求一个解释/澄清。
答案1
似乎普格福普特使用包鍵盤,它又是 TikT/PGF 束的一个组成部分,其中手册.pdf是手册和参考。鍵盤在“第七部分实用程序”的“87 密钥管理”一章中进行了描述。
宏参数中的⟨key⟩=⟨value⟩对中的一个⟨key⟩\pgfkeys
由两个部分组成:
⟨key-path⟩和⟨key-name⟩。
-handler/.cd
可以让你缩写,这样在仅提供 ⟨key-name⟩ 的情况下,通过添加通过 -thingie 指定的 ⟨key-path⟩ 来完成 ⟨key⟩ /.cd
。
密钥处理程序/.is family
执行两件事,我建议将其视为两个彼此独立的概念。
第一件事:
/SomeFamilys/Path/.is family,
定义键/SomeFamilys/Path
不采用任何值并且执行与 相同的操作/SomeFamilys/Path/.cd
。
/.is family
这是您在示例中所采用的方式。
完成 之后,如果愿意,/SomeFamilys/Path/.is family,
您可以用/SomeFamilys/Path,
或者/SomeFamilys/.cd, Path,
代替。/SomeFamilys/Path/.cd
第 2 件事:
第二个东西是关于过滤键的。也就是说,第二个东西是关于从给定的逗号分隔的 ⟨keys⟩ 和 ⟨key⟩=⟨value⟩ 对列表中选择执行哪些 ⟨keys⟩ 和/或 ⟨key⟩=⟨value⟩ 对的可能性。
这可能很方便,例如,在一个例程中,用户应仅在一个地方提供以逗号分隔的 ⟨keys⟩ 和 ⟨key⟩=⟨value⟩ 对列表,但并非所有 ⟨keys⟩/⟨key⟩=⟨value⟩ 对都应在该例程处理的同一阶段执行,但用户提供的一些 ⟨keys⟩/⟨key⟩=⟨value⟩ 对应在比其他对更早的处理阶段执行,以便在任何情况下,在执行该例程的过程中都会执行多个用于处理 ⟨keys⟩/⟨key⟩=⟨value⟩ 对的宏实例。
通常使用其中一个宏\pgfkeys
或\pgfqkeys
在其参数中指定以逗号分隔的 ⟨keys⟩ 和 ⟨key⟩=⟨value⟩ 对列表。列表中的 ⟨keys⟩ 和 ⟨key⟩=⟨value⟩ 对会逐一执行。
但还有宏\pgfkeysfiltered
和\pgfqkeysfiltered
。这些宏也处理以逗号分隔的 ⟨keys⟩ 和 ⟨key⟩=⟨value⟩ 对列表。但它们不会执行每个 ⟨keys⟩/⟨key⟩=⟨value⟩ 对。它们只执行其中 ⟨key⟩ 与某些关键过滤条件匹配的对。
那么问题来了:关键过滤标准是什么?
您可以通过宏\pgfkeysfiltered
调整宏的 key-filtering-criteria 。有各种 key-filters。软件包提供的\pgfqkeysfiltered
\pgfkeys
鍵盤在 key-path 中/pgf/key filters
。通过说,即通过将处理程序应用于宏参数内的键,您可以“告诉”系统,从今以后宏的实例将应用 key-filter 。/pgf/key filters/⟨KEY-FILTER⟩/.install key filter,
/.install key filter
/pgf/key filters/⟨KEY-FILTER⟩
\pgfkeys
\pgfkeysfiltered
\pgfqkeysfiltered
/pgf/key filters/⟨KEY-FILTER⟩
其中一个关键过滤器是 key-filter 。如果通过在宏的参数中/pgf/key filters/active families
给出指令,您提供指令,指示和的后续实例应使用该关键过滤器,那么对于宏和的后续实例,仅执行逗号分隔列表中的 ⟨keys⟩ 和 ⟨key⟩=⟨value⟩ 对,这些对属于当前激活的关键系列。/pgf/key filters/active families/.install key filter
\pgfkeys
\pgfkeysfiltered
\pgfqkeysfiltered
\pgfkeysfiltered
\pgfqkeysfiltered
反过来,这意味着必须以某种方式指定存在哪些密钥系列、哪些密钥属于它们以及哪些现有密钥系列具有活动属性。这反过来也是在 的参数中\pgfkeys
通过处理程序/.is family
和完成/.belongs to family={...}
的/.activate family
。
简而言之:
宏\pgfkeys{...}
可用于配置宏\pgfkeysfiltered{...}
和的后续实例的行为\pgfqkeysfiltered{...}
。
当通过\pgfkeys
安装(最好说选择)键过滤器并配置属于所选键过滤器的功能时,宏和的后续实例将\pgfkeysfiltered
应用\pgfqkeysfiltered
该键过滤器,即仅执行通过键过滤器的逗号分隔列表中的那些⟨keys⟩或⟨key⟩=⟨value⟩对。
在过滤键时继续处理以逗号分隔的 ⟨keys⟩ 或 ⟨key⟩=⟨value⟩ 对列表,与在不过滤键时处理以逗号分隔的 ⟨keys⟩ 或 ⟨key⟩=⟨value⟩ 对列表分开(前者通过宏\pgfkeysfiltered
/\pgfqkeysfiltered
完成,后者通过宏\pgfkeys
/\pgfqkeys
完成),否则您可能最终会配置和安装(选择)并因此使用键过滤器,而该键过滤器稍后会阻止应用 ⟨keys⟩ 或 ⟨key⟩=⟨value⟩ 对,这些对用于重新配置键过滤器的功能或用于切换到另一个键过滤器或用于完全关闭键过滤。
以下示例可能给出了按当前激活的密钥系列的成员资格进行密钥过滤的概念的线索:
\documentclass[a4paper]{article}
%============[adjust margins/layout]============================================
\paperheight=2\paperheight
\csname @ifundefined\endcsname{pagewidth}{}{\pagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pdfpagewidth}{}{\pdfpagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pageheight}{}{\pageheight=\paperheight}%
\csname @ifundefined\endcsname{pdfpageheight}{}{\pdfpageheight=\paperheight}%
\oddsidemargin=1.5cm
\marginparsep=.2\oddsidemargin
\marginparwidth=.4\oddsidemargin
\textwidth=\paperwidth
\advance\textwidth by -2\oddsidemargin
\advance\oddsidemargin by -1in
\evensidemargin=\oddsidemargin
\textheight=\paperheight
\topmargin=1.5cm
\headheight=0ex
\headsep=0ex
\advance\textheight by -2\topmargin
\advance\topmargin by -1in
{\normalfont
\setbox\csname @tempboxa\endcsname\hbox{0123456789}%
\global\footskip=\dimexpr .5cm -.5\dp\csname @tempboxa\endcsname
+.5\ht\csname @tempboxa\endcsname\relax
}%
{\normalfont
\setbox\csname @tempboxa\endcsname\hbox{%
0123456789ANCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz%
}%
\global\topskip=\ht\csname @tempboxa\endcsname
}%
\pagestyle{plain}%
\parindent=0ex
%==================[eof margin-adjustments]=====================================
\usepackage{pgfkeys}
\begin{document}
\begin{itemize}
\item Use \verb|\pgfkeys| for introducing keys and key-families and making keys
members of key-families; also use \verb|\pgfkeys| for adjusting the behavior of
the macros \verb|\pgfkeysfiltered| and \verb|\pgfqkeysfiltered|, i.e., for
selecting the key-filter which the macros \verb|\pgfkeysfiltered|/\hskip0pt
\verb|\pgfqkeysfiltered| shall apply, and configuring facilities of that
key-filter:
\begin{verbatim}
\pgfkeys{
%
% Introduce keys:
%
/SomeFamilys/Path/KeyE/.code=\par\noindent KeyE of Some Familys path has value: #1,
/SomeFamilys/Path/KeyF/.code=\par\noindent KeyF of Some Familys path has value: #1,
/First/Path/KeyA/.code=\par\noindent KeyA of first path has value: #1,
/First/Path/KeyB/.code=\par\noindent KeyB of first path has value: #1,
/Second/Path/KeyC/.code=\par\noindent KeyC of second path has value: #1,
/Second/Path/KeyD/.code=\par\noindent KeyD of second path has value: #1,
%
% Introduce key-families:
%
/SomeFamilys/Path/.is family,
%
% Make keys members of key-families:
%
/First/Path/KeyA/.belongs to family={/SomeFamilys/Path},
/Second/Path/KeyD/.belongs to family={/SomeFamilys/Path},
/SomeFamilys/Path/KeyF/.belongs to family={/SomeFamilys/Path},
%
% Let's configure the key-filtering done when applying the macro
% \pgf(q)keysfiltered:
%
% - Select the key-filter which filters for keys in activated key-families:
%
/pgf/key filters/active families/.install key filter,
%
% - Make the key-family /SomeFamilys/Path an activated key-family:
%
/SomeFamilys/Path/.activate family,
}%
\end{verbatim}
%
\pgfkeys{
/SomeFamilys/Path/KeyE/.code=\par\noindent KeyE of Some Familys path has value: #1,
/SomeFamilys/Path/KeyF/.code=\par\noindent KeyF of Some Familys path has value: #1,
/First/Path/KeyA/.code=\par\noindent KeyA of first path has value: #1,
/First/Path/KeyB/.code=\par\noindent KeyB of first path has value: #1,
/Second/Path/KeyC/.code=\par\noindent KeyC of second path has value: #1,
/Second/Path/KeyD/.code=\par\noindent KeyD of second path has value: #1,
/SomeFamilys/Path/.is family,
/First/Path/KeyA/.belongs to family={/SomeFamilys/Path},
/Second/Path/KeyD/.belongs to family={/SomeFamilys/Path},
/SomeFamilys/Path/KeyF/.belongs to family={/SomeFamilys/Path},
/pgf/key filters/active families/.install key filter,
/SomeFamilys/Path/.activate family,
}%
\item Use \verb|\pgfkeysfiltered| where you cannot specify keys in abbreviated
form:
\begin{verbatim}
\pgfkeysfiltered{
/First/Path/KeyA=A,
/First/Path/KeyB=B,
/Second/Path/KeyC=C,
/Second/Path/KeyD=D,
/SomeFamilys/Path/KeyE=E,
/SomeFamilys/Path/KeyF=F,
}%
\end{verbatim}
\noindent Result:
\pgfkeysfiltered{
/First/Path/KeyA=A,
/First/Path/KeyB=B,
/Second/Path/KeyC=C,
/Second/Path/KeyD=D,
/SomeFamilys/Path/KeyE=E,
/SomeFamilys/Path/KeyF=F,
}%
\vskip\topsep\vskip\partopsep
\noindent As you can see, only \verb|KeyA|, \verb|KeyD| and \verb|KeyF| are
carried out as \verb|\pgf(q)keysfiltered| is configured to filter for keys in
active key-families while only the key-family \verb|/SomeFamilys/Path| is
activated to which \verb|KeyB|, \verb|KeyC| and \verb|KeyE| do not belong.\\
(With \verb|\pgf(q)keysfiltered| by design you cannot use \verb|/.cd| and
abbreviate keys because key handlers like \verb|/.cd| actually are just keys
in a specific path and thus might be filtered out instead of being applied.)
\item Use \verb|\pgfqkeysfiltered| where you can specify one key-path in the 1st
argument, whose keys may be abbreviated:\\
(This time, too, only \verb|KeyA|, \verb|KeyD| and \verb|KeyF| are carried out
as \verb|\pgf(q)keysfiltered| is still configured to filter for keys in active
key-families while only the key-family \verb|/SomeFamilys/Path| is activated
to which \verb|KeyB|, \verb|KeyC| and \verb|KeyE| do not belong.)
\begin{verbatim}
\pgfqkeysfiltered{/First/Path}{
KeyA=A,
KeyB=B,
/Second/Path/KeyC=C,
/Second/Path/KeyD=D,
/SomeFamilys/Path/KeyE=E,
/SomeFamilys/Path/KeyF=F,
}%
\end{verbatim}
\noindent Result:
\vskip\topsep\vskip\partopsep
\pgfqkeysfiltered{/First/Path}{
KeyA=A,
KeyB=B,
/Second/Path/KeyC=C,
/Second/Path/KeyD=D,
/SomeFamilys/Path/KeyE=E,
/SomeFamilys/Path/KeyF=F,
}%
\vskip\topsep\vskip\partopsep
\item Use \verb|\pgfkeys| for resetting the behavior of the macros
\verb|\pgfkeysfiltered| and \verb|\pgfqkeysfiltered|:
\begin{verbatim}
\pgfkeys{
% Let's reset the key-filtering done when applying the macro \pgf(q)keysfiltered
% so that with \pgf(q)keysfiltered no filtering of keys takes place:
% - Make the key-family /SomeFamilys/Path a deactivated key-family:
/SomeFamilys/Path/.deactivate family,
% - Install/select the key-filter "true" which filters for every key:
/pgf/key filters/true/.install key filter,
}%
\end{verbatim}
%
\pgfkeys{
/SomeFamilys/Path/.deactivate family,
/pgf/key filters/true/.install key filter,
}%
\item Use \verb|\pgfkeysfiltered| where you cannot specify keys in abbreviated
form:\\
(All keys are carried out as now \verb|\pgf(q)keysfiltered| is configured to
filter for every key.)
\begin{verbatim}
\pgfkeysfiltered{
/First/Path/KeyA=A,
/First/Path/KeyB=B,
/Second/Path/KeyC=C,
/Second/Path/KeyD=D,
/SomeFamilys/Path/KeyE=E,
/SomeFamilys/Path/KeyF=F,
}%
\end{verbatim}
\noindent Result:
\vskip\topsep\vskip\partopsep
\pgfkeysfiltered{
/First/Path/KeyA=A,
/First/Path/KeyB=B,
/Second/Path/KeyC=C,
/Second/Path/KeyD=D,
/SomeFamilys/Path/KeyE=E,
/SomeFamilys/Path/KeyF=F,
}%
\item Use \verb|\pgfqkeysfiltered| where you can specify one key-path in the 1st
argument whose keys may be abbreviated:\\
(All keys are carried out as now \verb|\pgf(q)keysfiltered| is configured to
filter for every key.)
\begin{verbatim}
\pgfqkeysfiltered{/First/Path}{
KeyA=A,
KeyB=B,
/Second/Path/KeyC=C,
/Second/Path/KeyD=D,
/SomeFamilys/Path/KeyE=E,
/SomeFamilys/Path/KeyF=F,
}%
\end{verbatim}
\noindent Result:
\vskip\topsep\vskip\partopsep
\pgfqkeysfiltered{/First/Path}{
KeyA=A,
KeyB=B,
/Second/Path/KeyC=C,
/Second/Path/KeyD=D,
/SomeFamilys/Path/KeyE=E,
/SomeFamilys/Path/KeyF=F,
}%
\end{itemize}
\end{document}
答案2
允许.is family
使用您指定的路径作为,而.cd
无需您实际明确使用.cd
-handler。
这就是所有的魔法(至少在大多数情况下,见Ulrich Diez 的回答非常详细和精彩对于其他情况)。是的,您仍然可以.cd
明确使用,处理程序不会停止工作:
\RequirePackage{pgfkeys}
\pgfkeys{/foo/.is family, /foo/bar/.code=\typeout{bar used with #1}}
\pgfkeys{/foo/.cd, bar=baz}
\stop
印刷
bar used with baz
但是对于包选项,pgfopts
您不需要以下两者中的任何一个:
\pgfqkeys{/mypackage}{<key definitions>}
\ProcessPgfOptions{/mypackage}
(\pgfqkeys{/path}
与 相同\pgfkeys{/path/.cd}
但速度更快,在包代码中应优先使用)
话虽如此,我仍然建议你使用 LaTeX 新的内置机制来设置包选项(\DeclareKeys{<key definitions>}
然后\ProcessKeyOptions
),或者使用expkv-opt
(免责声明:我是作者)。如果您想与 KOMA 交互,另一个解决方案可能是提供的选项处理,scrbase
它也使用 LaTeX 的新选项处理机制(尽管我不确定它提供的确切功能范围)。