texjporg / platex

pLaTeX community edition
BSD 3-Clause "New" or "Revised" License
49 stars 8 forks source link

p 指定の tabular でのセル冒頭の \relax\par #63

Closed doraTeX closed 6 years ago

doraTeX commented 6 years ago

pdfLaTeX / LuaLaTeX と pLaTeX で,次のような組版結果の違いが生じることに気づきました。おそらく #43 の副作用かと思われますが,ひとまずご報告まで。

ソース

\documentclass{article}
\begin{document}
\begin{tabular}{p{5cm}}
A\\
\relax\par
A
\end{tabular}
\end{document}

pdfLaTeX / LuaLaTeX での組版結果

image

pLaTeX での組版結果

image

このように,pLaTeX で組版すると,空行が空きます。

aminophen commented 6 years ago

43 のときの記憶では,p の扱いは難しかったです。まだ試していませんが,pLaTeX では \@classv で必ず最初に空の \mbox{} を出すようにしているので,そこで水平モードに入っているため \par が効いてしまう,という話だと思います。段落頭の JFM グルーを消せるように pTeX 自体を改修する(例えばそういうスイッチを実装して tabular 内で有効化する)方が,マクロレベルでの対処より容易な気がしますね。

h-kitagawa commented 6 years ago

必ず最初に空の \mbox{} を出すようにしているので,そこで水平モードに入っているため \par が効いてしまう

\mbox{} を出す代わりに,セルの最初で \everypar{} に \inhibitglue を仕込んでおけばいいのかな,と思っています.なんだか頭がこんがらがっていますが,こんな感じ?

\def\@classv{\@addtopreamble{\@startpbox{\@nextchar}%
  \noexpand\unexpanded{\everypar{\inhibitglue
     \everypar{\noexpand\unexpanded\noexpand\expandafter{\noexpand\the\noexpand\everypar}}%
     \noexpand\unexpanded\noexpand\expandafter{\noexpand\the\noexpand\everypar}}}%
  \ignorespaces\@sharp\unskip\@endpbox}%
}

(まだ pLaTeX は e-TeX 拡張を要件とはしていなかったんでしたっけ? cf. #56)

2018-02-20 23:20 edit: む,私のコードは \everypar {\unexpanded \expandafter {\the \everypar}} のように,\the\everypar が各セル開始時に(つまり,\@preamble 定義時ではなく)実行されるようにしたかったのですが,どうやら \begin{tabular}{|p{1cm}|p{2cm}|…|} のように p 指定の後ろにさらに何かあると,そこで \the\everypar が展開されてしまいますね…….

aminophen commented 6 years ago

(まだ pLaTeX は e-TeX 拡張を要件とはしていなかったんでしたっけ? cf. #56)

e-TeX 必須な何かを plcore.ltx に導入するタイミングで,e-TeX 拡張を要件にするつもりでした。今回のようなケースはこれに該当すると思うので,TeX Live 2018 からはそうしましょう。

本題ですが,まだ試せていませんがとりあえず exppl2e に入れてみてはどうでしょう。> \everypar{} に \inhibitglue を仕込んでおけば

aminophen commented 6 years ago

まだよくわかっていないのですが,以下の簡単なコードでは駄目なのでしょうか.

\def\@classv{\@addtopreamble{\@startpbox{\@nextchar}%
  \everypar{\inhibitglue\the\everypar\everypar{\the\everypar}}%
  \ignorespaces\@sharp\unskip\@endpbox}%
}

最後の % の前に \show\@preamble を足すと「プリアンブル」の中身を見ることができますが,このコードでも期待どおり,\begin{tabular}{|p{1cm}|p{2cm}|…|} のようなセルの横並びで「逐次追加」されていくだけ(このとき展開は進まない)ように見えます。

(2018-02-21 20:48 edit) 上のコードは \documentclass{jsarticle} で Missing control sequence inserted. を引き起こすので当然のようにダメでした。

h-kitagawa commented 6 years ago

0d064a8b80d24f0534f5340e398d26a924b2ca21 で \everypar 関係を別命令にしたものを exppl2e.sty に入れました.手元では動いていそうですが,引き続きテストを行います.

doraTeX commented 6 years ago

ありがとうございます。 0d064a8b80d24f0534f5340e398d26a924b2ca21 をテストしたところ,うまく動いているように見えます。 plarray をロードした場合についても,同様の対策が必要になりそうですので,そちらにも Issue を立てておきました。

aminophen commented 6 years ago

plarray パッケージ (aminophen/platex-tools#9) の方を考え始めていますが,うまくいく方法が見つかっていません。安直に \mbox{}\inhibitglue\pltx@next@inhibitglue に置き換えてもエラーが出るのでダメです。何かあれば教えていただきたいです。

ちなみに,表組の中で \relax\par から始まる状況って良くあるのでしょうか? 特に重要な理由がないのであれば頑張らなくてもいいんじゃないかと思っていたりします。(以前 #57 に書いた「重箱の隅のような例」とかも LaTeX と pLaTeX で互換性がないことが既知ですが,保留にしてあります。)

doraTeX commented 6 years ago

ちなみに,表組の中で \relax\par から始まる状況って良くあるのでしょうか?

\relax\par としたのは極限のMWEまで切り詰めたからで,実用上登場する場面ではその形そのもので現れるわけではありません。 うちの英語科の教材作成者から,「去年と今年で組版結果が変わった」との報告があったので気づきました。 実際の教材上では,次のような場面で発現しました。(MWEへの切り詰めをもう少し実用的な形で抑え気味にした状態で例示します。)

\documentclass{jsarticle}
\usepackage{plarray}
\newlength\hoge

\newenvironment{paragraphWithArrow}{%
  \setlength\hoge{1zw}%
  \ifvmode\else\par\fi
  \advance\leftskip\hoge\relax
  \noindent\hspace{-\hoge}→\hspace{\hoge}\inhibitglue
}{\par}

\begin{document}

\begin{tabular}{p{12zw}p{12zw}}
I know the girl. & \\
+ She has long hair. & \\
\begin{paragraphWithArrow}
I know \textbf{the girl} \texttt{<}\textbf{who} has long hair\texttt{>}.
\end{paragraphWithArrow}
 & 私は〈\textgt{髪の長い}〉\textgt{その女の子}を知っています。\\
\end{tabular}

\end{document}
aminophen commented 6 years ago

MWEへの切り詰めをもう少し実用的な形で抑え気味にした状態

という状況がありうる,と理解すればいいのですかね。なんとなく理解しました。

ただ,まだ plarray.sty の方はどうすればいいのか思いつきません。私の能力だと,array.sty で一本化されている l, c, r と p の処理を分離すれば行けなくはないと思いますが,そうするとさらに別のパッケージと衝突しそうなので気が進んでいません。

h-kitagawa commented 6 years ago

plarray.sty

\insert@column のところに \the@toks\the\@tempcnta がありますが, この \the-文字列化された板号の終わりを検出するために \pltx@next@inhibitglue を展開限定文脈で展開しておかしなことになっているようです.

とりあえず \relax を前置すれば良い?(\space ではどうなんだろう?)

\def\insert@column{%
   \the@toks \the \@tempcnta
   \relax\pltx@next@inhibitglue % !!!
   \ignorespaces \@sharp \unskip
   \the@toks \the \count@ \relax}
aminophen commented 6 years ago

\insert@column のところに \the@toks\the\@tempcnta がありますが, この \the-文字列化された板号の終わりを検出するために \pltx@next@inhibitglue を展開限定文脈で展開しておかしなことになっているようです.

なるほど…

とりあえず \relax を前置すれば良い?(\space ではどうなんだろう?)

どちらも試してみましたが,今度は l, c, r のときにグルーが消えなくなるようです。

h-kitagawa commented 6 years ago

今度は l, c, r のときにグルーが消えなくなるようです。

\pltx@next@inhibitglue のところに,「現在が水平モードなら \inhibitglue 発行」を 付け加えれば良いかもしれません:

\protected\def\pltx@next@inhibitglue{%
  \ifhmode\inhibitglue\else
  \edef\@tempa{\everypar{\inhibitglue
    \everypar{\unexpanded\expandafter{\the\everypar}}%
    \unexpanded\expandafter{\the\everypar}}}%
  \@tempa\fi}
aminophen commented 6 years ago

なるほど! そうしていただけると plarray.sty が助かります。

今度は,\mbox{} を除くと plarray.sty で別の副作用が起きることに気づきました。現行では

   \ignorespaces \@sharp \unskip \unskip

のように \unskip を余分にもう一つ発行し,以下のような例で「& の間にソース中に空白文字があるかどうか」にかかわらず JFM グルーを消すことにしていました。

\begin{tabular}{|c|c|}
(中央)&(中央)\\ %% この行は空白文字なし
(中央) & (中央) %% この行は空白文字あり
\end{tabular}

ところが,\mbox{}\inhibitglue\relax\pltx@next@inhibitglue に置き換えると,「空のセル」が本当に空になるので,以下の例で |r| の罫線が揃わなくなります (#54 と同様)。

\begin{tabular}{|r|c|}
& xyz \\
a & 111 \\
bb & 22 \\
ccc & 3
\end{tabular}

pTeX で以下のソースの3行目で JFM グルーを消すことができれば,\unskip ではなく \inhibitglue を使うことができるので安全なのですが…。

あ)\inhibitglue あ\par % 消える
あ)\hskip20pt\unskip\unskip あ\par % 消える
あ)\hskip20pt\unskip\inhibitglue あ\par % 消えない
\bye
aminophen commented 6 years ago

texjporg/tex-jp-build#28 で「\inhibitglue が展開不能トークンを透過するケース」を排除しようといろいろやっていたのですが,pLaTeX の \@classv の実装がまさにこの「透過するケース」に依存していることに気づきました(本 issue の \@classv 改善案も同様)。実際に texjporg/tex-jp-build@f932384 の適用後は,p なセルで \inhibitglue が効かなくなっています。


そもそも現行の pTeX の挙動では

水\inhibitglue\ignorespaces (あ % (1)

これは \inhibitglue が \ignorespaces によってリセットされ, のグルーが入るのに対し,

水\hbox{あ}\inhibitglue\ignorespaces (あ % (2)

これは \inhibitglue がなぜかリセットされなくなり, のグルーが消えます。この後者 (2) のケースを利用していたのが,まさに pLaTeX の \@classv の実装でした。 → あっちのコメントに飛びます。

aminophen commented 6 years ago

65 の \removejfmglue 命令を活用しつつ, \@tabclassz (l,c,r) も \@classv (p) も LaTeX 本来の動作に近づいたはず(本 issue の問題は起きない)です。(l,c,r の方には \lastnodesubtype プリミティブが動作に関与していることになります) → この時点で一旦 pLaTeX 2018/03/09 としてリリース済み。

plarray パッケージの方も同じく開発版は LaTeX 本来の動作に近づいていますが,問題は tex-jp-build リポジトリの inhibitglue_flag ブランチ又は inhibit_flag_list ブランチの修正を適用した場合です。適用前は消えていたはずの「l,c,r の時の冒頭の JFM グルー」が適用後は消えなくなるようで,理由が分かりません。

h-kitagawa commented 6 years ago

適用前は消えていたはずの「l,c,r の時の冒頭の JFM グルー」が適用後は消えなくなる

ちょっと試してみましたが,こちらではいまいち再現できていません.どういう状況でしょう?

aminophen commented 6 years ago

すみません,p の時の間違いです。 aminophen/platex-tools@ac13b7f の時点の plarray.sty をカレントディレクトリに置いた状態で, plarray-01-tabglue.tex をコンパイルした結果で再現可能と思います。

h-kitagawa commented 6 years ago

p の時の間違い

なるほど.\pltx@next@inhibitglue が \everypar の先頭で \inhibitglue を実行するのが原因だと思います.

\protected\def\pltx@next@inhibitglue{%
  \ifhmode\inhibitglue\else
  \edef\@tempa{\everypar{%
    \everypar{\unexpanded\expandafter{\the\everypar}}%
    \unexpanded\expandafter{\the\everypar}\inhibitglue}}%
  \@tempa\fi}

と,\inhibitglue の実行箇所を最後にもってくるのはどうでしょう?(なぜ最初にしたんだっけ?>過去の自分)


platex 2018-03-09 で

\begin{tabular}{|p{3zw}|}
\rlap{\tiny\ttfamily\edef\@tempa{\the\everypar}\meaning\@tempa}\\
\end{tabular}

によって \pltx@next@inhibitglue によってどう \everypar が変わるかを調べてみると

\inhibitglue \everypar {\vrule \@height \ht \@arstrutbox \@width \z@ \everypar {}}
  \vrule \@height \ht \@arstrutbox \@width \z@ \everypar {}

となり,\vrule によって前の \inhibitglue が無効化されていることがわかります.

aminophen commented 6 years ago

\inhibitglue の実行箇所を最後にもってくる

おお,これで全て解消しそうです。 aminophen/platex-tools#7 (tabular 内で \hspace した場合の非互換) の方も,\removejfmglue マクロ (これは e-pTeX 新設の \lastnodesubtype プリミティブが活躍) を使えば解消することができていますし,非常に喜ばしい結果です。

aminophen commented 6 years ago

2018-03-16 付けで pLaTeX2e <2018/03/09>+1 として出し,

\pltx@next@inhibitglue が \everypar の先頭で \inhibitglue を実行するのが原因 [...] \inhibitglue の実行箇所を最後にもってくる

をリリースに含めました。platex-tools もリリースしておきました。ひとまず完了とします。