如何创建一个创建命令的命令?

如何创建一个创建命令的命令?

我最近学习了如何使用包创建key=value命令pgfkeys。我目前正在尝试定义一个命令,我们称之为\commander,它带有key=value可以定义新命令的选项,还可以使用key=value函数。(类似于超级命令或元命令。)的语法\commander大致如下:

\commander[color=red,pos=up,invert=false]{\thenewcommand}

我们的\thenewcommand预计会具有 的一些(但不是全部) 相同的key=value选项\commander;此外,它们的默认值必须是 调用的值(或如果没有明确调用,则为\commander的默认值)。例如,如果定义如上,则调用:\commander\thenewcommand

\thenewcommand[color=blue]

与调用以下命令相同:

\thenewcommand[color=blue,pos=up,invert=false]

我已经朝着定义迈出了一些步伐\commander。以下是它的pgfkeys

\newif\ifcommanderinvert
\pgfkeys{
    /commander/.is family, /commander,
    % "commander" options
    color/.estore in = \commanderColor,
    pos/.estore in = \commanderPos,
    invert/.is if=commanderinvert,
    % Ignore this: It is just for showing that I'm using the .unknown feature
    .unknown/.code={\edef\commanderUnk{\commanderUnk,\pgfkeyscurrentname=#1}},%
}

以下是的不完整定义\commander

% (Optional) argument #1 is for the options
% (Non-optional) argument #2 is the name of the new command
%                                    (e.g.: \thenewcommand)
\newcommand{\commander}[2][]{%
% Loading \commander's pgfkeys
\pgfkeys{/commander,%
    color=black,%
    pos=up,%
    invert=false,#1}%
%
% Here goes some code 
Code...
%
% Here I define the pgfkeys for \thenewcommand.
% Every appearance of the string "thenewcommand" has to be replaced
% by the actual name of our new command or an abbreviation.
% Else, we risk making conflicting names each time we call \commander.
\newif\ifthenewcommandinvert
\pgfkeys{
    /thenewcommand/.is family, /thenewcommand,
    % "thenewcommand" options
    % Notice I'm not using the "pos" option
    color/.estore in = \thenewcommandColor,
    invert/.is if=thenewcommandinvert,
}
% Defining \thenewcommand: it only has optional arguments
% Notice that the name of the new command is #2 of \commander
\newcommand{#2}[1][]{%
\pgfkeys{/thenewcommand,%
    color=\commanderColor,%
    %invert=?,
    % How do I pass here the value of /commander invert/?
    #1}%
% Here goes some code
\ifthenewcommandinvert%
    Code...%
\else%
    Code...\fi%
% (By the way, how can I distinctly refer to
% argument #1 of \commander and to argument #1 of \thenewcommand?)
}

根据这样的定义,如果我们调用\commander如下命令:

\commander[color=blue]{\bluecommand}

然后调用:

\bluecommand[invert=true]

必须与调用相同:

\bluecommand[color=blue,pos=up,invert=true]

为了完成这个功能我必须克服两个挑战:

  1. pgfkeys对于使用 创建的每个新命令,递归创建的最佳策略是什么\commander
  2. 我如何将invert的键的值传递作为新命令的键\commander的默认值。invert

我希望有人能帮我一下。先行致谢。

PS:对于此命令,我正在使用/需要包graphicxpgfkeystikz以及(可选)类beamer

答案1

这个答案提供了两个代码版本,一个使用expkv-cs,一个使用pgfkeys-only。

使用expkv-cs

以下内容可用于此目的,但通过使用可避免使用pgfkeysfor的大部分扩展问题。优点是,只要您使用只有几个键的简单宏,方法就会为您提供用户作为宏参数提供的键值。\commanderexpkv-cs\ekvcSplit

\documentclass{article}

\usepackage{pgfkeys}
\usepackage{expkv-cs}

\makeatletter
\newcommand*\commander[1][]{\commander@k{#1}}
\newif\ifcommander@invert
\ekvcSplitAndForward\commander@k\commander@d
  {
     color = black
    ,pos = up
    ,invert = false
  }
\pgfqkeys{/commander}%
  {%
    .is family
    ,color/.store in = \commander@color
    ,pos/.store in = \commander@pos
    ,invert/.is if=commander@invert
    ,.unknown/.code=%
      {\edef\commander@unk{\commander@unk,\pgfkeyscurrentname={##1}}}%
  }
\newcommand\commander@d[4]
  {%
    \newcommand#4[1][]
      {%
        \begingroup
          \pgfqkeys{/commander}{color={#1},pos={#2},invert={#3},##1}%
          \ifcommander@invert
            \commander@color\space code being inverted at \commander@pos
          \else
            \commander@color\space code at \commander@pos
          \fi
        \endgroup
      }%
  }
\makeatother

\commander[color=blue]\thenewcommand
\commander[invert=true]\thenewcommandinvert

\begin{document}
\thenewcommand

\thenewcommand[color=green,invert=false]

\thenewcommandinvert

\thenewcommandinvert[color=green,invert=false]
\end{document}

仅使用pgfkeys

此版本使用临时定义\commander@tmp,有助于扩展键的当前值。

\documentclass{article}

\usepackage{pgfkeys}

\makeatletter
\newcommand\commander[2][]
  {%
    \begingroup
    \pgfqkeys{/commander}{#1}%
    \edef\commander@tmp % <- shouldn't be used by a key
      {%
        \endgroup
        \unexpanded{\newcommand#2[1][]}%
          {%
            \begingroup
            \unexpanded{\pgfqkeys{/commander}}%
              {%
                 color={\unexpanded\expandafter{\commander@color}}%
                ,pos={\unexpanded\expandafter{\commander@pos}}%
                ,invert=\ifcommander@invert true\else false\fi
                ,####1%
              }%
            \unexpanded{\commander@code}%
            \endgroup
          }%
      }%
    \commander@tmp
  }
\newcommand\commander@code
  {%
    \ifcommander@invert
      \commander@color\space code being inverted at \commander@pos
    \else
      \commander@color\space code at \commander@pos
    \fi
  }
\newif\ifcommander@invert
\pgfqkeys{/commander}%
  {%
    .is family
    ,color/.store in = \commander@color
    ,color=black
    ,pos/.store in = \commander@pos
    ,pos=up
    ,invert/.is if=commander@invert
    ,invert=false
    ,.unknown/.code=%
      {\edef\commander@unk{\commander@unk,\pgfkeyscurrentname={##1}}}%
  }
\makeatother

\commander[color=blue]\thenewcommand
\commander[invert=true]\thenewcommandinvert

\begin{document}
\thenewcommand

\thenewcommand[color=green,invert=false]

\thenewcommandinvert

\thenewcommandinvert[color=green,invert=false]
\end{document}

两者的输出

在此处输入图片描述

相关内容