\AtBeginDocument とパッケージ

\AtBeginDocument とパッケージ

これは、(Lua)LaTeX コンパイラの非常に不可解な動作です。以下の状況では、出力は、一部のコードがパッケージに配置されているか、メイン ファイルに直接配置されているかによって異なります。\relaxドキュメントの先頭で追加のコマンドを要求すると、動作が変わります。また、謎のバグの原因を特定することはできません... このような動作を生成するためにコンパイラの内部で何が起こっているかを理解して、後続の同様の望ましくない動作を回避したいと思います。

状況は以下のとおりです。次の文書をご覧くださいmain.tex

\documentclass{minimal}
\usepackage{sandbox}
\begin{document}
$\alpha$
\end{document}

次のsandbox.styファイルと一緒に:

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{sandbox}
\AtBeginDocument{\relax}
\RequirePackage{unicode-math}
\AtBeginDocument{\renewcommand\alpha{\beta}}
\endinput

コンパイル後、ベータ記号が出力されるはずだったのに、アルファ記号が出力されます...! これが最初の驚くべき動作です。

さらに不思議なことに、もし私がどちらか以下の3つのいずれか:

  • ;\AtBeginDocument{\relax}の行をコメント化します。sandbox.sty
  • ;\RequirePackage{unicode-math}の行をコメント化します。sandbox.sty
  • の行\usepackage{sandbox}main.texコアコンテンツsandbox.sty(つまり、3行がパッケージの実際のコンテンツ)に置き換えます。

その後、当初予想したとおり、ベータ版が印刷されます... これはまったく矛盾しているようです! 説明の手がかりを持っている人はいますか?...

答え1

コメントで指摘されているように、これはフックへの追加の動作に関係しています。マテリアルはフックに追加され、デフォルトの順序では「以前の」ファイルのフックコンテンツが先に実行されます。を除外する最上位のエントリ (ユーザー ドキュメント) は最後にあります。\ShowHook{begindocument}入力に追加すると次のようになります。

-> The hook 'begindocument':
> Code chunks:
>     sandbox -> \relax \renewcommand \alpha {\beta }
>     fontspec-luatex -> \tl_set_eq:NN \cyrillicencoding \g_fontspec_encoding_t
l \tl_set_eq:NN \latinencoding \g_fontspec_encoding_tl \RenewDocumentCommand \o
ldstylenums {m}{\__fontspec_main_oldstylenums:n {##1}}\fontspec_maybe_setup_mat
hs: 
>     amsmath -> \reset@strutbox@ \MakeRobust \dddot \MakeRobust \ddddot \Umath
charnumdef \std@minus \Umathcodenum `\-\relax \Umathcharnumdef \std@equal \Umat
hcodenum `\=\relax \expandafter \let \csname overleftarrow \endcsname \@undefin
ed \expandafter \let \csname overrightarrow \endcsname \@undefined \MakeRobust 
\overrightarrow \MakeRobust \overleftarrow \MakeRobust \overleftrightarrow \Mak
eRobust \underrightarrow \MakeRobust \underleftarrow \MakeRobust \underleftrigh
tarrow 
>     unicode-math-luatex -> \__um_define_math_chars: \tl_if_eq:onT {\g__fontsp
ec_mathrm_tl }{\rmdefault }{\__fontspec_setmathrm_hook:nn {}{}}\tl_if_eq:onT {\
g__fontspec_mathsf_tl }{\sfdefault }{\__fontspec_setmathsf_hook:nn {}{}}\tl_if_
eq:onT {\g__fontspec_mathtt_tl }{\ttdefault }{\__fontspec_setmathtt_hook:nn {}{
}}\bool_if:NF \g__um_main_font_defined_bool \__um_load_lm: \__um_setup_mathtext
: \__um_define_prime_commands: \__um_define_prime_chars: \cs_new_protected:Npn 
\__um_patch_url: {\tl_put_left:Nn \Url@FormatString {\__um_switch_to:n {literal
}}\tl_put_right:Nn \UrlSpecials {\do \`{\mathchar `\`}\do \'{\mathchar `\'}\do 
\${\mathchar `\$}\do \&{\mathchar `\&}}}\@ifpackageloaded {url}{\__um_patch_url
: }{}\cs_new_protected:Npn \__um_patch_mathtools_B: {\cs_set_eq:NN \MToverbrack
et \overbracket \cs_set_eq:NN \MTunderbracket \underbracket \AtBeginDocument {\
msg_warning:nn {unicode-math}{mathtools-overbracket}\cs_set:Npn \downbracketfil
l ####1####2{\tl_set:Nn \l_MT_bracketheight_fdim {.27ex}\downbracketend {####1}
{####2}\leaders \vrule \@height ####1\@depth \z@ \hfill \downbracketend {####1}
{####2}}\cs_set:Npn \upbracketfill ####1####2{\tl_set:Nn \l_MT_bracketheight_fd
im {.27ex}\upbracketend {####1}{####2}\leaders \vrule \@height \z@ \@depth ####
1\hfill \upbracketend {####1}{####2}}\cs_set_eq:NN \Uoverbracket \overbracket \
cs_set_eq:NN \Uunderbracket \underbracket \cs_set_eq:NN \overbracket \MToverbra
cket \cs_set_eq:NN \underbracket \MTunderbracket }}\@ifpackageloaded {mathtools
}{\__um_patch_mathtools_B: }{}\cs_new_protected:Npn \__um_patch_mathtools_C: {\
msg_warning:nn {unicode-math}{mathtools-colon}\DeclareDocumentCommand \dblcolon
 {}{\Colon }\DeclareDocumentCommand \coloneqq {}{\coloneq }\DeclareDocumentComm
and \Coloneqq {}{\Coloneq }\DeclareDocumentCommand \eqqcolon {}{\eqcolon }}\@if
packageloaded {mathtools}{\__um_patch_mathtools_C: }{}\Umathcharnumdef \std@min
us \Umathcodenum `-\Umathcharnumdef \std@equal \Umathcodenum `=\debug_suspend: 
\__um_resolve_greek: \debug_resume: \@ifpackageloaded {amsmath}{}{\__um_redefin
e_radical: }\__um_setup_active_frac: \g__um_secret_hook_tl 
> Document-level (top-level) code (executed last):
>     ---
> Extra code for next invocation:
>     ---
> Rules:
>     ---
> Execution order:
>     sandbox, fontspec-luatex, amsmath, unicode-math-luatex.
<recently read> }

のフックは のフックsandboxより前に発生することに注意してくださいunicode-math。そのため、同じエントリを再定義する場合は後者が「優先」されます。

フックシステムのポイントは、順序を制御できるようにすることです。したがって、追加する必要があるのは

\DeclareHookRule{begindocument}{sandbox}{after}{unicode-math-luatex}
\DeclareHookRule{begindocument}{sandbox}{after}{unicode-math-xetex}

sandboxフックコードが順序付けられていることを確認するために、ファイルに次の行を追加します。

> Execution order (after applying rules):
>     fontspec-luatex, amsmath, unicode-math-luatex, sandbox.

関連情報