Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pxeveryshi.sty: LaTeX2e 2020-10-01 対策 #16

Closed
wants to merge 1 commit into from
Closed

pxeveryshi.sty: LaTeX2e 2020-10-01 対策 #16

wants to merge 1 commit into from

Conversation

wtsnjp
Copy link

@wtsnjp wtsnjp commented Sep 13, 2020

aminophen/plautopatch#12 を調べていて発覚した根本原因の修正案です.ひとまず,向こうの issue で言及した MWE はこれで通るようになります.ただし色々と配慮不足の点があるかもしれませんので,すぐにマージして大丈夫そうかというと,かなり怪しいです.

なお,この変更が plautopatch でも効果を発揮するようにするには,別途 plautopatch.sty に以下を追加する必要があります.

\platpc@patch@after{everyshi-ltx}{pxeveryshi}% platex-tools

@wtsnjp
Copy link
Author

wtsnjp commented Sep 13, 2020

この変更でやろうとしていることについて,少し説明しておきます.

LaTeX2e 2020-10-01 では everyshi-ltx パッケージにて everyshi のエミュレートをすることになったようです.この everyshi-ltx はかなり素朴に実装されていて,everyshi の2つの公開インターフェース (\EveryShipout, \AtNextShipout) のみを定義しています.元々 pxeveryshi は everyshi の内部命令 \@EveryShipout@Output をパッチすることで目的を達成していましたが,この内部命令は everyshi-ltx では定義すらされておらず,完全に役割を果たせていません.

https://github.com/latex3/latex2e/blob/develop/base/ltshipout.dtx#L1688-L1694

この修正提案は \vbox{\yoko <code>} による手当てを,everyshi-ltx の定義に対してかなり雑に放り込んだものです.また LaTeX2e カーネルが everyshi を everyshi-ltx に読み替える動作を打ち消し,代わりに pxeveryshi に読み替えるようにしています.とりあえず試した例では動いていますが,基本的に元の pxeveryshi の挙動とは非互換です.

そういう意味では,そもそも everyshi-ltx が everyshi と互換ではありません.既に言及したように内部命令に対応していませんし,ltshipout.dtx の実装箇所直後に言及があるように,\EveryShipout のフック内で直接 box 255 をいじる複雑な処理をした場合には期待する動作にならない可能性が指摘されています(もっとも pxpgfrcs のパッチ対象である pgfutil-latex.def 内でも \EveryShipout のフック内で直接 box 255 をいじっていますが,それ自体は問題を引き起こしていないので,結構大丈夫なのかもしれませんね).

cf. https://github.com/latex3/latex2e/blob/develop/base/ltshipout.dtx#L1696-L1716

@aminophen
Copy link
Owner

pull request ありがとうございます。

everyshi-ltx はかなり素朴に実装されていて,everyshi の2つの公開インターフェース (\EveryShipout, \AtNextShipout) のみを定義しています.

なるほど atbegshi -> atbegshi-ltx と似た状況ということですね。pxatbegshi については一応対処したつもりだったのですが,例の texjporg/platex#94 でも話題のとおり,「その対処を pLaTeX カーネルに入れたほうが良いのではないか」という考えも出ています。

既存の問題には「everyshi 読込時のみ公開インタフェースにパッチする」という方法で十分なことがわかったのは収穫ですが,もう少し検討したいと思います。

@aminophen
Copy link
Owner

pxatbegshi に関しては #15 の問題があり,外からパッチする方法ではなく #14 の話の流れのとおり「LaTeX カーネル側で pLaTeX 用に \yoko 発行可能なプレースホルダを用意してもらう」という方法の方が良いのではないかというのが今の私の思いです。ただ,その方法を進めるには,「そのプレースホルダを挿入する適切な場所がどこなのか」/「提示可能なテストケースはどんな物があるか」を,予めこちらから提示しないといけず,expl3 を読むのがつらい…。

@h-kitagawa
Copy link

pLaTeX 用に \yoko 発行可能なプレースホルダを用意してもらう

! Use \yoko' at top of list. エラーにならない保証はあるのか,とずっと心配していましたが,LaTeX の通常の流れ(\output\@opcol\@outputpage\shipout)だと output routine に入った時点で内部垂直モードになるので,「shipout/before フックの前にプレースホルダを入れる」だとエラー発生の心配はなさそうですね.

ただ,ほとんど気にしなくてもよいのかもしれませんが,

hoge % outer horizontal
\shipout\vbox{\tate あっという間にABCV} % ==> ! Improper `\yoko'
\par % outer vertical
\shipout\vbox{\tate あっという間にABCV} % ==> ! Use `\yoko' at top of the page.

のように外部水平モード・外部垂直モードで \shipout が呼ばれる可能性もありますね.

@aminophen
Copy link
Owner

外部水平モード・外部垂直モードで \shipout が呼ばれる可能性

プレースホルダに入れる物は pLaTeX 側で自由にできるので

  • LaTeX 側で shipout/before フックの前にプレースホルダを入れる
  • プレースホルダに \ifホゲホゲ \yoko \fi を入れる(内部垂直モードの時だけ true にすればよい?)

だとどうでしょう?

@h-kitagawa
Copy link

LaTeX 側で shipout/before フックの前にプレースホルダを入れる

これについては異存ありません.

プレースホルダに入れる物

output routine 内で呼ばれる場合は \yoko で良いですが,簡単な検出手段はあるのでしょうかね.

その他の場合には

  1. 不用意に \yoko を実行することはできない(! Improper `\yoko' の可能性)
  2. そもそも \shipout されるボックスが横組かわからない

という 2 つの問題があります.
どうするのが一番いいのかはわかりませんが,一つの案としては,

  • \shipout 実行時の組方向が横組なら \yoko 実行せずそのまま.
  • そうでないときは従来どおり \__shipout_execute_cont: を横組ボックス \l__platex_shipout_dummy_box で括って実行するが,
    処理終了時に \box\l__platex_shipout_dummy_box してメイン垂直リストに中身を戻す
  • \l_shipout_box が横組でない場合は事前に \setbox\l_shipout_box\vbox{\yoko\box\l_shipout_box} して横組化する

@aminophen
Copy link
Owner

『\shipout が output routine 内で呼ばれたことを検知し,その場合のみプレースホルダに \yoko を入れる』(その他の場合の \shipout は弄らない)ということが出来れば OK である,と理解しました。もしここで「output routine 内で呼ばれた」が「\@outputpage の定義内に現れた」と等価だとすれば,plcore.ltx に存在する \@outputpage の定義内の \shipout をラップしてやれば行けそうな予感がします(まだ試していませんが)。

@aminophen
Copy link
Owner

考えてみれば \AtBeginDvi も everyshi も atbegshi も「\yoko が必要な理由」はひとえに「pLaTeX カーネルの \@outputpage が \shipout する \vbox が \yoko を指定しているから」にほかなりません。つまり,今回のすべての問題について,plcore.ltx の \@outputpage の \shipout だけ「プレースホルダに \yoko を入れた \shipout」を使うようにラップすれば原理的には十分なはずです。

@aminophen
Copy link
Owner

aminophen commented Sep 15, 2020

plcore.ltx の \@outputpage の \shipout だけ「プレースホルダに \yoko を入れた \shipout」を使うようにラップすれば原理的には十分なはずです。

pLaTeX の output routine は十分なはずですが,一方 #16 (comment) に挙げられた

\documentclass{article}
\begin{document}

hoge % outer horizontal
\noindent
\shipout\vbox{\tate あっという間にABCV}

\stop

は現行の platex だと OK ですが,現行の platex-dev で既にエラーですね。

! Incompatible direction list can't be unboxed.
<argument> ...p_box \vbox_unpack:N \l_shipout_box 
                                                  \kern \c_zero_dim 
l.6 \shipout\vbox{\tate あっという間にABCV}
                                            % ==> ! Use `\yoko' at top of th...

?

しかも「plcore.ltx の \@outputpage の \shipout だけラップ」の方針では当然漏れます。

どうしたものか…。

@wtsnjp
Copy link
Author

wtsnjp commented Sep 15, 2020

ちょっと話の流れを遮ってしまいますが

LaTeX 側で shipout/before フックの前にプレースホルダを入れる

の実現方法については見当が付いていますか? これは shipout/before の直前に shipout/before/before 的なフックを追加するということですか?

@aminophen
Copy link
Owner

aminophen commented Sep 15, 2020

LaTeX 側で shipout/before フックの前にプレースホルダを入れる

の実現方法については見当が付いていますか?

十分検証していませんが

https://github.com/latex3/latex2e/blob/develop/base/ltshipout.dtx#L627

\hook_use:n {shipout/before} の直前行に \pltx@maybe@yoko 的な命令を入れるというのを想定しています(expl3 的な命名系統を使うなら pLaTeX2e カーネルでも \ExplSyntaxOn すれば良い。ただし 「shipout/before/before 的なフック」という方法はユーザが自由にフックを追加できてしまうので好ましくなく,pLaTeX カーネル以外が使わない非公開インタフェースになればいいなという希望はあります)。

@h-kitagawa
Copy link

\hook_use:n {shipout/before} の直前行に \pltx@maybe@yoko

私もそのようなイメージでいました(LuaTeX-ja でもこの命令を使うと思います).

@aminophen
Copy link
Owner

非公開インタフェースになればいいなという希望

これに関して言えば,そもそも \pltx@maybe@yoko のような「専用命令」でなくても,一般的な「フック順序入れ替えを禁止して \yoko を必ず先頭に固定する方法」があれば十分な気もしています。ともあれテストケースを十分用意しないと LaTeX3 team に提案・要望するのが難しい(後で「やっぱり検討不足で駄目でした」は申し訳ない)ので,まずはそちらを準備したいと考えています。

@wtsnjp
Copy link
Author

wtsnjp commented Sep 16, 2020

なるほど,だいたいわかりました.

前者は \__ltshipout_execute_firstpage_hook: のような感じの関数を \hook_use:n {shipout/before} 直前に仕込んでおいてもらって,その関数の定義は LaTeX2e カーネルとしては \prg_do_nothing: と等価のままにしておいてもらえば,pLaTeX2e 側で対処できそうですね.

cf. https://github.com/latex3/latex2e/blob/develop/base/ltshipout.dtx#L803

そもそも \pltx@maybe@yoko のような「専用命令」でなくても,一般的な「フック順序入れ替えを禁止して \yoko を必ず先頭に固定する方法」があれば十分

これはむしろ要望・実装の難易度が上がりそうですが…… 本件以外でも同様に「フック先頭を固定する機能」が有用な場面が複数あるなら,この方が良い選択肢になると思います.

@h-kitagawa
Copy link

一般的な「フック順序入れ替えを禁止して \yoko を必ず先頭に固定する方法」

なんだか泥沼になりそうな気がします(……と思うのは自分だけ?).
フックにいれられた「普通のコード」をレベル 0,「\DeclareHookRule に関係なく『普通のコード』より前で実行される」フック内のコードをレベル 1 と呼ぶことにすると,複数のレベル 1 コード間の順序が問題になる状況はすぐに生まれそうな気がします.
そうすると,「\DeclareHookRule に関係なくレベル 1 以下のコードより前で実行される」レベル 2 コードの概念が生まれ,以下同様に

\DeclareHookRule に関係なくレベル α 以下のコードより
前で実行されるコードをレベル α+1 のコードと呼ぶ (α∈On)

とかなると収拾がつきません.

@h20y6m
Copy link

h20y6m commented Sep 21, 2020

よくわかっていないのですが、

\AddToHook{shipout/before}{\yoko}
\documentclass{tarticle}
\begin{document}
\begin{figure}
\caption{キャプション}
\end{figure}
\end{document}

がエラーになります。

! Use `\yoko' at top of list.
\__hook shipout/before ->\yoko
                               \__hook_next shipout/before
l.7 \end{document}

詳細は分かりませんが、フロートのみの状態で \clearpage\end{document} のような命令が実行されたときに起きるようです。

ここの議論に影響しそうな気がしたので……

@aminophen
Copy link
Owner

LaTeX team に要望を送るに際して「通るべきテストケース」と「期待される結果」をまとめた物を示したいと思います。それ専用のリポジトリを立てようと思います。

l3build のログだけで確認するのは難しい可能性があるので,TeX ソースと生成した DVI や PDF を置いていく感じの想定で。

@aminophen
Copy link
Owner

フロートのみの状態で \clearpage や \end{document} のような命令が実行されたとき
! Use `\yoko' at top of list.

このテストケースがかなり重要なことがわかりました。前に私が書いていた

LaTeX 側で shipout/before フックの前にプレースホルダを入れる

の方法も,やはり原理は同じでエラーが出てしまいます。事はそんなに単純じゃなかった…。

@h-kitagawa
Copy link

フロートのみの状態で \clearpage や \end{document} のような命令が実行されたとき

この状態で hook の内容を

\AddToHook{shipout/before}[platex]{\tracingall\showlists\tracingnone\yoko}

として \yoko 直前のリストの内容を出力させたところ

### tate direction, internal vertical mode entered at line 12 (\output routine)

\write-{} % クラスファイル読み込み時の \onecolumn→\clearpage 由来
\write-{} % \end{document} 内の \clearpage 由来
prevdepth ignored
### tate direction, vertical mode entered at line 0
### recent contributions:
\penalty 10000
prevdepth 0.0

となっていました.\output で入った内部垂直モード内に \clearpage 由来の \write が 2 つあるのが「! Use `\yoko' at top of list.」の原因だと思われますが,まだよくわかりません.

@aminophen
Copy link
Owner

https://github.com/texjporg/tests-shipout の candidate 3 を以って,everyshi の公開インタフェースをパッチすることなく pLaTeX カーネル内部で対策できるようになりました。これが pLaTeX に採用されれば pxeveryshi は不要となるため,先走って 51be5bf でコードを消してみました。

pLaTeX カーネルが確定しましたら,この pull request は close させていただきます。

@wtsnjp
Copy link
Author

wtsnjp commented Sep 25, 2020

その変更をこのプルリクに追加コミットしようと思っていたのですが,先に反映されたのですね.了解しました.

@aminophen
Copy link
Owner

platex-tools 2020-09-27 を出しました。

  • pLaTeX2e 2020-10-01 は現在も作業中ですが,なんとか間に合わせる。
  • pxeveryshi / pxatbegshi 側では,上記を前提に何もしない。

という方針により,こちらは close と致します。

@aminophen aminophen closed this Sep 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants