マクロツイーター

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

行頭で括弧が揃うようにする

コレの話の続き。

(おさらい)

  • pLaTeX の既定動作では、段落冒頭と強制改行の直後の行頭で開き括弧を用いると、(通常の文字の後と同様に)括弧の前に伸縮する空き(グル―)が入る。これは、会話が続く(つまり段落頭/行頭に鉤括弧が並ぶ)場合に括弧の位置が不揃いになる原因となる。
  • そもそも折り返しの行頭の括弧の前には空きがないので、「頭の括弧の扱い」として一貫していない。
  • 奥村氏の「新ドキュメントクラス」(JSクラス)では対策が施されているが完全ではない。(何れにしても縦組みでは使えない。)
  • 手動で対策するには、段落頭/行頭で \inhibitglue\<)を置いてグル―を消して、改めて必要量の無伸縮の空きを入れればよい。

さてここからは、自動的に必要な個所に \inhibitglue を入れる(というパッケージを作成する)ための方策を考える(無論 TeX プログラミングを行うことを前提とする)。「直後のトークンが開き括弧の文字*1であれば \inhibitglue を実行する(かつ必要なカーンを入れる)」というマクロ(仮に \xx@maybe@inhibitglue とする)を作るのは難しくない。なので、後は「段落頭」と「強制改行の後」の 2 箇所に \xx@maybe@inhibitglue を自動的に挿入できればよい。このうち、後者については実現は簡単である。強制改行の命令(\\\newline)は最終的に \@gnewline という下請けのマクロを呼ぶので、その末尾に \xx@maybe@inhibitglue が入るようにそのマクロを再定義すればよい。

\let\xx@org@@gnewline\@gnewline
\def\@gnewline#1{%
  \xx@org@@gnewline{#1}%
  \xx@maybe@inhibitglue
}

これに対して、段落頭に自動的に \xx@maybe@inhibitglue を入れるのはかなり難しい。というと、plain TeX 使いの人は奇異に感じるだろう。\everypar を使うだけではないかと。(\everyparトークレジスタ型のパラメタでその内容が全ての段落冒頭に自動的に挿入される。)

% \everypar にトークンを追加する
\everypar\expandafter{\the\everypar\xx@maybe@inhibitglue}

実は LaTeX では話はそんなに簡単ではない。というのも、LaTeXカーネル\everypar を独占的に(つまりパッケージがその機能を利用することを全く考慮せずに)使っているからである。実際、カーネルの中には \everypar を無条件に空にしている((つまり、\everypar{} を実行している。))箇所が幾つもある。だから、パッケージが \everypar を設定しても、それはいつの間にか消されてしまうのである。

これへの対処として、真っ先に思い浮かぶのが、「\everypar にパッケージ開発者用のフックが入れられるようにカーネルにパッチを当てる」ことであろう。実際に JS クラスではこの方法を用いている。興味がある人は jsclasses.dtx の「段落の頭へのグルー挿入禁止」を参照されたい。ただ、そのコードを見て判る通り、割と大きな改変になるので、文書クラスならまだしも、(後から追加される)パッケージとしては憚られる。((前回、minipage 環境では空きの補正が効かなくなると述べたが、実際に、この位置では \everypar は空になってしまって(つまり、JS クラスで仕掛けたフックが消滅して)いる。))

といっても、パッチを行う他に術はなさそうだが、こういう場合に気を付けるべきなのは、「同じパッチを使って同じ機能を与えるパッケージが既に存在していないか」である。同じパッチを行うパッケージを複数存在させてしまうと不幸が起こる原因になるので、この場合は、できるだけ既存のパッケージを使うべきである。そう思って、CTAN を探索すると、everyhook というパッケージが見つかる。これはまさに「LaTeX\everypar((および他の \every〜 のバラメタ。))を使えるようにする」という機能を提供する。ちょっと面白い方法を使っていて、LaTeXカーネルの方々にパッチを当て回らなくても済むようになている(実は \everypar 自身を別のトークレジスタで置き換えている)。とにかく、このパッケージを使うと、次のようにして、「段落頭に特定のトークンを挿入する」ことが可能になる。

\PushPostHook{par}{\xx@maybe@inhibitglue}

*1:その集合は予め決まっているとする。