マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

Beamer の frame の fragile

fragile オプションのややこしい話

マニュアルで説明されているように、Beamer のフレーム記述(frame 環境)の中に verbatim 環境を含める場合は、環境のオプションとして fragile を指定する必要がある。

\documentclass{beamer}
\begin{document}
% ↓fragile オプションが必要!
\begin{frame}[fragile]{You know\ldots}
  Of course, all {\TeX} learners \alert{must}
  see what this means:
  \par\small
\begin{verbatim}
\begingroup\expandfater\expandfater\expandfater\endgroup
\expandafter\ifx\csname xx@opt@\xx@opt\endcsname\relax
...
\fi
\end{verbatim}
\end{frame}
\end{document}

マニュアルをよく読むと解るが、fragile オプションには singleslide という値を設定することができる。つまり、fragile の「値」は次の 3 種類があることになる。

  • 指定なし(fragile=false と同値)
  • fragile 指定(fragile=true と同値)
  • fragile=singleslide 指定(containsverbatim と同値*1

この値により、フレームの中身の内部処理に違いがあるらしい。仕様としては以下の点が異なる。*2

  • 「指定なし」の場合:

    verbatim 環境は使えない。

  • 「fragile」の場合:

    verbatim 環境が使えるようになる。フレームの中身を一旦ファイルに書き出してそれを改めて読み込むという処理が行われるらしい。このため、処理が若干重くなる。また、処理の都合上、次のような制約が生じる。((これは、fragile 指定時には、フレームの終端を「\end{frame}」の行で判断するという処理が行われるからである。))

    フレームの内容に \end{frame} だけからなる行を含められない。

    もちろん、frame 環境をネストさせることはないはずである。しかし、Beamer の解説のプレゼンを作っていて verbatim 環境の中に \end{frame} と書きたいという場合には困ることになる。

  • 「fragile=singleslide」の場合:

    verbatim 環境が使えるようになる。また fragile が持つ欠点や制約はこちらには当てはまらない。代わりに次のような制約が生じる。

    複数スライドからなるフレームが作れない。つまり \pause 等が使えない。

    だから、この指定と fragile 指定を使い分ける必要があるかも知れない。

frame 環境で「\end{frame}」と書くための素敵な方法

ところで、先に説明した「制約」を考え合わせると、「複数スライドを生じるフレームの中に verbatim があってその中に \end{frame} だけの行が存在する」という非常に不幸な状況では fragile の値をどれにしても解決できないことになる。

\documentclass{beamer}
\begin{document}
\begin{frame}[fragile]{Beamer is easy}
  Making a slide is as easy as follows:\par
  %↓オーバレイを使った
  \begin{quote}<2>\small
%↓verbatim があって中に \end{frame} がある
\begin{verbatim}
\begin{frame}{Slide title}
  ...Content...
\end{frame}
\end{verbatim}
  \end{quote}
\end{frame}
\end{document}

\end{Frame} の前後に何か文字があれば問題ないのであるが、verbatim の中だから当然追加した文字はそのまま出力されてしまう。すると、「後ろに空白文字を入れる(これなら見た目が変わらない)」という方策を思いつくが、残念ながら TeX の仕様による制約のため上手くいかない。*3何か素敵な解決法はないものか。

そう、素敵な解決法といえば、半角カナを使って……

……じゃなくて、frame 環境の environment オプションを利用するのが正解。

\documentclass{beamer}
\newenvironment{specialframe}
  {\begin{frame}[fragile,environment=specialframe]}
  {\end{frame}}
\begin{document}
\begin{specialframe}{Beamer is easy}
  Making a slide is as easy as follows:\par
  \begin{quote}<2>\small
\begin{verbatim}
\begin{frame}{Slide title}
  ...Content...
\end{frame}
\end{verbatim}
  \end{quote}
\end{specialframe}
\end{document}

frame 環境に展開される「specialframe 環境」を定義する。その際に、frame 環境に environment=specialframe というオプションを指定する。これで、Beamer はフレームの終端を「\end{specialframe}」という行(実際に終端として書かれるのはそれのはずである)で判断するようになる。すなわち、「\end{frame}」の行は安全に含めることができる。

*1:containsverbatim は fragile=singleslide の設定に対する旧版での名前であるが、現在でもサポートされている。

*2:もちろんマニュアルに記載されている。

*3:行末にある空白文字は、例え(verbatim の中のように)空白文字のカテゴリコードが 10 以外になっていても、無条件に無視されてしまうのである。ただし、全角空白(U+3000)や no-break space(U+00A0)はこの制約を受けないので、その文字が使える環境であれば回避策になりうる。