我想在目录中添加线段分隔符,并发现以下方法有效:
\documentclass[12pt]{book}
\usepackage{tocloft}
\begin{document}
\thispagestyle{empty}
\addtocontents{toc}{{\textbf{------------------}}}
%\addtocontents{toc}{\rule{1.5in}{.02mm}}
\tableofcontents
\end{document}
输出结果如下:
不过,我想让分隔符更厚;我想我可以尝试这个:
\addtocontents{toc}{\rule{1.5in}{.02mm}}
但遗憾的是,它不起作用(导致出现大量错误行)。
问题:如何调整目录中线段分隔符的粗细(和长度)?这似乎应该是一项简单的任务,但我一直不知道该怎么做。
答案1
简短回答
使用\protect\rule
而不是\rule
,或者更新你的 TeX 发行版。
长答案
\addtocontents
使用 TeX 的\write
原语将 LaTeX 代码写入 .toc 文件,并\write
在页面发送出去时递归扩展标记(\write
导致那是什么节点添加到 TeX 正在组装的当前列表中,因此最终,此节点位于明确定义的页面上)。这是必要的,以便\thepage
扩展到正确的页码,尽管 TeX 在段落被组装之前不知道给定字符/框/什么/等的位置。完整阅读(这是因为它优化了所有换行符的集合在每个段落中)。
因此,此\write
操作会导致宏被展开,但有些宏是稍后在读取 .toc 文件排版目录时展开的,而不是在编写目录时展开的。测试通常就是这种情况。
在您的示例中,\rule
使用\@ifnextchar
来测试 是否存在[
,即确定是否提供了可选参数(指定应提高规则的量)。这是如何工作的?
经过一些简化(因为\@ifnextchar
在寻找下一个非空间标记时会跳过空间标记),\@ifnextchar
使用\futurelet
设置\@let@token
为输入流中的下一个标记并插入一些宏来测试是否\@let@token
等同\ifx
于[
。这就是早期扩展\write
使其惨遭失败的地方:\futurelet
当 TeX 仅扩展标记时(\write
递归扩展其参数时就是这种情况),原语无法完成其工作。\futurelet
是不可扩张;其展开式为\futurelet
。因此,当\write
展开其参数时,\futurelet
不会分配\@let@token
,但是以下测试看是否\@let@token
等同\ifx
于[
本质上可扩展。因此,它会被展开(根据当前的含义丢弃真或假分支\@let@token
,无论它是什么),结果(在所有可扩展的内容都已展开之后)将写入 .toc 文件。如果没有进一步的错误阻止执行\write
,则意味着将做出选择并将结果刻在石头上(.toc 文件),但不会以正确的方式做出此选择。
如果采用了“错误的”代码分支,例如如果剩余分支对应于可选参数的存在而实际上没有参数,则此分支中的宏在\write
扩展它们时很可能会在早期导致错误:例如,可能有一个宏采用以 分隔的参数[
,如果在预期的位置没有 ,则会导致错误[
(它可能会抓取文档的大部分内容,然后找到合适的[
,从而导致以后出现进一步的错误,或者在到达文件末尾之前找不到任何参数)。
这可能是第一次运行 LaTeX 时出错的原因。在后续运行中,当读取 .toc 文件时,也可能出现错误,因为其中写入的代码\write
扩展得太早了。
为了避免此类问题,有几种技术。首先,请注意\addtocontents
不直接使用\write
,而是使用名为 的包装宏\protected@write
。默认情况下,此包装宏会立即扩展所有可扩展标记,但 除外\thepage
;此外, 之前的标记\protect
根本不会通过 进行扩展\protected@write
(\protect\whatever
写为\protect \whatever
)。
考虑到这一点,以下是用于防止您遇到的问题的典型技术:
\rule
可以制作宏强壮的。这是一种特殊类型的定义,由 完成\DeclareRobustCommand
,它\protect
在后台使用,以便“真实”代码仅在排版期间传递,而不是在\protect
-aware 扩展上下文中传递,例如在\protected@write
、\protected@edef
& Co 内。这是最近版本的 LaTeX 内核所具有的(一个强大的\rule
宏);在这种情况下,处于您这种情况的用户不会遇到任何问题。当
\rule
(或任何导致问题的脆弱命令) 不够强大时,这显然是您的情况,您可以在其前面加上\protect
,即:使用\protect\rule
而不是。这可以防止被使用\rule
的 扩展,因此在此阶段甚至看不到问题。读取 .toc 文件时,的实际代码会扩展(然后- 等于,通常等于)。\rule
\protected@write
\addtocontents
\@ifnextchar
\rule
\protect
\let
\@typeset@protect
\let
\relax
另一种主要可能性是使用类似(或等) 的东西将其定义
\rule
为宏。在这种情况下,甚至不会扩展它 — — 该机制是不需要的。但原语不是 Knuth TeX 的一部分;它是在 e-TeX 中添加的。我认为 LaTeX 团队在此期间开发了 + 技术,或者可能是后来开发的,但他们仍然希望 LaTeX 可以与当时的 Knuth TeX 一起使用;因此,+技术保留了下来,并且仍然在 LaTeX 内核中广泛使用,尽管据我所知,当前的 LaTeX 需要 e-TeX 扩展。\protected
\protected\def\rule...
\NewDocumentCommand
\write
\protected@write
\protected
\DeclareRobustCommand
\protect
\DeclareRobustCommand
\protect
注意:据我所知,所有正在积极开发中的 TeX 引擎都具有\protected
原语;我相信它们实现了大多数(如果不是全部) e-TeX 的扩展。