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
はframe
、次の手法を使用して本体を収集します。\begin{frame}
を検索した後、トークンを読み取り、1 つのケース (以下を参照) を除いて拡張せずに保存しますが、収集プロセス中にと同じ数の が見つかった場合にのみ、収集される環境本体の末尾として\end{frame}
を受け入れます(一致させようとはしません)。これは、fromの で使用されているものです。\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}
1 つをプッシュしますb
(つまり、1 レベル開きます) \beamer@begin@stack
。が読み取られるb
と、これがポップされます。この時点で、は の後にだけ見たことを認識しています。 これは正しいですが誤解を招きます。が展開されると、2 つのポップが生成されるためです。 そのため、は、次はを提供する必要があると考えます (おそらくトークンを展開した後で、脚注 1 を参照)。 残念ながら、これは正しくありません。次は です。がこのように展開され、を探し続けますが、もちろん見つからず、ファイルの末尾に到達して、エラーが発生します。\end{myframe}
\beamer@collect@@body
\begin{...}
\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
つまり、基本的に、問題は がこれら 2 つ ( ) を隠しており、 が存在するにもかかわらず の展開によってこれらを発見できないため、 が を適切にカウントできないということです。これは、がこれ\beamer@collect@@body
を見つけた時点でよりも多く見ているからです( によりスタックが空ではありません)。\end{...}
\end{myframe}
\end{itemize}\end{frame}
\beamer@collect@@body
\endmyframe
\end{myframe}
\begin{...}
\end{...}
\end{myframe}
\begin{itemize}
解決策としては、展開されない\end{...}
マクロに隠れないようにする必要があります。1つは、次のようにパッケージを使用することです。\beamer@collect@@body
environ
ferahfeza の回答、もう 1 つは\itemize
と\enditemize
を次のように使用しています (どちらもスタックには影響しないため、が を見た\beamer@begin@stack
ときにスタックは空であり、 が1 回展開され、環境本体のスキャン プロセスに対して が見えるようになります)。\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
第一レベルの展開で置き換えます。これは展開によって生成されるものと似ていますが、後者ではさらにいくつかの処理が行われます ( p. 272 を参照)。\endfoobar\endgroup
\end{foobar}
\end{foobar}
source2e.pdf
- の置換テキストが
\@currenvir
であることを確認します (の場合と同様に、これは、ここで説明している本体収集プロセスfoobar
では失敗します)。beamer
frame
\@currenvir
frame
- 前の
\@endparenv
コマンドを尊重する (テキストの前に空白行または がない限り、段落作成環境に続くテキストの先頭の段落インデントを抑制するために使用されます\par
)。 - 前の
\ignorespacesafterend
コマンドを尊重します (次のコマンド\end{...}
に続くスペースを無視させるために使用されます)。
- スタック