Enmarcar y detallar juntos

Enmarcar y detallar juntos

Quiero redefinir framecomo frame + itemize. Hasta ahora he probado esto.

\documentclass{beamer}
\newenvironment{myframe}{\begin{frame}\begin{itemize}}{\end{itemize}\end{frame}}

\begin{document}
\begin{myframe}
\item
\end{myframe}
\end{document}

¿Qué es exactamente lo que está mal en esto y luego cómo redefinirlo correctamente?

Respuesta1

El beamerentorno framerecolecta su cuerpo usando la siguiente técnica: lee y almacena tokens siguiendo \begin{frame}la búsqueda \end{frame}sin expandirlos excepto en un caso (ver más abajo), pero aceptará un \end{frame}como final del cuerpo del entorno que se recolecta solo si ha visto el el mismo número de \begin{...}que \end{...}durante este proceso de recopilación (no intenta igualarlos). Esto es lo que \beamer@begin@stackse utiliza en \beamer@collect@@bodyfrom beamerbaseframe.sty.

En caso de que la pila esté vacía (es decir, haya visto tantas \end{...}como \begin{...}después \begin{frame}) y lo siguiente \end{...}no sea un \end{frame}, lo expande con \endla esperanza de que aparezca \end{frame}. 1 Pero estosolosucede bajo la condición que di (tantas \end{...}como después de que se hayan visto \begin{...}las iniciales ).\begin{frame}

En su ejemplo, \begin{itemize}empuja uno b(es decir, abre un nivel) a la \beamer@begin@stackpila. Esto baparece cuando \end{myframe}se lee. En este punto, \beamer@collect@@bodysabe que ha visto tantos \begin{...}como \end{...}después del \begin{frame}. Esto es cierto pero engañoso, ya que si \end{myframe}se ampliara, produciría dos estallidos. Entonces, \beamer@begin@stackpiensa que el siguiente \end{...}debe proporcionar \end{frame}, posiblemente después de expandir el \end...token (ver nota al pie 1). Desgraciadamente, esto es incorrecto; el siguiente \end{...}es \end{document}. \enddocumentPor lo tanto, se expande, luego \beamer@collect@@bodycontinúa buscándolo \end{frame}pero, por supuesto, nunca lo encuentra, llega al final del archivo, lo que genera el error:

Runaway argument?
\let \AtEndDocument \@firstofone \@enddocumenthook \@checkend {docume\ETC.
! File ended while scanning use of \beamer@collect@@body.
<inserted text> 
                \par 

Entonces, básicamente, el problema es que \beamer@collect@@bodyno puedes llevar un recuento adecuado de \end{...}porque \end{myframe}ocultas dos de estos ( \end{itemize}\end{frame}) y \beamer@collect@@bodyno los descubrirá mediante la expansión de \endmyframea pesar de la presencia de \end{myframe}, porque ha visto más \begin{...}que \end{...}en el punto donde ve. this \end{myframe}(pila no vacía debido a \begin{itemize}).

Las soluciones requieren que no te escondas \end{...}en macros que \beamer@collect@@bodyno se van a expandir. Uno está usando elenviron paquete como enLa respuesta de ferahfeza, otro está usando \itemizey \enditemizede la siguiente manera (ninguno de ellos afecta la \beamer@begin@stackpila, por lo tanto, cuando \beamer@collect@@bodyve \end{myframe}, la pila está vacía, por lo tanto \endmyframese expande una vez, lo que hace que el \end{frame}proceso de escaneo del cuerpo sea visible para el entorno):

\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}

Captura de pantalla


Nota

  1. Más precisamente, lo que sucede es lo siguiente (en beamer 2018/12/02 v3.55). Si:

    • la \beamer@begin@stackpila está vacía (tantas \end{...}como \begin{...}se han visto después de \begin{frame}cuyo cuerpo se está recolectando) y
    • el siguiente \end{...}no es un \end{frame}, digamos que es un \end{foobar},

    luego \beamer@collect@@bodysustituye la expansión de primer nivel de \endfoobar\endgroupesto \end{foobar}en el material recopilado. Esto es similar a lo que \end{foobar}produciría la expansión, aunque esta última haría algunas cosas más (ver source2e.pdfp. 272):

    • verifique que el texto de reemplazo \@currenvirsea foobar(esto fallaría en el beamer frameproceso de recolección del cuerpo del que estamos hablando, tal \@currenvircual frame);
    • respetar un comando anterior \@endparenv(usado para suprimir la sangría de párrafo al comienzo del texto después de algunos entornos de creación de párrafos, a menos que dicho texto esté precedido por una línea en blanco o por \par);
    • respetar un comando anterior \ignorespacesafterend(usado para hacer que el siguiente \end{...}ignore los espacios que pueden seguirlo).

Respuesta2

Usando el paquete environ:

\documentclass{beamer}
\usepackage{environ}

\NewEnviron{myframe}[1][]{%
\begin{frame}{#1}
\begin{itemize}
\BODY
\end{itemize}
\end{frame}
}

\begin{document}
\begin{myframe}
\item First
\item Second
\end{myframe}
\end{document}

ingrese la descripción de la imagen aquí

información relacionada