昨天我在读etoolbox
文档其中定义了一些新的文档命令,例如:
\Before<Begin/End>Environment{<envir>}{<code>}
%
\At<Begin/End>Environment{<envir>}{<code>}
%
\After<Begin/End>Environment{<envir>}{<code>}
我发现它在处理特定环境内部或外部的微调宏扩展时非常有用。
然而,当我想根据上述内容定义一个新命令时,主要问题出现了,如下所示:
\If<Before/At/After><Begin/End>Environment{<envir>}{<code>}{%
<yes>%
}{%
<no>%
}
此代码的主要作用是检查特定的控制序列名称或宏/代码是否<code>
出现<Before/At/After><Begin/End>
,environment
然后如果满足所述条件则应用代码,否则执行其他操作。这类似于纯 TeX 中众所周知的标准 if 子句条件(也许一些 TeXpert 可以关注这个宏)。
它读取控制序列名称的主要原因是,如果特定环境后面存在某个宏,它就不会扩展其参数并继续将其作为 读取csname
。
所以我的问题可以表达为:如何创建这个宏?是否有一些我不知道的命令可以模拟其操作?
我基本上找不到任何与该应用程序的宏设置相关的文档或来源。
答案1
\documentclass{article}
\usepackage{listings}
\def\foo{\futurelet\tmp\xfoo}
\def\xfoo{\ifx\tmp\begin\expandafter\xxfoo\else\expandafter\nolistingsfoo\fi}
\def\xxfoo#1#2{\def\tmp{#2}%
\ifx\tmp\xlistings\expandafter\listingsfoo\else\expandafter\nolistingsfoo\fi
#1{#2}}
\def\xlistings{lstlisting}
\def\listingsfoo{\typeout{lstlisting is next}}
\def\nolistingsfoo{\typeout{lstlisting is not next}}
\begin{document}
\foo
\begin{lstlisting}
\end{lstlisting}
\foo
\begin{center}
\end{center}
\foo xxxx
\begin{lstlisting}
\end{lstlisting}
\end{document}
生产
lstlisting is next
lstlisting is not next
lstlisting is not next
答案2
代码比 David 的要长,但展示了如何以更抽象的方式做到这一点。
\documentclass{article}
\usepackage{xparse,listings}
\ExplSyntaxOn
\NewDocumentCommand{\newcheckcommand}{mm}
{
\andrea_new_check_command:Nn #1 { #2 }
}
\tl_new:N \l_andrea_prefix_tl
\cs_new_protected:Npn \andrea_new_check_command:Nn #1 #2
{
\cs_if_exist:NTF #1
{ Damn! } % probably a better message is needed
{ \andrea_def_check_command:Nn #1 { #2 } }
}
\cs_new_protected:Npn \andrea_def_check_command:Nn #1 #2
{
\cs_new:Npn #1 { \andrea_check:N #1 }
\tl_set:Nx \l_andrea_prefix_tl { \cs_to_str:N #1 @ }
\keys_set:nn { andrea/check } { default = {} }
\keys_set:nn { andrea/check } { #2 }
}
\keys_define:nn { andrea/check }
{
unknown .code:n = \cs_new:cpn { \l_andrea_prefix_tl \l_keys_key_tl } { #1 } ,
default .code:n = \cs_gset:cpn { \l_andrea_prefix_tl default } { #1 } ,
}
\cs_new:Npn \andrea_check:N #1
{
\peek_meaning_ignore_spaces:NTF \begin
{
\andrea_exec:NNn #1
}
{
\use:c { \cs_to_str:N #1 @ default }
}
}
\cs_new:Npn \andrea_exec:NNn #1 #2 #3
{
% #2 is \begin, #3 is the environment's name
\cs_if_exist:cTF { \cs_to_str:N #1 @ #3 }
{
\use:c { \cs_to_str:N #1 @ #3 }
}
{
\use:c { \cs_to_str:N #1 @ default }
}
#2{#3} % put back the \begin{...}
}
\ExplSyntaxOff
\newcheckcommand{\foo}{
lstlisting = \texttt{lstlisting} comes next,
quotation = \texttt{quotation} comes next,
default = I don't know what to do
}
\begin{document}
\foo
\begin{lstlisting}
x
\end{lstlisting}
\foo
\begin{center}
y
\end{center}
\foo
\begin{quotation}
z
\end{quotation}
\foo xxxx
\begin{lstlisting}
t
\end{lstlisting}
\end{document}
通过调用\newcheckcommand{\foo}{...}
定义了一组宏;唯一已知的键是default
;如果它没有在参数中设置,则不会执行任何操作,因为default
宏被初始化为空。