在开发版本的软件包中cleveref-usedon
,有一个命令\SetUsedByAndOnMessageStyle
,目前简单定义为
\NewDocumentCommand \SetUsedByAndOnMessageStyle { m }
{
\cs_set:Nn \__UsedByAndOnMessage:nn { #1 }
}
这样当用户写类似的东西时
\SetUsedByAndOnMessageStyle
{%
\todo{%
\UsedByAndOnMessageText{#1}{#2}%
}%
}
内部命令\__UsedByAndOnMessage:nn
应定义为指定的内容。但是,我希望用户能够编写
\SetUsedByAndOnMessageStyle
{%
\todo{%
#1% <--- Changed line
}%
}
并让命令\SetUsedByAndOnMessageStyle
将其替换#1
为\UsedByAndOnMessageText{#1}{#2}
。这可能吗?(例如,通过一些辅助宏?)
下面是 MWE。
\documentclass{article}
\usepackage{xcolor}
\ExplSyntaxOn
% Some preset for testing
\cs_new:Nn \__UsedByAndOnMessage:nn { }
\NewDocumentCommand \UsedByAndOnMessageText { m m }
{
\begin{enumerate}
\item #1
\item #2
\end{enumerate}
}
% This is the command to be improved
\NewDocumentCommand \SetUsedByAndOnMessageStyle { m }
{
\cs_set:Nn \__UsedByAndOnMessage:nn { #1 }
}
\NewDocumentCommand \test { m m }
{
\__UsedByAndOnMessage:nn { #1 } { #2 }
}
\ExplSyntaxOff
\begin{document}
\SetUsedByAndOnMessageStyle{
\color{red}
% \UsedByAndOnMessageText{#1}{#2} % This generates the ideal result
#1
}
\test{a}{b}
\end{document}
答案1
这是你想要的嗎?
\ExplSyntaxOn
\NewDocumentCommand \SetUsedByAndOnMessageStyle { m }
{
\cs_set:Npn \__UsedByAndOnMessage:nn ##1 { \cs_set:Nn \__UsedByAndOnMessage:nn { #1 } }
\__UsedByAndOnMessage:nn { \UsedByAndOnMessageText{##1}{##2} }
}
\SetUsedByAndOnMessageStyle
{
\todo{ #1 }
}
\cs_show:N \__UsedByAndOnMessage:nn
\SetUsedByAndOnMessageStyle{
\color{red}
% \UsedByAndOnMessageText{#1}{#2} % This generates the ideal result
#1
}
\cs_show:N \__UsedByAndOnMessage:nn
\stop
控制台输出:
pdflatex test.tex
This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2020-10-01> patch level 4
L3 programming layer <2021-02-18>
> \__UsedByAndOnMessage:nn=\long macro:#1#2->\todo {\UsedByAndOnMessageText
{#1}{#2}}.
<recently read> }
l.13 \cs_show:N \__UsedByAndOnMessage:nn
?
> \__UsedByAndOnMessage:nn=\long macro:#1#2->\color
{red}\UsedByAndOnMessageText {#1}{#2}.
<recently read> }
l.21 \cs_show:N \__UsedByAndOnMessage:nn
?
)
No pages of output.
Transcript written on test.log.
尝试给出一些解释:
乍一看可能会令人困惑,但您可以像任何其他非 -token 一样将哈希()作为宏参数的组成部分。#6\outer
乍一看,事情似乎很微妙,需要在嵌套宏定义中挑剔“哈希加倍”和在扩展宏时挑剔“哈希折叠”:
在展开宏时,一些标记来自定义宏时提供的宏的 ⟨replacement text⟩。其他标记来自展开宏时收集的宏的参数。
如果在定义宏时在 ⟨替换文本⟩ 中提供了两个连续的哈希值,那么在扩展宏时,这两个连续的哈希值会折叠成一个哈希值。
如果在 TeX 中定义\def\macro{\string##}
,则扩展\macro
会产生\string #
。
如果在 expl3 中定义\cs_new:Npn \macro{\token_to_str:N ##}
,则展开\macro
可得到\token_to_str:N #
。
这种“哈希值崩溃”就是为什么在定义内嵌套定义时可以/需要双重哈希值的原因。但刚刚提供的小定义表明,“哈希值崩溃”并不局限于在定义内嵌套定义。
需要注意的是,这种哈希折叠仅适用于定义时提供的⟨替换文本⟩的哈希。它不适用于在扩展宏时作为宏参数的组件收集的哈希。
通过\SetUsedByAndOnMessageStyle
您希望提供一个宏参数,该参数将形成宏的⟨替换文本⟩ \__UsedByAndOnMessage:nn
,而宏又需要两个参数。
使用该⟨替换文本⟩参数,您希望#1
将其替换为\UsedByAndOnMessageText{#1}{#2}
。
因此,第一步的想法是定义(通过\cs_new:Npn
,您可以在其中指定p
独立于要定义的宏名称签名的参数文本)的“临时变体” \__UsedByAndOnMessage:nn
,尽管签名:nn
只处理一个参数 -#1
您提供的\SetUsedByAndOnMessageStyle
“⟨替换文本⟩参数” - 并且重新定义自身以处理两个参数。
在第二步中,使用\UsedByAndOnMessageText{#1}{#2}
作为其参数来调用 scratch-variant,现在将其转换为 ⟨replacement text⟩ 而不是#1
。
例如,
\SetUsedByAndOnMessageStyle
{
\todo{ #1 }
}
使用\SetUsedByAndOnMessageStyle
的参数#1
= \todo{ #1 }
,并考虑到 的\SetUsedByAndOnMessageStyle
⟨替换文本⟩ 中的两个连续哈希折叠成一个哈希,得出:
\cs_set:Npn \__UsedByAndOnMessage:nn #1 { \cs_set:Nn \__UsedByAndOnMessage:nn { \todo{ #1 } } }
\__UsedByAndOnMessage:nn { \UsedByAndOnMessageText{#1}{#2} }
,因此第二行,
\__UsedByAndOnMessage:nn { \UsedByAndOnMessageText{#1}{#2} }
产量
\cs_set:Nn \__UsedByAndOnMessage:nn { \todo{ \UsedByAndOnMessageText{#1}{#2} } }