![向现有命令/环境添加可选参数](https://linux22.com/image/444734/%E5%90%91%E7%8E%B0%E6%9C%89%E5%91%BD%E4%BB%A4%2F%E7%8E%AF%E5%A2%83%E6%B7%BB%E5%8A%A0%E5%8F%AF%E9%80%89%E5%8F%82%E6%95%B0.png)
假设我想创建一个新的环境,它是类的副本beamer
,frame
但它允许人们随意放置(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}