如何创建“环境依赖”的宏

如何创建“环境依赖”的宏

昨天我在读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宏被初始化为空。

相关内容