6.5.1 ⁑Hierarchical Paragraph Numbering
Suppose you want a document that looks something like the following:
The simplest way of achieving this is to use the enumerate
environment (described in Volume 1) and redefine the way
the counters are displayed. By default, LaTeX allows up to four
nested enumerate
environments. Each level has a separate
counter: enumi
, enumii
, enumiii
and
enumiv
. Recall from Volume 1
that
the displayed value of a counter is governed by the command:
(For example, \theenumi
.)
The default formats for each level use: \arabic
, \alph
,
\roman
and \Alph
. The format used if the
items are cross-referenced using the \label
/\ref
mechanism prefixes \the⟨counter⟩
with:
For example, \p@enumiv
\theenumiv
.
The prefix is ignored if \p@⟨counter⟩
doesn't exist (so just \the⟨counter⟩
is used).
The above \the⟨counter⟩
and \p@⟨counter⟩
are general counter-related commands.
In addition, for the enumerate
environment, there are also
commands that determine the item label formats:
(For example, \labelenumi
for the first level.)
Example:
Suppose you want to have a lower case letter for the third level enumerate items:
and you want the label for the third level enumerate items to use parentheses:
but when you cross-reference a third level enumerate item,
\ref
should use the format
⟨level1⟩.⟨level2⟩.⟨level3⟩:
or, similarly setting \p@enumii
:
To reproduce the format shown at the start of this section,
the standard \section
command can be used for the first level
(“Information About Us”, “Our Products” and “Refunds”). The
levels below this can be created using nested enumerate
environments, where the counter formats are defined as:
\renewcommand*{\theenumi}{\thesection.\arabic{enumi}} \renewcommand*{\theenumii}{\theenumi.\arabic{enumii}} \renewcommand*{\theenumiii}{\theenumii.\arabic{enumiii}} \renewcommand*{\theenumiv}{\theenumiii.\arabic{enumiv}}
and the labels are defined as:
\renewcommand*{\labelenumi}{\theenumi.} \renewcommand*{\labelenumii}{\theenumii.} \renewcommand*{\labelenumiii}{\theenumiii.} \renewcommand*{\labelenumiv}{\theenumiv.}
Since all the counter formats (\theenumi
, …, \theenumiv
)
are now hierarchical, the internal commands used as a prefix by the
cross-referencing mechanism need to be defined to do nothing:
\renewcommand*{\p@enumi}{} \renewcommand*{\p@enumii}{} \renewcommand*{\p@enumiii}{} \renewcommand*{\p@enumiv}{}
The text can now be formatted as follows:
\section{Information About Us} \begin{enumerate} \item This website is run by the Secret Lab of Experimental Stuff (``We'', ``Our''). We operate from the University of Somewhere. \end{enumerate} \section{Our Products} \begin{enumerate} \item All Products shown on our site are subject to availability. \item You may only purchase our products if you are at least 18 years old. \end{enumerate} \section{Refunds} \begin{enumerate} \item You are entitled to a refund unless: \begin{enumerate} \item you have eaten the mind-controlling cookies; \item you have thrown the exploding chocolates; \item you have used the ray gun as: \begin{enumerate} \item a table chock; \item a weapon unless: \begin{enumerate} \item \label{permit}you have a ray gun permit; \item you are an extraterrestrial. \end{enumerate} \end{enumerate} \end{enumerate} \end{enumerate}
I've labelled one of the items using \label
, so I can
reference it using:
which produces:
6.5.1.1 ⁂Delving Deeper
If your document is complicated enough to require deeper levels than
the default maximum of four, it's possible to extend the maximum
enumerate
depth. In order to do this, it's necessary to:
- Modify the
enumerate
environment to allow more levels. This may additionally require modifying the underlying genericlist
environment that only allows a maximum of six nested list environments. - Define a new enum⟨n⟩ counter (using
\newcounter
) for each level ⟨n⟩, where ⟨n⟩ is the lower case Roman numeral representing the level index. (For example, enumv for the fifth level). - Define a new
\labelenum
⟨n⟩ command for the item label for each level ⟨n⟩. - Define a new
\leftmargin
⟨n⟩ length (using\newlength
and\setlength
) for the left margin for each level ⟨n⟩. - Define a new
\@list
⟨n⟩ command that sets up the margin for each level ⟨n⟩.
The counters and label commands are the easy part. For example, to allow a maximum of six levels, counters and label commands need to be defined for levels 5 (v) and 6 (vi):
\newcounter{enumv}[enumiv] \newcounter{enumvi}[enumv] \newcommand*{\labelenumv}{\theenumv.} \newcommand*{\labelenumvi}{\theenumvi.}
(If necessary, you can also redefine the counter prefixes
\p@⟨counter⟩
.)
The left margin lengths are already provided up to six levels, but supposing you needed a seventh (vii), this would be done using:
\newlength\leftmarginvii \setlength{\leftmarginvii}{15pt}
(Change the length as required.)
The \@list
⟨n⟩ commands are more complicated. These commands
need to set the length \leftmargin
to the current level's left margin
\leftmargin
⟨n⟩ and set the \labelwidth
length to
\leftmargin
⟨n⟩ less the value of \labelsep
.
Again, there are already up to six levels provided, but supposing you
needed a seventh (vii), this would be done using:
\newcommand*{\@listvii}{% \setlength{\leftmargin}{\leftmarginvii}% \setlength{\labelwidth}{\leftmarginvii}% \addtolength{\labelwidth}{-\labelsep}% }
Modifying the enumerate
environment is slightly harder.
This can be done using \renewenvironment
(described in
Volume 1) however, in this case, only the beginning of the
environment needs changing. The \begin
{
⟨env-name⟩}
command
works by (amongst other things) using the command
\⟨env-name⟩
so \begin
{enumerate}
calls the command \enumerate
, and it's this command that
needs modifying. Recall from §2.1.1 Macro Definitions that you can
find out the definition of a command using either \show
in your
document or using the texdef script. If I run:
I get the response (tidied up a bit for legibility):
\enumerate: macro:->\ifnum \@enumdepth >\thr@@ \@toodeep \else \advance\@enumdepth\@ne \edef\@enumctr{enum\romannumeral\the\@enumdepth}% \expandafter\list\csname label\@enumctr\endcsname{% \usecounter\@enumctr \def\makelabel##1{\hss\llap{##1}}% }% \fiThe key part here is the TeX conditional:
\ifnum \@enumdepth >\thr@@This tests if the number stored in the
\@enumdepth
register is greater
than \thr@@
(which is defined in the LaTeX kernel to have the value
3). So the new definition of \enumerate
needs to change
\thr@@
to one less than the new maximum.
Since this code contains internal commands, the new definition
should either be placed in a class or package or, if used in the
document, be placed between \makeatletter
and
\makeatother
. Therefore to set the maximum to six levels:
\makeatletter \renewcommand*{\enumerate}{% \ifnum \@enumdepth > 5 \@toodeep \else \advance\@enumdepth\@ne \edef\@enumctr{enum\romannumeral\the\@enumdepth}% \expandafter\list\csname label\@enumctr\endcsname{% \usecounter\@enumctr \def\makelabel##1{\hss\llap{##1}}% }% \fi } \makeatother
If you really do need more than six levels (although I hope you don't), you
similarly need to modify \list
, which by default tests if
\@listdepth
is greater than five.
enumerate
Depth
For this exercise, extend the maximum enumerate
depth to
6 levels (as described above), so that you can create the following:
The choice of document class is up to you. For example, you can use
the article or scrartcl classes. (If you use
scrartcl, the class option numbers=endperiod
will
display a full stop after the section numbers.)
You can download
or
view
a solution.
This book is also available as A4 PDF or 12.8cm x 9.6cm PDF or paperback (ISBN 978-1-909440-07-4).