我需要将一段代码的执行延迟到其他包加载时,因此我将其包装到\AtBeginDocument
:
\AtBeginDocument{%
\def\reserved@a#1#2{%
\edef\reserved@b{#1}%
\edef\reserved@c{#2}%
\ifx\reserved@b\reserved@c
\let\cyrillicencoding\reserved@c
\fi}
\def\cdp@elt#1#2#3#4{%
\reserved@a{#1}{OT2}%
\reserved@a{#1}{LCY}%
\reserved@a{#1}{X2}%
\reserved@a{#1}{T2C}%
\reserved@a{#1}{T2B}%
\reserved@a{#1}{T2A}%
\if@uni@code
\reserved@a{#1}{EU1}%
\reserved@a{#1}{EU2}%
\fi}
\cdp@list
}
此代码查看已加载的字体编码列表(保存在 中\cdp@list
),将其与预定义的所需西里尔编码列表(从最不优选到最优选排序)进行比较(OT2、LCY... EU2),然后将选定编码的名称保存到宏\cyrillicencoding
。如果 LuaTeX 或 XeTeX 正在运行,则布尔宏的\if@uni@code
计算结果为 true:
\newif\if@uni@code
\ifdefined\luatexversion \@uni@codetrue \else
\ifdefined\XeTeXrevision \@uni@codetrue \fi\fi
它工作正常。但是,如果我将部分预备定义移出框外,它就会失败。例如,
\def\reserved@a#1#2{%
\edef\reserved@b{#1}%
. . .
\fi}
\AtBeginDocument{\cdp@list}
我猜测移动参数内的宏\AtBeginDocument
应该以某种方式被protect
编辑或expendafter
。有人能解释一下我的烦恼从何而来吗? 第二个问题:将大块代码延迟到文档开始时间是一种好的做法吗?
更新:这是一个最简单的例子:
\documentclass{minimal}
\usepackage{mytest}
\usepackage[T2B]{fontenc}
\begin{document}
\verb|cyrillicencoding|={\csname cyrillicencoding\endcsname}
\end{document}
和mytest.sty
\def\reserved@a#1#2{%
\edef\reserved@b{#1}%
\edef\reserved@c{#2}%
\ifx\reserved@b\reserved@c
\let\cyrillicencoding\reserved@c
\fi}
\def\cdp@elt#1#2#3#4{%
\reserved@a{#1}{T2C}%
\reserved@a{#1}{T2B}%
\reserved@a{#1}{T2A}%
}
\AtBeginDocument{\cdp@list}
如果将 的整个内容mytest.sty
包装到 中\AtBeginDocument
,则输出将是\cyrillicencoding=T2B
。
答案1
你应该绝不依赖于\reserved@a
内核经常用作“临时宏”的类似控制序列名称的含义。因此删除\reserved@a
from的定义\AtBeginDocument
是错误的,这就是为什么带有
\AtBeginDocument{\cdp@list}
例如,对于一个最小文档,执行\reserved@a
时我得到的意思是\@begindocumenthook
> \reserved@a=macro:
->\def \@currenvir {document}\edef \@currenvline {\on@line }\csname document\endcsname .
在 中包含大段代码并没有错\AtBeginDocument
;但是你可以通过以下方式缩短标记列表:
\def\@setcyrillicencoding{%
\def\sce@a##1##2{%
\edef\sce@b{##1}%
\edef\sce@c{##2}%
\ifx\sce@b\sce@c
\let\cyrillicencoding\sce@c
\fi}%
\def\cdp@elt##1##2##3##4{%
\sce@a{##1}{OT2}%
\sce@a{##1}{LCY}%
\sce@a{##1}{X2}%
\sce@a{##1}{T2C}%
\sce@a{##1}{T2B}%
\sce@a{##1}{T2A}%
\if@uni@code
\sce@a{##1}{EU1}%
\sce@a{##1}{EU2}%
\fi}%
\cdp@list
}
\AtBeginDocument{\@setcyrillicencoding}
\@onlypreamble\@setcyrillicencoding
\@onlypreamble\sce@a
\@onlypreamble\sce@b
\@onlypreamble\sce@c
最后几行用于释放文档中无用的宏\@setcyrillicencoding
和所占用的内存。的内容将自动清除。\sce@x
\@begindocumenthook
由于\reserved@a
在那里使用,因此不建议重新定义它。
答案2
有人能解释一下我的烦恼从何而来吗?
您正在使用预订的*临时*宏,然后不要直接使用它们。一旦执行任何其他 LaTeX 内核宏,这些宏可能会被覆盖。换句话说,您的定义将不会保留,直到\begin{document}
您的\cdp@list
宏使用临时宏的一些任意定义。
您应该使用其他临时宏。如果babel
您调用的代码确实需要\reserved@a
使用,您需要确保在使用宏之前直接进行定义\cdp@list
。
而且,您的定义也\cdp@elt
被改变了fontenc
,所以当然您需要在使用它之前直接进行这个定义,而不是在您的包内。
将大块代码延迟到文档开始时间是一种好的做法吗?
我会将所有内容定义到一个宏中,并仅将此宏添加到钩子中。每次钩子获得更多代码时,所有旧代码都会被复制,如果许多软件包安装了大量代码,则成本会很高。请注意,#
如果将宏定义放入宏中,则需要将所有内容翻倍。