LaTeX 技巧 962:Beamer frame 中的抄錄環境

今天 @Butui Hu 在群里問了一個老問題:怎么在 Beamer 的 frame 當中使用 minted 環境?

這個問題的答案很簡單:其實不論是 minted 還是 lstlisting 還是基本的 verbatim,這些「抄錄」環境與 frame 聯用時,統統都需要給 frame 加上 fragile 參數,形如:

\begin{frame}[fragile]
% verbatim-like environment.
\end{frame}

但問題是,為啥事情會變成這個樣子?這篇文章簡單討論一下。

抄錄環境是怎么實現的?

首先我們要解決的第一個問題是,類似 verbatim 的抄錄環境是怎么實現的?

基本上說,抄錄環境有這么一些特征:

當然,對于 minted 和 lstlisting 之類的環境,還會有為特定字符、詞組渲染顏色的功能。但這些都是「錦上添花」,我們要關注的核心還是上面四條。

很顯然,抄錄環境對于輸入內容的處理方式與正常內容的處理方式有很大差異。比如,反斜線 \ 原本作為 TeX 默認的轉義字符,此時卻要原樣輸出。我們知道,TeX 中之所以有諸多特殊用途的字符(\, {, }, $ 等等),其原因在于輸入處理器讀入內容時,會為每個字符分配分類碼。輸入處理器會根據字符和字符的分類碼,將輸入內容處理成記號流(token stream),交由展開處理器繼續處理。顯然,抄錄環境要改變 TeX 中特殊用途的字符的行為,就必須要改變他們的分類碼。實際上,這些字符的分類碼,在抄錄環境中,都會被設置為 12(other)。

此外,為了恢復這些特殊用途的字符,TeX 要在合適的位置重新設置這些字符的分類碼。對于 LaTeX 使用者來說,很顯然這個「時機」就應該是 \end{varbatim} 出現時了。這個論斷說對也對,說不對也不完全對。考慮到,進入抄錄環境之后,諸如 \ 的分類碼已經改變,因此 \end{varbatim} 不會像正常的「結束環境」的標志那樣被 TeX 識別并處理。于是,為了達到預期效果,你必須把 \end{varbatim}單獨成行,作為恢復分類碼的標志。也就是說,\end{varbatim} 在這里起到的是一個純粹的標志作用,而不是通常意義上「結束環境」的作用。

\begingroup
\catcode `|=0 \catcode `[= 1 \catcode`]=2
\catcode `\{=12 \catcode `\}=12 \catcode`\\=12
|gdef|@xverbatim#1\end{verbatim}[#1|end[verbatim]]
|gdef|@sxverbatim#1\end{verbatim*}[#1|end[verbatim*]]
|endgroup

上面這段代碼是 LaTeX2e 中有關抄錄環境結束的命令的定義。在由 begingroup 和 endgroup 形成的 semi-group 分組中,我們將 | 定義為轉義字符(0),[] 分別定義為分組開始和結束的字符(1, 2),然后把 {}\ 都定義為「其他字符」(12)。雖有,用 |gdef(相當于平時的 \gdef)超出 semi-group 的范圍,定義控制序列 @xverbatim,它接受 1 個參數,這個參數以 \end{verbatim}這串字符結尾,同時將它的內容替換成實際內容 #1,以及有實際含義的 |end[verbatim](后者會被展開成 \endverbatim 命令,負責真正的「結束環境」的工作)。

一頓操作猛如虎,最終還靠分類碼。而最最重要的是我們得知道,分類碼是由輸入處理器在讀入文件時設置的。

脆弱命令是怎么回事?

在輸入處理器把文本流變成記號流之后,展開處理器和執行處理器就開始工作啦!通常來說,展開處理器會拼了老命將記號展開成更加底層的記號,直到不可展開,然后執行處理器開始執行各個不可展開的底層記號。

但某些情況下,這個流程會有問題。其中一個典型的例子,就是所謂的「移動參數」問題。

考慮 \section{} 命令。它做四件事:

  1. 編號自增 1

  2. 輸出章節標題

  3. 處理目錄(和 PDF 書簽)

  4. 做頁眉的章節標記

其中 (3) 依賴于將標題內容和編號寫入 <jobname>.toc 文件,當 TeX 第二遍編譯時,從 <jobname>.toc 文件讀入內容再去排版目錄。也就是說,此類命令的具體含義在兩次編譯過程中是不一樣的,而具體它是什么含義(最終效果),要等排版完成之后才能確定。

問題在于:

  1. TeX 在寫文件時,會將宏——此處特別注意 \section{} 參數中可能包含的宏——完全展開;

  2. 但完全展開寫入文件之后,又要重新為 TeX 所讀入,這時可能造成奇怪的錯誤。

比方說,\(\) 展開后會包含很多帶有 @ 的內容,如果將這些內容寫入文件,再重新讀入,就會因為 @ 的分類碼是 12 而非 11 不能作為控制序列的一部分而報錯。

我們將提前展開和延后展開的最終效果不一樣的命令,稱之為脆弱命令(fragile commands)。與之對應的,就是健壯命令(robust commands)。

這和 frame 有什么關系?

為此我們需要查看 Beamer 的文檔。文檔 12.9 節提到:

If you wish to use a {verbatim} environment in a frame, you have to add the option [fragile] to the {frame} environment. In this case, [...] and the \end{frame} must be alone on a single line. Using this option will cause the frame contents to be written to an external file and the read back.

這段提到了在 frame 當中使用抄錄環境,必須制定 fragile 參數。但仍然沒有解釋「為啥要用」。繼續找到文檔 8.1 節:

If a frame contains fragile text, different internal mechanisms are used to typeset the frame to ensure that inside the frame the character codes can be reset. The price of switching to another internal mechanism is that either you cannot use overlays or an external file needs to be written and read back (which is not always desirable).

In detail, the following happens when this option is given for normal (pdf)LaTeX: The contents of the frame is scanned and then written to a special file named ?jobname?.vrb or, if a label has been assigned to the frame, ?jobname?.?current frame number?.vrb. Then, the frame is started anew and the content of this file is read back. Since, upon reading of a file, the character codes can be modified, this allows you to use both verbatim text and overlays.

To determine the end of the frame, the following rule is used: The first occurence of a single line containing exactly \end{?frame environment name?} ends the frame. The ?environment name? is normally frame, but it can be changed using the environmentoption. This special rule is needed since the frame contents is, after all, not interpreted when it is gathered.

這樣我們就明白了。frame 在某種程度上限制了環境內容對分類碼的修改。因此,對于抄錄環境這樣需要修改分類碼來實現目的的「脆弱內容」,我們要指定 fragile 參數,然后 Beamer 會將這些內容寫入到外部文件(為此 frame 環境變成了脆弱命令)。然后,在再次讀入這些內容時,讓輸入處理器有機會正確處理分類碼。如此一來,才能顧全這些「脆弱內容」的渲染,和 Beamer 的 overlay 效果。

選自:https://liam.page/2019/08/26/verbatim-environments-and-frame-in-beamer/#more

分享到:
未經允許不得轉載:LaTeX 技巧 962:Beamer frame 中的抄錄環境
已有 條意見

    最新文章

    加載中...
      本站提供專業LaTeX排版、咨詢、定制服務,請點擊下圖咨詢詳情


      全國首個精品的LaTeX視頻教程,大牛帶著你入門,讓LaTeX學習不再糾結,請點擊下圖咨詢詳情

      熱門評論

        聯系我們

        交流QQ群:91940767
        本站QQ號:343083553
        郵箱聯系[email protected]
        淘寶店鋪https://shop240512713.taobao.com/ 提供排版,模板定制,培訓,圖片處理,視頻教程等LaTeX服務。

        關注我們微信公眾號

        如果您投稿或者希望加入我們團隊,請發送您的簡歷到[email protected]
        刺激战场比赛ag