4

With beamer frames, this does not work.

\newenvironment{itemframe}[1]{
  \begin{frame}{#1}
    \begin{itemize}
}{
    \end{itemize}
  \end{frame}
}

Adding fragile, environment=itemframe as an optional argument to the frame will solve the issue. But there is also an alternative that avoids making the frame fragile: Exporting everything apart from the frame environments to own commands.

\documentclass{beamer}
\usepackage{xparse}

\newenvironment{itemframe}[1]{
%\NewDocumentEnvironment{itemframe}{m}{
  \begin{frame}{#1}
    \itemframebegin
}{
    \itemframeend
  \end{frame}
}
\newcommand\itemframebegin{
  \begin{itemize}
}
\newcommand\itemframeend{
  \end{itemize}
}

\begin{document}
\begin{itemframe}{Title}
  \item A
  \item B
  \item C
\end{itemframe}
\end{document}

Now when \newenvironment is replaced with \NewDocumentEnvironment from the xparse package, as shown as a comment above, both solutions again fail with

! File ended while scanning use of \beamer@collect@@body.

Is there a possibility to make a \NewDocumentEnvironment including a frame? Avoiding the fragile option is preferred.

5
  • 2
    You can't have \end{frame} hidden in a macro.
    – egreg
    Commented Nov 16, 2013 at 17:15
  • I use variations of the second code block in many of my documents. So in an environment, it seems possible.
    – XZS
    Commented Nov 16, 2013 at 17:17
  • I replaced the second code block with a minimal working example to show that it is indeed possible.
    – XZS
    Commented Nov 16, 2013 at 21:53
  • Environments defined with \NewDocumentEnvironment seem to play bad with \beamer@collect@@body. But what's the gain in defining such an environment? I can't see any.
    – egreg
    Commented Nov 17, 2013 at 0:48
  • @egreg Do you want to write an answer?
    – Johannes_B
    Commented Feb 8, 2015 at 11:52

1 Answer 1

4

Unfortunately, xparse defined environments play bad with \beamer@collect@@body.

A workaround is using environ:

\documentclass{beamer}
\usepackage{xparse,environ}

\NewEnviron{itemframe}{\expandafter\doitemframe\BODY\ENDBODY}
\NewDocumentCommand{\doitemframe}{mo u{\ENDBODY}}{%
  \begin{frame}{#1}
  \IfNoValueTF{#2}{NO OPT}{OPT}
  \begin{itemize}
  #3
  \end{itemize}
  \end{frame}
}

\begin{document}
\begin{itemframe}{Title}[opt]
  \item A
  \item B
  \item C
\end{itemframe}
\end{document}

The argument list is ended by u{\ENDBODY} so that \doitemframe collects the arguments in the proper way and then you can use #3 (or whatever is the resulting argument number).

If you don't need the full force of xparse but just standard arguments, you can do

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

With xparse release 2019-05-03 one can do as follows: +b denotes that the body of the environment will be collected (in this case as #3) before processing further.

\documentclass{beamer}
\usepackage{xparse}

\NewDocumentEnvironment{itemframe}{mo+b}
 {%
  \begin{frame}{#1}
  \IfNoValueTF{#2}{NO OPT}{OPT: #2}
  \begin{itemize}
  #3
  \end{itemize}
  \end{frame}
 }{}

\begin{document}
\begin{itemframe}{Title}[opt]
  \item A
  \item B
  \item C
\end{itemframe}
\end{document}
2
  • Both solutions do not work with fragile frames.
    – stefanct
    Commented Sep 29, 2016 at 15:15
  • @stefanct Of course they don't, but the OP wanted exactly to avoid fragile frames.
    – egreg
    Commented Sep 29, 2016 at 15:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .