コレの話の続き。
(おさらい)
- 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:その集合は予め決まっているとする。