是否可以创建一个新的分段级别?

是否可以创建一个新的分段级别?

我想知道是否有可能在 \part 之上创建一个新的分段级别。我已经浏览了相当多似乎相关但实际上没有帮助的主题。有人建议将所有级别向下推一级,但 (i) 这将消除使用子段落的可能性(可以吗?)并且 (ii) 我对使用预先存在的设置可以获得的输出非常满意,而重新分配每个级别会相当麻烦(或者有什么简单的方法可以做到这一点?)。

简而言之,是否可以定义某种 \superpart{},其设置与 \part{} 相同,但写得更大或大写?

我希望我的问题足够清楚,并提前感谢您的回答。

文档结构如下:

\documentclass[a4paper, 10pt]{book}
\usepackage{blindtext}
\renewcommand{\thesection}{\arabic{section}}
\setcounter{secnumdepth}{5}


\begin{document}
\part{This is part1}
\chapter{Chapter title}
\section{This is a section}
\section{Section}
\subsection{Subsection}
\subsubsection{Subsubsection}
\paragraph{Paragraph}
\subparagraph{Subparagraph}

\blindtext

\end{document}

答案1

当然。没有理由你不能向任何方向无限前进。

在 中book, 的部分级别\part为 -1。您只需定义一个级别为 -2 的级别即可。

深入研究book.cls你会发现相关的定义\part

\newcommand\part{%
  \if@openright
    \cleardoublepage
  \else
    \clearpage
  \fi
  \thispagestyle{plain}%
  \if@twocolumn
    \onecolumn
    \@tempswatrue
  \else
    \@tempswafalse
  \fi
  \null\vfil
  \secdef\@part\@spart}

\def\@part[#1]#2{%
    \ifnum \c@secnumdepth >-2\relax
      \refstepcounter{part}%
      \addcontentsline{toc}{part}{\thepart\hspace{1em}#1}%
    \else
      \addcontentsline{toc}{part}{#1}%
    \fi
    \markboth{}{}%
    {\centering
     \interlinepenalty \@M
     \normalfont
     \ifnum \c@secnumdepth >-2\relax
       \huge\bfseries \partname\nobreakspace\thepart
       \par
       \vskip 20\p@
     \fi
     \Huge \bfseries #2\par}%
    \@endpart}
\def\@spart#1{%
    {\centering
     \interlinepenalty \@M
     \normalfont
     \Huge \bfseries #1\par}%
    \@endpart}
\def\@endpart{\vfil\newpage
              \if@twoside
               \if@openright
                \null
                \thispagestyle{empty}%
                \newpage
               \fi
              \fi
              \if@tempswa
                \twocolumn
              \fi}

我们不要仅仅通过剪切、粘贴和编辑来获得\superpart,而是用二十一世纪的 LaTeX 和来重新定义\NewDocumentCommmand

样式中的分段命令模板xparse是¹:

\NewDocumentCommand{\superpart}{s O{#3} m}{%

这表示我们的命令有一个可选的星号形式(s),一个可选参数(默认为强制参数的值),然后是一个强制参数。

然后我们可以做一些事情\part来为超级部分标题打开一个新的单列页面:

  \if@openright  % ❶
     \cleardoublepage
  \else
     \clearpage
  \fi
  \thispagestyle{plain}%
  \if@twocolumn
     \onecolumn
     \@tempswatrue
  \else
     \@tempswafalse
  \fi % ➀
  \null \vfil % ❷

到目前为止需要注意几点。在我标记 ❶ 的行上,我们检查是否应该在 recto² 页面上,如果是,则\cleardoublepage转到奇数页。否则,我们只需开始一个新页面。还请注意,我们有一些命令,@这意味着我们需要在类/包文件中,或者将我们的定义括在\makeatletter...中\makeatother

在标有 ❷ 的行上,\null之前的\vfil是一个空框。通常,页面顶部的任何粘连都会被忽略。这使我们能够将超部分标题置于页面中央。

接下来,我们检查是否对超级部分进​​行编号(我们可能正在编号),这取决于是否secnumdepth≥-2 以及我们是否正在进行星号形式。

我们将在本文末尾解释 ➀ 的含义。

  \IfBooleanF{#1}{% 
     \ifnum\c@senumdepth > -3\relax
       \refstepcounter{superpart}%
       \addcontentsline{toc}{superpart}{\thesuperpart\hspace{1em}#2}%
     \else
       \addcontentsline{toc}{superpart}{#2}%
     \fi
     \superpartmark{#2}% ❸
  }%

我对 ❸ 处的逻辑做了一点小改动,引入了一个我们稍后会定义的新命令。book假设您不希望零件名称进入标题,并且不提供这样做的功能。但也许你想。

接下来我们实际打印标题。

  {%
     \centering
     \interlinepenalty \@M % ❹
     \normalfamily
     \IfBooleanF{#1}{%
       \ifnum\c@secnumdepth > -3\relax % ❺
         \Huge % ❻
         \bfseries 
         \superpartname\nobreakspace\thesuperpart
         \par
         \vskip 20\p@
       \fi
     }%
  }

❹ 处的设置是错误的,也是一个坏主意,但这是 LaTeX 37 年来一直在做的事情,所以我不会改变它。它使 LaTeX 不愿意在段落内换行。这意味着 (a) 如果标题长度超过一页,则(超级)部分编号将被推到页面底部;(2) 如果不带编号的标题仍然太长而无法放在一页上,它就会溢出页面底部。故事的道德启示 不要使用长标题

我原本以为应该使用临时开关,以避免重复 ❺ 和上一个代码块中看似相同的逻辑,但仔细检查就会发现,由于对\superpartmark上面的调用,这两种情况并不完全相同。 不急于尽早优化的好例子。 另外,LaTeX 提供了@tempswa但没有@tempswb

我讨厌 LaTeX 的尺寸选择命令,比如 ❻ 中的命令。它们是位图字体时代的遗物,锁定在 Knuth 对字体大小的 1.2 次方的特殊选择上。“真正的”印刷师永远不会将某些东西设置为 17.28pt。较小的尺寸甚至更糟糕,因为 LaTeX 使用它来表示“比正常文本尺寸小两个尺寸”和“脚注的格式”。就我个人而言,我认为,至少所有尺寸调整命令都应该是名称中\footnotesize包含的私有命令。@

最后,我们总结一下 superpart 页面,

  \vfil\newpage
  \if@twoside
     \if@openright
       \null
       \thispagestyle{empty}% ❼
       \newpage
     \fi
  \fi
  \if@tempswa % ❽
     \twocolumn
  \fi
  \@afterheading ❾
}

在 ❼ 处,我们确保如果在右页上打开设置,我们会插入一个没有页眉或页脚的空白页。当然,正如我们在 的设置中提到的那样\interlineskip,不能保证我们的部分标题实际上会打印在一页上(尽管有保证如果它拆分到多个页面中会很难看)。

❽还记得在第一节中我们设置\@tempswatrue是否处于两列模式吗?现在我们可以利用该值再次恢复两列模式。

❾ 处的命令不是 的一部分\part,但可以说应该是 的一部分。LaTeX 通常会抑制节标题后的文本缩进³,在这种情况下没有理由不这样做。

现在我们有一些事情要做。首先,我们为我们的超级部分声明一个计数器:

\newcounter{superpart}

\thesuperpart如果我们不想使用默认的阿拉伯数字,我们也会重新定义。如果你想使用xparse-style 定义,你需要这样写,例如,

\RenewExpandableDocumentCommand{\thesuperpart}{}{\Roman{superpart}}

如果我们改用\RenewDocumentCommand,我们会发现目录中打印的数字是错误的,我们会很伤心。通常,我们希望命令是健壮的,并且在写入目录等时不会改变,但对于打印计数器值之类的事情,我们希望相反,这样我们实际上会写入MCMLXXXVIII而不是\thesuperpart

如果我们想用 superparts 来编号零件,我们还需要添加

\numberwithin{part}{superpart}

为了打印目录中的行,我们需要定义\l@superpart。这不是特别有趣,所以我只是对做了一些小的book修改\l@part

\NewDocumentCommmand\l@superpart{m}{%
  \ifnum \c@tocdepth >-3\relax
    \addpenalty{-\@highpenalty}%
    \addvspace{2.25em \@plus\p@}%
    \setlength\@tempdima{3em}%
    \begingroup
      \parindent \z@ \rightskip \@pnumwidth
      \parfillskip -\@pnumwidth
      {\leavevmode
       \large \bfseries #1\hfil
       \hb@xt@\@pnumwidth{\hss #2%
                          \kern-\p@\kern\p@}}\par
       \nobreak
         \global\@nobreaktrue
         \everypar{\global\@nobreakfalse\everypar{}}%
    \endgroup
  \fi}

我们需要定义要打印的名称\superpart。不妨自命不凡地称之为“Book”?

\NewDocumentCommand{\superpartname}{}{Book}

最后,我们创建了一个钩子,用于在页面标题中使用 superpart 标题(如果我们选择的话)。我决定让它执行该操作\part,即在两个标记中都放入空文本。

\NewDocumentCommand{\superpartmark}{m}{\markboth{}{}}

这就是(模数拼写错误,因为这当然都是未经测试的)如何从头开始定义分段命令。

编辑Ulrike Fischer 指出,需要付出一些额外的努力才能使分层书签发挥hyperref作用。⁴hyperref假设我们使用 LaTeX 的内部宏(和宏结构)来完成其工作。以下是它的作用\part

\let\H@old@part\@part % ❿
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname chapter\endcsname\relax
  \let\Hy@secnum@part\z@
\else
  \let\Hy@secnum@part\m@ne
\fi
\def\@part{%
  \ifnum\Hy@secnum@part>\c@secnumdepth
    \phantomsection % ⓫
  \fi
  \H@old@part
}
%    \end{macrocode}
%    \begin{macrocode}
\let\H@old@spart\@spart % ❿
\def\@spart#1{%
  \Hy@MakeCurrentHrefAuto{part*}% ⓬
  \Hy@raisedlink{%
    \hyper@anchorstart{\@currentHref}\hyper@anchorend
  }%
  \H@old@spart{#1}%
}

在 ❿(出现两次)处,我们使用了一个修补宏的老派技巧:(\let\foo=\bar=可选的)将 的当前含义复制\bar到 中\foo。当我们想要重新定义\bar但保留其功能时,这很方便。例如

\let\foo\bar
\NewDocumentCommand{\bar}{%
   stuff before old bar
   \foo % old bar functionality
   stuff after old bar
}

现在孩子们都在使用patchcmd软件包或ted进行更改,这更为可靠,但无论如何,这些修改都假设我们对命令定义方式的内部原理有所了解。无论如何,hyperref对我们的命令一无所知\superpart,所以它什么也不会做。

⓫ 是我们的目的中最重要的部分。\phantomsection在出现的位置添加一个锚点。文档表明它应该在 旁边\addcontentsline,所以我们必须回到我们的文档并\phantomsection在我标记 ➀ 的行后插入,但我们不想直接插入它,因为它可能不存在!所以我们改为这样做

\ifdefined\phantomsection
  \phantomsection
\fi

在那一点。那么 ⓬ 处的代码呢?好吧,事实证明,这几乎与 的代码完全相同\phantomsection,唯一的区别是而不是。我们在非 的情况下使用 的事实\phantomsection表明该值是什么并不重要,因此我们可以在选择的点处获得一个。\Hy@MakeCurrentHrefAuto{section*}\Hy@MakeCurrentHrefAuto{part*}\phantomsection*\phantomsection

为了处理层次结构,还有一件事是必要的hyperref。我们需要

\NewDocumentCommand{\toclevel@superpart}{}{-2}}

这些\toclevel@*命令不是 LaTeX 内核的一部分,但被类等使用,ams*并且也hyperref利用了这一点。如果我们没有为分段级别定义级别,hyperref则默认为 0(相当于\chapterin book),这不是我们想要的。再说一次,我没有测试过这些,但我认为我已经把所有移动部件都准备好了,或者至少解释得足够好,你应该能够修复任何错误。


  1. 关于这一点我有点撒谎。这与默认的 LaTeX 分段命令定义之间有一个关键区别:此定义允许您写入\superpart*[foo]{bar}哪个,默认情况下 LaTeX 将被解释为\superpart*{[} foo]{bar}哪个foo]{bar}将是 之后的第一个段落\superpart*。(顺便说一下,文档中提到了这一点xparse,尽管更简洁一些。)

  2. 印刷师用花哨的语言来表示右侧。左侧称为 verso。

  3. 不适用的情况是双栏模式下的after\part和 after 。我认为这些都是疏忽,但 37 年后再改变可能已经太迟了。\chapterbook.cls

  4. 他还发现了一些拼写错误,我已经修正了。谢谢你的校对!

答案2

类(和memoir的超集)在分区上方提供了一个分区。手册提供了有关此代码的一般详细信息。和的格式的各个方面都很容易配置。bookreport\book\part\book\part

相关内容