LaTeXでもっと段落を継続できる件

:::note info
これは「[TeX & LaTeX Advent Caleandar 2024](https://adventar.org/calendars/10647)」の1日目の記事です。
（2日目は [津茶利休 さん](https://zenn.dev/tyty/articles/09bebde8fe4f47)です。）
:::

LaTeXのカーネルは（ここ数年の実績としては）年2回のペースでリリースされています。直近では2024年11月1日に最新のバージョンがリリースされました。例によって、改修内容はLaTeX Newsにまとめられています。

  * [LaTeX News Issue 40, November 2024][ltnews40]（PDF形式；LaTeX Project）

今回のLaTeX Newsの文書は「Thirty Years of LaTeX2e」と題した節から始まっています。今年（2024年）は“LaTeX2e”が最初にリリースされてからちょうど30年目という、LaTeXにとって記念すべき年に当たります。

:::note info
今回のLaTeX Newsの概要を解説した日本語の記事がありますので、興味がある人はぜひ読みましょう。冒頭の「Thirty Years of LaTeX2e」の節については全文の翻訳が載っています。

  * [LaTeX News斜め読み (4) Issue 40, 2024年11月発行][lr-ltnews40]（ラング・ラグー）
:::

というわけで、本記事ではLaTeXの **“30年ぶりに改善された機能”** について解説したいと思います。

## 前提知識
本記事を読むのには「LaTeXのごく**キホン的**な知識」があれば大丈夫です:blush:

## LaTeXで段落する話

まずは超キホン的なLaTeX文法の確認です。LaTeXの文書ソースの書き方の規則では「文書中の**改段落**を**ソース中の空行**で表す」となっているのでした。例えば、以下のLaTeX文書ソース（の断片）の場合、`名前はまだ無い。`の直後にある空行が「そこで次の段落に移っている」ことを指示しています。つまり、`吾輩は猫である。名前はまだ無い。`という塊と`どこで生れたか……種族であったそうだ。`という塊がそれぞれ1つの段落をなしているわけです。

```latex
吾輩は猫である。
名前はまだ無い。

どこで生れたかとんと見当がつかぬ。
何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。
吾輩はここで始めて人間というものを見た。
しかもあとで聞くとそれは書生という人間中で
一番獰悪な種族であったそうだ。
```

:::note info
ソース上の「空行では**ない**改行」は文書構造としては** “無視”** されます[^soft-break]。（行末が欧文文字の場合は空白文字と同等になり、和文文字の場合は本当に無視されます。）
:::

[^soft-break]: 先の例では`吾輩は猫である。`の後の改行は空行を作らずに次の行`名前はまだ無い。`に続いているため、改行せずに  
`吾輩は猫である。名前はまだ無い。`
と書いたのと同じと見なされます。

組版結果中で段落がどういう **“外形”** （視覚的な表現形式）で表されるかは文書のレイアウト設定（つまり文書クラス）に依存しますが、LaTeXで一般的に使われる文書クラスでは「段落は（組版結果で）前後が改行で区切られた上で、先頭に**段落下げ**(paragraph indent)の水平空きを入れる」という形式で表されます。

例えば、先に示した文章を（upLaTeX上で）jsarticleクラス[^layout]を用いて組版したとしましょう。以下に完全な文書ソースを示します。

[^layout]: 本記事で以降に示すLaTeX文書の例でも上記の例と同じレイアウトを用いることにします。

```tex:example1.tex
% upLaTeX＋dvipdfmx
% 行長を小さくするためにあえて2段組にする
\documentclass[uplatex,dvipdfmx,a4paper,twocolumn]{jsarticle}
\begin{document}
吾輩は猫である。
名前はまだ無い。

どこで生れたかとんと見当がつかぬ。
何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。
吾輩はここで始めて人間というものを見た。
しかもあとで聞くとそれは書生という人間中で
一番獰悪な種族であったそうだ。
\end{document}
```

この場合の出力は以下のようになります。段落が段落下げを伴っていることが判ります。

![image-1a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/c3c3e5b4-1a2f-ea58-7ca4-6a343c7018bb.png)

## 段落を継続する話

### 段落継続とは何か

多くの場合、文章の段落は“文字の列”です。しかし時々段落が箇条書きなどの**別行立て要素**を中に含むことがあります。

:::note info
「別行立て要素」というのは前後に必ず改行を伴って配置される文書要素のことです。例としては箇条書きの他に章見出しや別行立て数式（ディスプレイ数式）などがあります。
:::

例えば以下に示す文章は「箇条書きを中に含む単一の段落」からなっています。箇条書きの直前・直後で改段落がされて**いない**ことは、この文章全体が（日本語の文法において）“単一の文(sentence)”であることから明らかでしょう。以下では「改段落がされていない」ことを「**段落が継続**している」と呼ぶことにします。

![image-2a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/a910e780-e6de-3f23-6d88-7efac3c9c15d.png)

また箇条書きの直後については**外形**からも「段落が継続している」ことが明示されます。よく見ると、箇条書きの直後にある「などの、極めて個性的な……」で始まる塊は先頭の段落下げが行われて**いません**。段落下げがないので、この塊は単独で段落をなすものではなく直前の段落が継続しているはずなのです。

もちろん、文章によっては、箇条書きの直後で改段落が行われることもあります。

![image-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/1ee038d5-3554-990c-39d8-6f886472fd05.png)

この場合は箇条書きの直後の「これらのプリミティブが……」に段落下げが行われて**いる**ことによって、この塊が段落をなす（前の段落を継続して**いない**）ことが明示されています。

:::note info
なお、箇条書き（などの別行立て要素）の直前については「そこで改段落が行われたか」を表現する方法がないため、外形だけでは判断ができません。以降では別行立て要素の直後の段落継続のみを扱います。
:::

### LaTeXで段落継続する（しない）方法

別行立て要素の直後で段落が継続するか否かは外形（組版結果）の違いとして現れることが判りました。LaTeXは組版ソフトウェアなので当然、段落が継続する場合としない場合を区別して取り扱う必要があります。LaTeXではこの2つの場合を文書ソース上でどのように区別するのでしょうか。

その答えはとても単純で「LaTeXの**キホンの規則に従う**」というものです。「ソース上の空行が改段落を表す」わけなので、箇条書きの直後（つまり`\end{itemize}`の直後）に空行が**なければ**改段落されずに段落が継続して**いる**という意味になります。

```tex:example2.tex
% upLaTeX＋dvipdfmx
\documentclass[uplatex,dvipdfmx,a4paper,twocolumn]{jsarticle}
\begin{document}
{\TeX}言語には数百個のプリミティブがありますが、その中には
\begin{itemize}
\item \verb|\expandafter|
\item \verb|\futurelet|
\item \verb|\afterassignment|
\end{itemize}
などの、極めて個性的な機能をもつものが多数存在し、
これが{\TeX}言語でのプログラミングを
「トッテモ楽しい」ものにしています。
\end{document}
```

このソースをタイプセットして得られる出力結果では、箇条書き直後には段落下げは入っていません。

![image-2a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/a910e780-e6de-3f23-6d88-7efac3c9c15d.png)

逆に`\end{itemize}`の直後に空行が**あれば**改段落されている（段落が継続して**いない**）という意味になります。

```tex:example3.tex
% upLaTeX＋dvipdfmx
\documentclass[uplatex,dvipdfmx,a4paper,twocolumn]{jsarticle}
\begin{document}
{\TeX}言語には数百個のプリミティブがありますが、その中には
以下のような極めて個性的な機能をもつものが多数存在します。
\begin{itemize}
\item \verb|\expandafter|
\item \verb|\futurelet|
\item \verb|\afterassignment|
\end{itemize}%この後に空行を入れる

これらのプリミティブが{\TeX}言語でのプログラミングを
「トッテモ楽しい」ものにしています。
\end{document}
```

当然ですが、こちらの出力結果では、箇条書き直後に段落下げが入っています。

![image-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/1ee038d5-3554-990c-39d8-6f886472fd05.png)

この段落継続に関する“LaTeXの原則（ソース上空行＝改段落）通りの対応”はLaTeX2eの最初期（つまり**30年前**）からサポートされています。従って、多くのLaTeXユーザはこの段落継続の機能を特に意識せずに利用していることでしょう。

:::note info
ただし、全ての別行立て要素について段落継続がサポートされているわけではないことに注意が必要です。例えば、節見出しはその前後の改段落を強制する[^sectioning]ため、`\section`命令の直後に空行がなくても、その後に続く塊は新しい段落を開始すると見なされます。
:::

[^sectioning]: 段落が節を跨いでいることは論理的にありえないからです。

## もっと段落を継続する話

### 従来のLaTeXで段落継続できない件

さてここからが話の本題です。LaTeXでは30年前から「別行立て要素の直後の段落継続」を判定する機能をもっているわけですが、残念ながらその実装は**不完全**でした。文書ソースが少々複雑になってくると、判定が正常に働かずに結果的に不適切な出力をしてしまう場合があったわけです。

例えば以下のような文書ソースを考えます。これはexample2.texと同じ文章ですが、箇条書きのレイアウトを一時的に変更するためにitemize環境全体を**グルーピング**の中に入れて（局所化して）います。

```tex:example4.tex
% upLaTeX＋dvipdfmx
\documentclass[uplatex,dvipdfmx,a4paper,twocolumn]{jsarticle}
\begin{document}
{\TeX}言語には数百個のプリミティブがありますが、その中には
{%←グループ開始
  %itemizeのレイアウトを一時的に変更する
  \setlength{\itemsep}{0pt}
  \begin{itemize}
  \item \verb|\expandafter|
  \item \verb|\futurelet|
  \item \verb|\afterassignment|
  \end{itemize}
}%←グループ終了, 直後に(空行なしで)文を続ける
などの、極めて個性的な機能をもつものが多数存在し、
これが{\TeX}言語でのプログラミングを
「トッテモ楽しい」ものにしています。
\end{document}
```

この文書を（少し昔の）upLaTeX[^uplatex]でタイプセットした出力結果を見ると、箇条書きの直後に改段落（空行）を入れていないにもかかわらず「などの…」から始まる塊に段落下げが**入って**しまっています。

[^uplatex]: なお、段落継続の判定はLaTeXカーネルの話なので、エンジンの種類（upLaTeX、pdfLaTeX、LuaLaTeX……）とは無関係です。つまりどのエンジンでもこの不具合が発生していました。

![image-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/5906f5ea-a55f-66a6-e611-721003106847.png)

これは明らかに不具合なのですが、30年間改善されることなく残っていました。

### 最新のLaTeXでもっと段落継続できる件

ところが、直近の2024年の11月のLaTeXカーネルのリリースにおいて、ついにこの**不具合が修正**されました。つまり、最新のupLaTeXで先のexample4.texをタイプセットした場合は段落継続が正しく判定され、結果的に「などの…」の塊に入っていた余計な段落下げが解消します。

![image-4a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14550/277c9401-958f-1abd-facd-641205bb3910.png)

LaTeX2eの初期からあった不具合が、30年の年月を経てついに修正されたのです:tada:

### もっと段落継続した理由

この話について興味深い点は「なぜ今のタイミングで30年来の不具合を修正することになったのか」ということでしょう。

段落継続に関する不具合が長らく“放置”されていた原因は「少し気を付けていれば容易に不具合を回避できるから」でした。もし別行立て要素の近辺の文書ソースが複雑になっていて段落継続の判定が異常になったとしても、その影響は「出力結果に余計な段落下げが入ってしまう」ことに留まっています。なので、その余計な段落下げを`\noindent`命令で消してしまえば**見かけ上は**正しい出力が得られます。

```tex
{\TeX}言語には数百個のプリミティブがありますが、その中には
{
  \setlength{\itemsep}{0pt}
  \begin{itemize}
  \item \verb|\expandafter|
  \item \verb|\futurelet|
  \item \verb|\afterassignment|
  \end{itemize}
}
\noindent % 余計な段落下げを消してゴマかす
などの、極めて個性的な機能をもつものが多数存在し、
これが{\TeX}言語でのプログラミングを
「トッテモ楽しい」ものにしています。
```

この状況に変化が起こった理由として、近年のLaTeXカーネルの**​「タグ付PDFのサポート」​**の取組が考えられます。

:::note info
「タグ付PDFとは何か」については（例によってサッパリ時間がない:upside_down:ので）先日（2024-11-30）開催された[TeXConf2024][texconf2024]の講演のスライドを参照してください。

* [LaTeX News斜め読み][texconf-wtsnjp]（朝倉卓人／TeXConf2024講演）

※9～12ページに「タグ付PDFサポート」の話が載っています。
:::

タグ付PDFのサポートをするには大前提として「文書ソース上に文書の**論理的構造**が明示されている」ことが要求されます。当然「文章のどの部分が1つの段落をなすのか」というのも重要な論理的構造の情報です。そうすると、従来のような「出力結果さえ辻褄が合っていればよい」という考えは通用しなくなり、段落継続の有無を正確に判定することが必須の要請となります。LaTeXカーネルのタグ付PDFのサポートが進展した今だからこそ、段落継続処理の不具合を解消する動機が生まれたのでしょう。

30年来の不具合の解消は、最近のLaTeXカーネル開発の潮流を象徴する出来事であると感じています。

## まとめ

**​「[TeX & LaTeX Advent Calendar][texadvent]」では参加者を募集しています！** TeX/LaTeXに関するとっておきのネタを思いついたら、カレンダーに登録してどんどん披露していきましょう！:information_desk_person:

[lr-ltnews40]: https://blog.wtsnjp.com/2024/11/13/ltnews40/
[ltnews40]: https://www.latex-project.org/news/latex2e-news/ltnews40.pdf
[texadvent]: https://adventar.org/calendars/10647
[texconf2024]: https://texconf2024.tumblr.com/
[texconf-wtsnjp]: https://speakerdeck.com/wtsnjp/texconf2024-ltnews