从中interface3.pdf
我们可以看到提供了几个关键属性,l3keys
例如.code:n
,,.tl_set:N
.usage:n
但我不知道如何定义一个新的关键属性。
此时我的代码是这样的:
\keys_define:nn {test}
{
keya .code:n = \somemacro {#1},
keyb .code:n = \othermacro {#1},
}
现在我想定义一个新的键属性,.mycode:n
以便
\keys_define:nn {test}
{
keya .mycode:n = \somemacro {#1},
keyb .mycode:n = \othermacro {#1},
}
是相同的
\keys_define:nn {test}
{
keya .code:n = \MyFunction \somemacro {#1},
keyb .code:n = \MyFunction \othermacro {#1},
}
我该怎么做? 其中包括一个最小示例:
\documentclass{article}
\begin{document}
\newcommand\somemacro[1]{\detokenize{#1}}
\newcommand\othermacro[1]{\detokenize{#1}}
\newcommand\MyFunction[2]{\detokenize{#1,#2}}
\ExplSyntaxOn
\keys_define:nn {test}
{
keya .code:n = \somemacro {#1},
keyb .code:n = \othermacro {#1},
}
\keys_set:nn {test} {keya = a, keyb = b}
\keys_define:nn {test}
{
keya .code:n = \MyFunction \somemacro {#1},
keyb .code:n = \MyFunction \othermacro {#1},
}
\keys_set:nn {test} {keya = a, keyb = b}
\keys_define:nn {test}
{
keya .mycode:n = \somemacro {#1},
keyb .mycode:n = \othermacro {#1},
}
\keys_set:nn {test} {keya = a, keyb = b}
\ExplSyntaxOff
\end{document}
问题背景
最近我发现tcolorbox
了一个有趣的IfEmptyTF
键,你可以用它写
IfEmptyTF = {⟨token list⟩}{key=val1}{key=val2}
我决定tabularray
应该具有类似的功能,并且可以使界面对用户来说更自然、更强大:
key = \tlIfEmptyTF{⟨token list⟩}{\prgReturn{val1}}{\prgReturn{val2}}
在哪里\tlIfEmptyTF
函数来自functional
包。也就是说,用户可以functional
在值中使用包中的所有函数,并tabularray
应将其替换为其返回值。并且此功能仅在以下情况下才应启用:functional
用户加载库时才启用此功能。
为了实现这个新功能,同时保持代码更改最少,我认为在中定义一个新的关键属性是最好的解决方案l3keys
。
答案1
没有官方方法来添加新属性。由于属性可用于所有密钥创建,因此构成语言的一部分,因此添加新属性需要仔细考虑。(团队确实详细讨论了如何最好地为新选项处理程序添加“2e 友好”版本:最终我们确实例如 .if
同一命名空间中的别名.legacy_if_set:n
,但这并不是一个简单的决定。)
就其本身而言,.code:n
应谨慎使用:大多数键最好创建为设置变量,然后在运行时由代码查询。如果您想用多个键做类似的事情,我希望使用内部函数
\cs_new_protected:Npn \__mypkg_key_processor:nn #1#2
{
% Payload
}
\keys_define:nn { mypkg }
{
keya-a .code:n = \__mypkg_key_processor:nn { a } {#1} ,
keya-b .code:n = \__mypkg_key_processor:nn { b } {#1} ,
}
该团队目前正在考虑添加“后操作”属性。这可能会解决更容易允许“设置变量然后处理”的方法。(该问题专门出现在发布调试数据时,因此可能会添加更集中的属性。)
答案2
这显然是极其糟糕的作风(换句话说,不要这样做),但我认为这是实现你想要的目标的唯一方法。
\documentclass{article}
\begin{document}
\newcommand\somemacro[1]{\detokenize{#1}}
\newcommand\othermacro[1]{\detokenize{#1}}
\newcommand\MyFunction[2]{\detokenize{#1,#2}}
\ExplSyntaxOn
\cs_new_protected:cpn { key~prop~>~.mycode:n } #1
{ \__keys_cmd_set:nn \l_keys_path_str { \MyFunction #1 } }
\keys_define:nn {test}
{
keya .code:n = \somemacro {#1},
keyb .code:n = \othermacro {#1},
}
\keys_set:nn {test} {keya = a, keyb = b}
\keys_define:nn {test}
{
keya .code:n = \MyFunction \somemacro {#1},
keyb .code:n = \MyFunction \othermacro {#1},
}
\keys_set:nn {test} {keya = a, keyb = b}
\keys_define:nn {test}
{
keya .mycode:n = \somemacro {#1},
keyb .mycode:n = \othermacro {#1},
}
\keys_set:nn {test} {keya = a, keyb = b}
\ExplSyntaxOff
\end{document}
答案3
似乎 l3keys 目前不支持添加新的密钥处理程序。
如果您喜欢比 Joseph Wright 建议的代码更麻烦的代码:
如何使用\mymodule_mycode:nw{keya}...,
扩展为的宏并对的第二个参数keya.code=\MyFunction...,
进行一些e
扩展?\keys_define:nn
\ExplSyntaxOn
\cs_new:Npn \mymodule_mycode:nw #1 {\__mymodule_mycode:nw {#1}{}} % prevent brace-removal by ensuring a leading {} with delimited #2
\cs_new:Npn \__mymodule_mycode:nw #1#2, {\exp_not:n {#1.code = \MyFunction } \exp_not:n \exp_after:wN {\use_none:n #2,}}
\exp_args:Nne \keys_define:nn {test}
{
\mymodule_mycode:nw{keya} = \somemacro {#1},
\mymodule_mycode:nw{keyb} = \othermacro {#1},
% wrap things that shall not be affected by e-expansion into \exp_not:n
% ...
}
\ExplSyntaxOff
如果不是 l3keys 而是 pgfkeys,您可以/.mycode
通过将内容放入路径来实现密钥处理程序/handlers/
:
\documentclass{article}
\usepackage{pgfkeys}
\pgfkeys{%
/handlers/.mycode/.style={\pgfkeyscurrentpath/.code={\MyFunction #1}},
/MyPath/Worldkey/.mycode={World and #1!},
/MyPath/Moonkey/.mycode={Moon and #1!}
}
\def\MyFunction{Hello, }
\begin{document}
\pgfkeys{/MyPath/Worldkey={You}}
\pgfkeys{/MyPath/Moonkey={You}}
\end{document}