Ich möchte es neu definieren frame
als frame + itemize
. Ich habe bisher Folgendes versucht -
\documentclass{beamer}
\newenvironment{myframe}{\begin{frame}\begin{itemize}}{\end{itemize}\end{frame}}
\begin{document}
\begin{myframe}
\item
\end{myframe}
\end{document}
Was genau ist daran falsch und wie kann man dies dann richtig neu definieren?
Antwort1
Die beamer
Umgebung frame
sammelt ihren Körper mithilfe der folgenden Technik: Sie liest und speichert Token, die auf \begin{frame}
die Suche nach folgen \end{frame}
, ohne sie zu erweitern, außer in einem Fall (siehe unten), aber sie akzeptiert ein als Ende des zu sammelnden Umgebungskörpers nur, wenn sie während dieses Sammlungsprozesses \end{frame}
dieselbe Anzahl von \begin{...}
wie gesehen hat (sie versucht nicht, sie abzugleichen). Dies wird für in von verwendet .\end{...}
\beamer@begin@stack
\beamer@collect@@body
beamerbaseframe.sty
Falls der Stapel leer ist (d. h. er hat so viele gesehen \end{...}
wie \begin{...}
nach \begin{frame}
) und das Folgende \end{...}
kein ist \end{frame}
, erweitert er dies \end
in der Hoffnung, dass dies erscheinen wird \end{frame}
. 1 Aber diesnurgeschieht unter der von mir angegebenen Bedingung (so viele \end{...}
wie \begin{...}
nach dem Initial \begin{frame}
gesehen worden sein müssen).
In Ihrem Beispiel schiebt (d. h. öffnet eine Ebene) der \begin{itemize}
eine auf den Stapel. Dieser wird beim Lesen von herausgeholt. An diesem Punkt weiß , dass er genauso viele gesehen hat wie nach dem . Das ist richtig, aber irreführend, denn wenn erweitert würde, würde es zwei Herausholvorgänge ergeben. Also denkt , dass der nächste liefern muss , möglicherweise nach dem Erweitern des Tokens (siehe Fußnote 1). Leider ist das falsch; der nächste ist . wird also erweitert, sucht dann weiter nach , findet es aber natürlich nie, erreicht das Ende der Datei, was den Fehler auslöst:b
\beamer@begin@stack
b
\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
Das Problem besteht also grundsätzlich darin, dass \beamer@collect@@body
Sie die nicht richtig zählen können, \end{...}
da Ihr \end{myframe}
zwei davon ( \end{itemize}\end{frame}
) verbirgt und \beamer@collect@@body
sie \endmyframe
trotz des Vorhandenseins von nicht durch die Erweiterung von entdecken wird, da es an dem Punkt, an dem es dies sieht, \end{myframe}
mehr gesehen hat \begin{...}
als (nicht leerer Stapel aufgrund von ).\end{...}
\end{myframe}
\begin{itemize}
\end{...}
Die Lösungen erfordern, dass Sie sich nicht in Makros verstecken , die \beamer@collect@@body
nicht erweitert werden. Eine davon ist die Verwendung des environ
Pakets wie inferahfezas Antwort, ein anderer verwendet \itemize
und \enditemize
wie folgt (keiner von beiden beeinflusst den \beamer@begin@stack
Stapel, daher ist der Stapel leer, wenn \beamer@collect@@body
gesehen wird \end{myframe}
, und \endmyframe
wird daher einmal erweitert, wodurch der \end{frame}
Körperscanvorgang für die Umgebung sichtbar wird):
\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}
Fußnote
Genauer gesagt passiert Folgendes (in
beamer 2018/12/02 v3.55
). Wenn:- der
\beamer@begin@stack
Stapel leer ist (so viele,\end{...}
wie nach dem Einsammeln der Leiche\begin{...}
gesehen wurden ) und\begin{frame}
- das nächste
\end{...}
ist kein\end{frame}
– sagen wir, es ist ein\end{foobar}
,
ersetzt dann
\beamer@collect@@body
die Erweiterung der ersten Ebene von\endfoobar\endgroup
durch this\end{foobar}
im gesammelten Material. Dies ist ähnlich dem, was die Erweiterung\end{foobar}
erzeugen würde, obwohl letzteres noch ein paar weitere Dinge bewirken würde (siehesource2e.pdf
S. 272):- Überprüfen Sie, ob der Ersetzungstext von
\@currenvir
lautetfoobar
(dies würde imbeamer
frame
Textkörper-Sammelprozess, von dem wir sprechen, fehlschlagen, da\@currenvir
lautetframe
); - einen vorherigen
\@endparenv
Befehl berücksichtigen (wird verwendet, um die Absatzeinrückung am Anfang von Text nach einigen Umgebungen zur Absatzerstellung zu unterdrücken, es sei denn, dem Text geht eine Leerzeile oder ein\par
) voraus; - einen vorherigen
\ignorespacesafterend
Befehl berücksichtigen (wird verwendet, um den nächsten dazu zu bringen\end{...}
, die möglicherweise folgenden Leerzeichen zu ignorieren).
- der