是否可以定义接受具有类似 xparse 语法的值的 pgf 键?

是否可以定义接受具有类似 xparse 语法的值的 pgf 键?

pgfkeys软件包具有 /.code处理程序,允许定义用户设置键时要执行的代码,就像它执行了以 作为#1值的宏一样。/.code args处理程序允许以 -style 提供实际参数列表,\def以便可以定义花哨的键,例如rectangle/.code args={#1 by #2}{...}可以设置为rectangle=13 by 12

我的问题是:是否有一些包可以xparse与之集成pgfkeys以便使用xparse类似语法(例如{m o m})来定义键的参数?

例子:

\pgfkeys{my key/.xparse code={o m}{\def\mykey{Required: #2, Optional: #1}}}
\pgfkeys{my key = [Hello]{John}} % prints 'Required: John, Optional: Hello'

答案1

除了定义自己的 DocumentCommand 并手动将所有内容从 PGFkeys 转发到那里之外,还可以说

\NewDocumentCommand\myKey{o m}{<stuff>}
\pgfkeys{my key/.code=\myKey#1}

我们可以使用执行相同操作的处理程序来完成此操作。

my key/.xparse code = {o m}{<stuff>}

可以与

my key = [opt]{mand}

并且它会正常工作:

\myKey[opt]{mand}

但是,当不带可选参数使用时,例如

my key = mand
% or
my key = {mand}

PGFkeys 将丢失一些括号,并且调用\myKey将是

\myKey mand

它只会抓住m#2离开and

我们需要my key = {{{{mand}}}}


PGFkeys 的工作方式与\newcommands 或\NewDocumentCommands 有很大不同:每个 key-macro 都是一个分隔宏,其参数和带有\pgfeov。在内部,所有 key-macro 都会附加此参数。

不幸的是,xparse不提供相同的接口,它只知道

  • t→ 可选标记(将切换布尔值)和
  • u→ 强制性论点直到遇到指定的标记。

我选择了后者。这意味着,每一个

key/.xparse code={<args>}{<code>}

实际上将用参数来定义<args> u\pgfeov

这使得 PGFkeys 的使用非常方便,xparse但有一个注意事项:用户始终必须输入最后一个参数才不是指定。

这不是很好,但我还是要重申一下我的建议xparse:保持简单(释义)。不要在最后添加任何花哨的论点。

在您的情况下,您只需使用o,因为最后的强制性参数是强制性的。

\pgfkeys{my key/.xparse code={o}{Required: #2, Optional: #1}}

几点说明:

  • 如果你需要.append xparse code并且类似的东西需要做更多的工作,不过我有一些想法。

  • 我在下面的代码中明确展示了几乎唯一的坏情况,不要灰心。

  • 我正在使用,\DeclareDocumentCommand因为这只会覆盖宏(就像 PGFkeys 所做的那样.code),即使xparse手册建议不要这样做:

    应谨慎使用此方法。

代码

\documentclass{article}
\usepackage{pgfkeys,xparse,tabularx}
\pgfqkeys{/handlers}{
  .xparse code/.code 2 args={%
    \expandafter\DeclareDocumentCommand
      \csname pgfk@\pgfkeyscurrentpath/.@cmd\endcsname
      {#1u\pgfeov}{#2}%
    % probably useless unless .xparse append code is needed
    %\pgfkeyssetvalue{\pgfkeyscurrentpath/.@args}{#1u\pgfeov}%
    %\pgfkeyssetvalue{\pgfkeyscurrentpath/.@body}{#2}%
  },
  .xparse style/.code 2 args=%
    \pgfkeysalso{\pgfkeyscurrentpath/.xparse code={#1}{\pgfkeysalso{#2}}},
}
\newcommand*\doKey[2]{\texttt{\detokenize{#1}} & \pgfkeys{#1}
  \ifx\\#2\\\else\par\def\tt##1 {\texttt{##1} }\sffamily$\to$ #2\fi\\}
\parindent=0pt
\begin{document}
\pgfkeys{my key1/.xparse code   = { o }{Required1: #2, Optional1: #1}}
\pgfkeys{my key2/.xparse code   = { o }{Required2: #2, Optional2: #1}}
\pgfkeys{my style/.xparse style = { o o }%
                {my key1 = [1]{#1}, /utils/exec=\par, my key2 = {#2}}}

\begin{tabularx}{\linewidth}{l X}
  \doKey{my key1  = [Hello]{John}}{}
  \doKey{my key2  = John2        }{}
  \doKey{my style = [Foo]Bar     }{\tt Bar is lost (and no error message)}
\end{tabularx}

\vspace{1ex}% without the #4
\pgfkeys{omo/.xparse code={omo}{Opt1: #1, Req2: #2, Opt2: #3}}
\begin{tabularx}{\linewidth}{l X}
  \doKey{omo = [opt1]{Foo}[opt3]}{}
  \doKey{omo = [opt1]{FooBar}   }{}
  \doKey{omo = {FooBar}         }{\tt ooBar is lost}
  \doKey{omo = {Foo}Bar         }{\tt Bar is lost}
\end{tabularx}

\vspace{1ex}% as above but with #4 after the #2
\pgfkeys{omo/.xparse code={O{--}mO{--}}{Opt1: #1, Req2: #2#4, Opt2: #3}}
\begin{tabularx}{\linewidth}{l X}
  \doKey{omo = [opt1]{Foo}[opt3]}{}
  \doKey{omo = [opt1]{FooBar}   }{}
  \doKey{omo = {FooBar}         }{ooBar is lost}
  \doKey{omo = {Foo}Bar         }{Bar is caught}
\end{tabularx}
\end{document}

相关内容