Tuesday, March 22, 2011

Modifing some heading styles in LaTeX table of contents

I had several questions asked about the style of section titles in the table of contents. These concern the display or not of section numbers and/or pages for these sections.

Sectioning depth in TOC

The first easy question concerns the sectioning depth at which to stop using numbers. Usually, in the article class, sections are numbered up to the \subsubsection level, (e.g., "1.1.1 My sub-sub-section"), and not numbered below that, i.e., not for paragraphs or sub-paragraphs.

Sometimes, you may not want the sub-sub-sections to be in the table of contents (TOC), or you may want the paragraphs. For this, LaTeX provides a counter, tocdepth that we can set to determine the sectioning depth at which to stop putting sections in TOC. For instance:
\setcounter{tocdepth}{4}
will display up to the paragraph, while
\setcounter{tocdepth}{1}
will only display the sections.

Additionally, you may not want any number associated to sub-section, or you may want numbers associated to sub-paragraphs. This is controled by the secnumdepth counter respectively by:
\setcounter{secnumdepth}{1}
or
\setcounter{secnumdepth}{5}

Removing page numbers in TOC

Someone wanted more control over the table of contents. He wanted sub-sub-sections to appear but without any page number associated to them, i.e., not dotted line with the page number at the far right. This is trickier than the previous customization, because there is no mechanism provided to control this in LaTeX. So we need to modify the core function of the sectioning to perform this. We can find this macro by looking first at the table of contents file, i.e., the one with .toc extension.
In this file there are line like:
\contentsline {subsection}{\numberline {1.1}Test}{1}{section.1.1}

By searching the latex.ltx source file, we find that the \contentsline macro is defined as follows:
\def\contentsline#1{\csname l@#1\endcsname}

Meaning that it expands to a macro constructed using its first argument. In the example above, it would become \csname l@subsection, i.e., the control sequence \l@subsection.

In turn we find the definition of this macro in the article.cls class file:
\newcommand*\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}}

Which brings us to the final macro \@dottedtocline. This is the macro that displays the contents of one line of the TOC when you call \tableofcontents. Here is its definition (warning: unreadable code !):
\def\@dottedtocline#1#2#3#4#5{%
  \ifnum #1>\c@tocdepth \else
    \vskip \z@ \@plus.2\p@
    {\leftskip #2\relax \rightskip \@tocrmarg \parfillskip -\rightskip
     \parindent #2\relax\@afterindenttrue
     \interlinepenalty\@M
     \leavevmode
     \@tempdima #3\relax
     \advance\leftskip \@tempdima \null\nobreak\hskip -\leftskip
     {#4}\nobreak
     \leaders\hbox{$\m@th
        \mkern \@dotsep mu\hbox{.}\mkern \@dotsep
        mu$}\hfill
     \nobreak
     \hb@xt@\@pnumwidth{\hfil\normalfont \normalcolor #5}%
     \par}%
  \fi}

This macros is pretty horrible, but hopefully we don't have to understand all of it! In fact we are interested only in the part of it that displays the dotted line and the page number. This is the part where the \leaders macro is used, and the fifth parameter is the page number. Replacing this by a simple \hfill\kern0pt removes the "leaders" and page number for all sectioning commands (starting at sub-sections in the article class, as the \l@section macro and above use a different code).

To have control on the depth, we can create a new counter:
\newcounter{tocnopages}
\setcounter{tocnopages}{2} % display page number up to sub-sections

and then redefine the macros with a condition on this counter
(the \ifnum #1>\c@tocnopages... \else... \fi part):

\makeatletter
\def\@dottedtocline#1#2#3#4#5{%
  \ifnum #1>\c@tocdepth \else
    \vskip \z@ \@plus.2\p@
    {\leftskip #2\relax \rightskip \@tocrmarg \parfillskip -\rightskip
     \parindent #2\relax\@afterindenttrue
     \interlinepenalty\@M
     \leavevmode
     \@tempdima #3\relax
     \advance\leftskip \@tempdima \null\nobreak\hskip -\leftskip
     {#4}\nobreak
     \ifnum #1>\c@tocnopages \hfill \kern0pt \else
       \leaders\hbox{$\m@th
          \mkern \@dotsep mu\hbox{.}\mkern \@dotsep
          mu$}\hfill
       \nobreak
       \hb@xt@\@pnumwidth{\hfil\normalfont \normalcolor #5}%
     \fi
     \par}%
  \fi}
\makeatother


Removing numbering but only in the TOC

This question was asked on StackOverflow: How to display for instance "I am a subsection" in the TOC, but still having: "2.1 I am a subsection" in the body of the document. I answered directly on the StackOverflow website so go get a look at it if you want to know more. The idea is to redefine conditionally
the \numberline macro (see the \contentsline above) to something empty in the \@dottedtocline macro.

No comments:

Post a Comment