我需要对以下代码进行一些修改,以便更好地适应我的用例,但我真的很难学习和理解它的一些语言。像这样的标记\tl
太短了,无法在搜索中返回任何有意义的结果,我甚至不知道它代表什么,无法尝试通过它找到它。
以下是代码:
% code to create chapters, verses, and cross references
\ExplSyntaxOn
\int_new:N \crossref_int
\int_new:N \vs_int
\tl_new:N \crossref_tl
% insert a cross reference
\NewDocumentCommand {\crossref} {m}
{
\int_compare:nNnT { \crossref_int } > { 25 }
{
\int_set:Nn \crossref_int { 0 }
}
\int_incr:N \crossref_int
% NOT PRESENTLY REQUIRING LETTERED SUPERSCRIPTS
% \textsuperscript{ \emph { \int_to_alph:n { \crossref_int } } }
\tl_if_empty:NF \crossref_tl
{
\tl_gput_right:Nn \crossref_tl { ~ }
}
\tl_gput_right:Nx \crossref_tl
{
% NOT PRESENTLY REQUIRING LETTERED SUPERSCRIPTS
% \exp_not:N \textsuperscript
% {
% \exp_not:N \emph { \int_to_alph:n { \crossref_int } }
% }
\, #1
}
}
%Sample output
% insert chapter marker
\NewDocumentCommand {\ch} {m}
{
\int_gset:Nn \vs_int {1}
\lettrine [findent=0.5em,nindent=0em] { #1 } {}
}
% output cross references from previous verse and insert verse marker
\NewDocumentCommand {\vs} {m}
{
\tl_if_empty:NF \crossref_tl
{
\sidebar
{
\textbf { \int_use:N \vs_int } \, \tl_use:N \crossref_tl
}
}
\int_gset:Nn \vs_int { #1 }
\tl_gclear:N \crossref_tl
\textsuperscript { #1 \, }
}
% output any remaining cross references
\AtEndDocument
{
\tl_if_empty:NF \crossref_tl
{
\sidebar
{
\textbf { \int_use:N \vs_int } \, \tl_use:N \crossref_tl
}
}
}
\ExplSyntaxOff
在此代码中的某个地方,交叉引用大概被放置在边缘处,但目前在该过程中有几件事情无法正常工作,我需要进行修复,包括这仅适用于偶数页,它不会使参考编号变为粗体(并且奇怪的是,当我尝试\emph
在代码中添加时,交叉引用全部落在文本列中而不是边缘处),并且我希望能够将第二个文本列的引用发送到边缘的底部 - 如果可能的话。
感谢那些能够帮助我理解此代码的人!
答案1
没有\tl
。我认为你可能会有点困惑,因为你看到了 expl3 语法(因此代码周围是\ExplSyntaxOn
...) 。可以通过键入简短概述和详细但不一定容易理解的说明\ExplSyntaxOff
来找到此内容的关键文档。Alan Xiang 的texdoc expl3
texdoc interface3
LaTeX3 教程是一个更温和的介绍和一个良好的起点。
但是让我们一点一点地浏览您的代码以尝试理解它:
\ExplSyntaxOn
这是我们处于 expl3 模式的信号。在此模式下,命令名称可以包含_
,:
因此您认为的\tl
实际上是多个以 开头\tl
但内容更多的不同命令名称。此外,此模式下的所有空格都将被忽略(如果您需要文字空格,~
将提供该空格,\nobreakspace
如果您需要不间断空格,则可以使用 while。
\int_new:N \crossref_int
\int_new:N \vs_int
\tl_new:N \crossref_tl
这里我们声明了一些新变量¹。标准命令的命名是使用\
⟨范围⟩ _
⟨模块⟩ _
⟨描述⟩ _
⟨类型⟩ 来命名这些。可惜的是,除了将类型放在末尾之外,此代码没有遵循该约定。我们还看到了一些命令。命令的 expl 3 约定是\
⟨模块⟩ _
⟨描述⟩ :
⟨参数规范⟩ 至少在内部是遵循的。这:
有助于注意到什么时候是命令而不是变量,这至少有助于解决 TeX 编程的神秘性的一个方面。所有 expl3 命令将要有:
,即使它们不接受参数。在这里我们看到一个 arg-spec,N
它引用单个标记,这里是 LaTeX 控制序列名称。所以我们在这里所做的是定义两个新的整数变量和一个标记列表(这就是\tl
您到处看到的)。
% insert a cross reference
\NewDocumentCommand {\crossref} {m}
这里我们定义了一个新的文档命令,\crossref
带有一个强制参数。这大致相当于您可以在命令行中输入\newcommand*{\crossref}[1]{...}
以下内容来了解详细信息。\NewDocumentCommand
texdoc xparse
{
\int_compare:nNnT { \crossref_int } > { 25 }
{
\int_set:Nn \crossref_int { 0 }
}
现在我们实际上已经开始了命令定义。我们正在进行整数比较。这里的参数规范是nNnT
。sn
指的是用括号分隔的参数。N
再次是一个单个标记,尽管这次是,>
并且T
是的特殊情况,n
它指的是比较为真时要执行的代码块(还有F
和两者都可以用于比较,因此,例如,\int_compare:nNnTF
它在比较代码后占用两个代码块来执行真和假分支。
因此在这种情况下,如果\crossref_int
大于 25,我们将其重置为 0。因为正如我们稍后会看到的,我们使用它来生成字母索引,所以这是完全合理的。
\int_incr:N \crossref_int
在这里,我们增加了 的值\crossref_int
。
% NOT PRESENTLY REQUIRING LETTERED SUPERSCRIPTS
% \textsuperscript{ \emph { \int_to_alph:n { \crossref_int } } }
\tl_if_empty:NF \crossref_tl
{
\tl_gput_right:Nn \crossref_tl { ~ }
}
现在,标记列表开始发挥作用。正如其名称所示,标记列表是标记列表。在本例中,我们查看 的值\crossref_tl
并查看它是否为空。如果是不是(注意F
上的参数说明\tl_if_empty
),然后我们调用\tl_gput_right:
在右侧添加一个空格。g
ingput
表示全局,这是遵循 expl3 约定会很有用的地方之一。 TeX 的局限性之一是,如果您对其寄存器变量进行全局和本地操作,则可能会导致内存泄漏。 Knuth 对此的建议是采用一种约定,例如,只对偶数寄存器执行全局操作,对奇数寄存器执行本地操作。²
\tl_gput_right:Nx \crossref_tl
{
% NOT PRESENTLY REQUIRING LETTERED SUPERSCRIPTS
% \exp_not:N \textsuperscript
% {
% \exp_not:N \emph { \int_to_alph:n { \crossref_int } }
% }
\, #1
}
}
然后是此命令的主要工作。将新的标记列表放入标记列表的右侧\crossref_tl
。请注意,这里的参数列表表示Nx
我们x
想要在附加列表之前扩展列表的内容。这将允许注释的代码在添加到标记列表之前执行,这是我们想要的,因为我们关心\crossref_int
执行命令时的值。如果我们没有这样做,那么我们最终会得到一个标记列表,例如,
d注1d笔记2d注 3d注 4
而不是期望的
A注1b笔记2C注 3d注 4
%Sample output
% insert chapter marker
\NewDocumentCommand {\ch} {m}
{
\int_gset:Nn \vs_int {1}
\lettrine [findent=0.5em,nindent=0em] { #1 } {}
}
这个很简单。我们定义\ch
采用单个强制参数,并使用lettrine
class³ 以首字下沉样式设置章节编号。我们还(全局)将计数器设置\vs_int
为 1。
% output cross references from previous verse and insert verse marker
\NewDocumentCommand {\vs} {m}
{
\tl_if_empty:NF \crossref_tl
{
\sidebar
{
\textbf { \int_use:N \vs_int } \, \tl_use:N \crossref_tl % ❶
}
}
\int_gset:Nn \vs_int { #1 } % ❷
\tl_gclear:N \crossref_tl % ❸
\textsuperscript { #1 \, } % ❹
}
因此,在这里,我们\vs
还定义了一个强制参数,即诗句编号,它被设置为诗句文本前的上标❹。但在此之前,我们将输出交叉引用(如果有)。我们查看\crossref_tl
它是否为空(\tl_if_empty
),如果不是(因此F
在参数规范中),我们使用\sidebar
以粗体显示来设置的值\vs_int
(我们必须使用\int_use:N
来获取此目的的值),然后设置标记列表的内容\crossref_tl
(再次,\tl_use:N
是获取该值所必需的❶)。然后,我们将的值设置为\vs_int
传递给参数\vs
❷的数字并清除\crossref_tl
标记列表❸。
% output any remaining cross references
\AtEndDocument
{
\tl_if_empty:NF \crossref_tl
{
\sidebar
{
\textbf { \int_use:N \vs_int } \, \tl_use:N \crossref_tl
}
}
}
最后一段代码是为了确保剩余的交叉引用输出到文档末尾。这是使用钩子完成的\AtEndDocument
(尽管较新的风格应该是这样写\AddToHook{enddocument}
(LaTeX 为类和包编写者添加了广泛的“钩子”机制。请参阅texdoc source2e
详细信息)。设置此项的代码与定义时使用的代码基本相同,\vs
因此我不会再多说了。
\ExplSyntaxOff
然后我们关闭 expl 语法,以便文档的其余部分没有问题。
至于您最初的问题,我猜您要解决的问题在于 的定义\sidebar
,无论它来自哪里。
TeX 没有确切地有变量。有 256 个寄存器各种类型(计数器
\count
– 用普通的 TeX 语言来表示,它保存整数、长度(普通的 TeX 称之为\dimen
s)、胶水(普通的 TeX 称之为\skip
s,它们本质上是可以拉伸或收缩的长度)、标记列表、盒子、muskips、插入、读写流和数学字体系列。其中大多数限制为 256 个寄存器,一些寄存器被保留(例如,\count0
页码)。TeX 中的大多数“变量”只是宏,这让生活有点困难,expl3 试图对事物施加一些秩序,尽管正如我们将看到的,这种秩序并没有被强制执行)。或者可能恰恰相反。我要回忆一下 1986 年的往事。
这是一个很好的例子正确的使用
lettrine
。由于首字下沉没有任何语义值,因此实际上不应直接在文本中设置,而应将其作为其他代码的一部分。无需太多努力,就可以使用 的lettrine
功能自动设置第一个段落的第一个字母,\chapter
而无需任何额外的标记。