向现有命令/环境添加可选参数

向现有命令/环境添加可选参数

假设我想创建一个新的环境,它是类的副本beamerframe但它允许人们随意放置(something)在末尾以改变的行为frame。我仍然想捕捉手册中描述的原始“框架”环境的复杂性:\begin{frame}<⟨overlay specification⟩>[<⟨default overlay specification⟩>][⟨options⟩]{⟨title⟩}{⟨subtitle⟩}

有没有一种规范的方法可以做到这一点而又不会变得太混乱?

\documentclass{beamer}

\NewDocumentEnvironment{myframe}{d<> o o m m d() +b}{%
\begin{frame}% some conditional and expansion magic here to only include #1, #2, etc. if they are provided
~~does something with (#6)
#7
\end{frame}
}{}

\begin{document}

\end{document}

答案1

也许 xparser 的已弃用的 g-type-argument 可以解决这个问题。

但是您还需要检查方括号中的可选参数,以便<确定默认覆盖规范。

\documentclass{beamer}
\usepackage{xparse}

\makeatletter
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\expandafter\UD@stopromannumeral\@secondoftwo}{%
  \expandafter\UD@stopromannumeral\@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether start has a leading <
%%.............................................................................
%% \UD@CheckWhetherLeadingExplicitSpace{<Argument which is to be checked>}%
%%                                     {<Tokens to be delivered in case <argument
%%                                       which is to be checked> does have a
%%                                       leading "<"-token>}%
%%                                     {<Tokens to be delivered in case <argument
%%                                       which is to be checked> does not have a
%%                                       a leading "<"-token>}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@CheckWhetherLeadingLower[1]{%
  \romannumeral\UD@CheckWhetherNull{#1}%
  {\expandafter\UD@stopromannumeral\UD@secondoftwo}%
  {%
    % Let's nest things into \UD@firstoftwo{...}{} to make sure they are nested in braces
    % and thus do not disturb when the test is carried out within \halign/\valign:
    \expandafter\@firstoftwo\expandafter{%
      \expandafter\expandafter\expandafter\UD@stopromannumeral
      \romannumeral\expandafter\@secondoftwo
      \string{\UD@CheckWhetherLeadingLowerB.#1<}{}%
    }{}%
  }%
}%
\@ifdefinable\UD@CheckWhetherLeadingLowerB{%
  \long\def\UD@CheckWhetherLeadingLowerB#1<{%
    \expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
    {\UD@Exchange{\@firstoftwo}}{\UD@Exchange{\@secondoftwo}}%
    {\expandafter\expandafter\expandafter\UD@stopromannumeral
     \expandafter\expandafter\expandafter}%
     \expandafter\@secondoftwo\expandafter{\string}%
  }%
}%
\NewDocumentEnvironment{myframe}{d<> o o g g d()}{%
  \IfNoValueTF{#5}{\@firstofone}{\UD@Exchange{{#5}}}{%
    \IfNoValueTF{#4}{\@firstofone}{\UD@Exchange{{#4}}}{%
      \IfNoValueTF{#3}{%
        \IfNoValueTF{#2}{\UD@Exchange{[{environment=myframe,fragile}]}}%
                       {%
                          \UD@CheckWhetherLeadingLower{#2}{%
                            \UD@Exchange{[#2]}%
                          }{%
                            \UD@Exchange{[environment=myframe,fragile,#2]}%
                          }%
                       }%
      }{%
        \IfNoValueTF{#2}{%
                          % This case should never happen.
                          \UD@CheckWhetherLeadingLower{#3}{%
                            \UD@Exchange{[#3]}%
                          }{%
                            \UD@Exchange{[environment=myframe,fragile,#3]}%
                          }%
                        }%
                        {%
                          \UD@CheckWhetherLeadingLower{#2}{%
                            \UD@CheckWhetherLeadingLower{#3}{%
                              % This should not happen:
                              \UD@Exchange{[#2][#3]}%
                            }{%
                              \UD@Exchange{[#2][environment=myframe,fragile,#3]}%
                            }%
                          }{%
                            \UD@CheckWhetherLeadingLower{#3}{%
                              % This should not happen:
                              \UD@Exchange{[environment=myframe,fragile,#2][#3]}%
                            }{%
                              % This should not happen:
                              \UD@Exchange{[environment=myframe,fragile,#2][environment=myframe,fragile,#3]}%
                            }%
                          }%
                        }%
      }{%
        \IfNoValueTF{#1}{\@firstofone}{\UD@Exchange{<#1>}}{\begin{frame}}%
      }%
    }%
  }%
  \IfNoValueF{#6}{does something with (#6)}%
}{\end{frame}}
\makeatother

\begin{document}

\begin{myframe}(bla)
blubb
\end{myframe}

\end{document}

在此处输入图片描述

相关内容