我最近学习了如何使用包创建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]
为了完成这个功能我必须克服两个挑战:
pgfkeys
对于使用 创建的每个新命令,递归创建的最佳策略是什么\commander
?- 我如何将
invert
的键的值传递作为新命令的键\commander
的默认值。invert
我希望有人能帮我一下。先行致谢。
PS:对于此命令,我正在使用/需要包graphicx
,pgfkeys
和tikz
以及(可选)类beamer
。
答案1
这个答案提供了两个代码版本,一个使用expkv-cs
,一个使用pgfkeys
-only。
使用expkv-cs
以下内容可用于此目的,但通过使用可避免使用pgfkeys
for的大部分扩展问题。优点是,只要您使用只有几个键的简单宏,方法就会为您提供用户作为宏参数提供的键值。\commander
expkv-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}