Совместное создание рамок и деталей

Совместное создание рамок и деталей

Я хочу переопределить 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}за поиском \end{frame}, не расширяя их, за исключением одного случая (см. ниже), но она примет \end{frame}как конец собираемого тела среды, только если она увидела то же количество , \begin{...}что и \end{...}во время этого процесса сбора (она не пытается сопоставить их). Это то, что \beamer@begin@stackиспользуется для в \beamer@collect@@bodyfrom beamerbaseframe.sty.

В случае, если стек пуст (т.е. он увидел столько же, \end{...}сколько \begin{...}после \begin{frame}), а следующее \end{...}не является \end{frame}, он расширяет это \endв надежде, что это заставит \end{frame}появиться. 1 Но этотолькопроисходит при условии, которое я указал ( должно быть замечено столько \end{...}, сколько \begin{...}после инициала ).\begin{frame}

В вашем примере \begin{itemize}помещает один b(т. е. открывает один уровень) в \beamer@begin@stackстек. Это bвыталкивается при \end{myframe}чтении. В этот момент \beamer@collect@@bodyзнает, что видел столько же, \begin{...}сколько \end{...}после \begin{frame}. Это верно, но вводит в заблуждение, так как если бы \end{myframe}были развернуты, это дало бы два выталкивания. Поэтому \beamer@begin@stackдумает, что следующий \end{...}должен предоставить \end{frame}, возможно, после расширения \end...токена (см. сноску 1). Увы, это неверно; следующим \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 пакет, как вответ ферахфезы, другой использует \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}

Скриншот


Сноска

  1. Точнее, происходит следующее (в beamer 2018/12/02 v3.55). Если:

    • стек \beamer@begin@stackпуст (столько, сколько \end{...}было \begin{...}увидено после того, \begin{frame}чье тело собирается) и
    • следующее \end{...}не является \end{frame}—скажем так, это \end{foobar},

    затем \beamer@collect@@bodyзаменяет расширение первого уровня \endfoobar\endgroupна это \end{foobar}в собранном материале. Это похоже на то, что \end{foobar}произвело бы расширение, хотя последнее сделало бы несколько больше вещей (см. source2e.pdfстр. 272):

    • проверьте, что заменяющий текст \@currenvirравен foobar(это приведет к сбою в beamer frameпроцессе сбора тел, о котором мы говорим, поскольку \@currenvirэто так frame);
    • соблюдать предыдущую \@endparenvкоманду (используется для подавления отступа абзаца в начале текста после некоторых сред создания абзацев, если только указанному тексту не предшествует пустая строка или \par);
    • соблюдать предыдущую \ignorespacesafterendкоманду (используется для того, чтобы следующая команда \end{...}игнорировала пробелы, которые могут следовать за ней).

решение2

Используемый пакет 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}

введите описание изображения здесь

Связанный контент