我想重新定义frame
为frame + itemize
。到目前为止,我已经尝试过这个 -
\documentclass{beamer}
\newenvironment{myframe}{\begin{frame}\begin{itemize}}{\end{itemize}\end{frame}}
\begin{document}
\begin{myframe}
\item
\end{myframe}
\end{document}
这到底是什么问题?如何正确地重新定义它?
答案1
环境使用以下技术收集其主体:它读取并存储查找后的标记beamer
,除了一种情况(见下文)外,不会扩展它们,但只有当它在此收集过程中看到相同数量的as时,它才会接受作为正在收集的环境主体的末尾(它不会尝试匹配它们)。这就是from中 for 的使用。frame
\begin{frame}
\end{frame}
\end{frame}
\begin{...}
\end{...}
\beamer@begin@stack
\beamer@collect@@body
beamerbaseframe.sty
如果堆栈为空(即,它已经看到了之后的\end{...}
),并且后面不是,它会扩展这个,希望这会出现。1但是这个\begin{...}
\begin{frame}
\end{...}
\end{frame}
\end
\end{frame}
仅有的发生在我给出的条件下(初始之后的\end{...}
次数必须被看到)。\begin{...}
\begin{frame}
在您的示例中,\begin{itemize}
将一个b
(即打开一个级别)推送到堆栈\beamer@begin@stack
。读取b
时弹出\end{myframe}
。此时,\beamer@collect@@body
知道在之后已经看到了\begin{...}
与。这是正确的,但具有误导性,因为如果展开,它会产生两次弹出。因此,认为下一个必须提供,可能在展开标记之后(参见脚注 1)。唉,这是不正确的;下一个是。因此展开,然后继续寻找但当然永远找不到它,到达文件末尾,从而触发错误:\end{...}
\begin{frame}
\end{myframe}
\beamer@begin@stack
\end{...}
\end{frame}
\end...
\end{...}
\end{document}
\enddocument
\beamer@collect@@body
\end{frame}
Runaway argument?
\let \AtEndDocument \@firstofone \@enddocumenthook \@checkend {docume\ETC.
! File ended while scanning use of \beamer@collect@@body.
<inserted text>
\par
因此,基本上,问题在于\beamer@collect@@body
无法保持对的正确计数,\end{...}
因为您的\end{myframe}
隐藏了其中两个(\end{itemize}\end{frame}
)并且尽管存在,\beamer@collect@@body
也不会通过扩展发现它们,因为在看到这个时它已经看到了超过(由于非空堆栈)。\endmyframe
\end{myframe}
\begin{...}
\end{...}
\end{myframe}
\begin{itemize}
解决方案要求你不要隐藏在不会扩展的\end{...}
宏中。一种方法是使用如下包\beamer@collect@@body
environ
Ferahfeza 的回答,另一种是使用\itemize
和\enditemize
如下(它们都不影响堆栈\beamer@begin@stack
,因此当\beamer@collect@@body
看到时\end{myframe}
,堆栈是空的,从而\endmyframe
被扩展一次,这使得\end{frame}
对环境主体扫描过程可见):
\documentclass{beamer}
\newenvironment*{myframe}[1]
{\begin{frame}{#1}%
\begingroup\itemize}
{\enditemize\endgroup
\end{frame}}
\begin{document}
\begin{myframe}{Frame title}
\item An item
\item Another item
\end{myframe}
\end{document}
脚注
更准确地说,会发生以下情况(在
beamer 2018/12/02 v3.55
)。如果:- 堆栈
\beamer@begin@stack
为空(在收集其主体之后已看到的\end{...}
一样多),并且\begin{...}
\begin{frame}
- 下一个
\end{...}
不是\end{frame}
——假设它是一个\end{foobar}
,
然后用
\beamer@collect@@body
的第一级扩展替换收集到的材料中的\endfoobar\endgroup
this 。这与扩展产生的效果类似,尽管后者会做更多的事情(参见第 272 页):\end{foobar}
\end{foobar}
source2e.pdf
- 检查 的替换文本
\@currenvir
是否为foobar
(这会在beamer
frame
我们正在讨论的正文收集过程中失败,因为\@currenvir
是frame
); - 遵守前一条
\@endparenv
命令(用于在某些段落制作环境之后抑制文本开头的段落缩进,除非所述文本前面有一个空行或\par
); - 遵守前一个
\ignorespacesafterend
命令(用于使下一个命令\end{...}
忽略可能跟在其后的空格)。
- 堆栈