8

When there is a succession of short sections, or chapter-to-section changes with no text in between, like in here,

\documentclass[10pt,a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage{lipsum}


\begin{document}
\tableofcontents

\chapter{Chapter 1}
\lipsum[1]
\section{Section 1}
\lipsum[2]
\section{Section 2}
\lipsum[3-5]
\section{Section 3}
\lipsum[6]
\section{Section 4}
\lipsum[7]

\end{document}

I end up having a toc that looks like this:

My question is, is it possible to tell the toc not to display anything unless the page number have changed ? In order to get something like:

enter image description here

Or alternatively, get the redundant page numbers in a shade of gray, like enter image description here

EDIT: All of the solutions work perfectly fine on their respective MWE, but not for my thesis. It will take me some time to find which package is responsible for this amoung the tens that are loaded. Heiko's solutions are the one producing the best results in my thesis, but I have the following problem on a new toc page:

The labels are back to normal, and this do not happen on the MWE.

  • 2
    I wouldn't do this. Imagine the poor reader if, for example, Section2 entry is on page 1 of the ToC but Section 3 entry is on page 2. He/She has to turn back the page to find out the page for Section3. – Gonzalo Medina Sep 8 '15 at 18:22
  • Good point. Another option is to colour redundant numbers in gray. I will edit the post to take this option into account. – HcN Sep 8 '15 at 18:24
  • 1
    The class and or packages, which influence the table of contents should be added to the MWE. – Heiko Oberdiek Sep 8 '15 at 20:56
  • @HeikoOberdiek Those which influences the toc are in already. I wrote a MWE with all the packages and all the same surrounding around the \tableofcontents entry, and yet I could not reproduce this error. I am certainly missing something, but it is unlikely that this error will reproduce in the actual thesis as these chapters should be rather long. – HcN Sep 9 '15 at 12:56
6

See ADDENDUM for hyperref version.

Here's a tocloft solution. I patch the definitions of \cftXfillnum so that #1 is replaced with \clrize{#1}. Then I define \clrize to check if #1 matches the globally defined previous page entry. If so, it makes it gray, otherwise, it leaves it black and updates the globally saved page entry.

EDITED to use \xpatchcmd instead of specifying a full \renewcommand.

\documentclass[10pt,a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage{tocloft,xcolor,xpatch}
\xpatchcmd\cftchapfillnum{#1}{\clrize{#1}}{}{}
\xpatchcmd\cftsecfillnum{#1}{\clrize{#1}}{}{}
\def\svpage{0}
\def\clrize#1{\ifnum#1=\svpage\relax\textcolor{black!20}{#1}\else#1\gdef\svpage{#1}\fi}
\usepackage{lipsum}
\begin{document}
\tableofcontents

\chapter{Chapter 1}
\lipsum[1]
\section{Section 1}
\lipsum[2]
\section{Section 2}
\lipsum[3-5]
\section{Section 3}
\lipsum[6]
\section{Section 4}
\lipsum[7]
\end{document}

enter image description here

ADDENDUM:

The OP asked about hyperref compatibility. After thrashing about a bit, I discovered that #1 to the \cftXfillnum macros was not a number, but instead a hyperref command of some sort. I therefore had to parse that command in order to extract the page number as argument #4 of that new command.

\documentclass[10pt,a4paper]{report}
\usepackage[linktoc=all]{hyperref}
\usepackage[utf8]{inputenc}
\usepackage{tocloft,xcolor,xpatch}
\usepackage{lipsum}
\xpatchcmd\cftchapfillnum{#1}{\clrize#1\relax#1}{}{}
\xpatchcmd\cftsecfillnum{#1}{\clrize#1\relax#1}{}{}
\def\svpage{0}
\def\clrize#1#2#3#4#5\relax{\ifnum#4=\svpage\relax%
  \color{black!30}\else\gdef\svpage{#4}\fi}
\begin{document}
\tableofcontents

\chapter{Chapter 1}
\lipsum[1]
\section{Section 1}
\lipsum[2]
\section{Section 2}
\lipsum[3-5]
\section{Section 3}
\lipsum[6]
\section{Section 4}
\lipsum[1-42]
\section{Section 5}
\lipsum[7]
\end{document}

enter image description here

  • Thanks a lot. Your solution do is elegant, but for some reason it is not happy cohabiting with \usepackage[linktoc=all]{hyperref}. Is there something that can be done ? – HcN Sep 8 '15 at 19:47
  • @HcN Please see addendum to my answer. – Steven B. Segletes Sep 8 '15 at 23:46
  • It works on the MWE, but it seems not to work anymore when they are parts or subsections e.g. if we add after \tableofcontents the code \part{Part} \chapter{Chapter 1}\lipsum[1] \section{Section 1} \subsection{Subsection 1} – HcN Sep 9 '15 at 15:02
  • @HcN You have to add a line like \xpatchcmd\cftXfillnum{#1}{\clrize#1\relax#1}{}{} for each sectioning unit you wish to support, where I have shown, in my MWE, X = chap and sec. You will need to add lines for part, subsec, subsubsec, para, etc., as needed. Looking at the tocloft package documentation might help. – Steven B. Segletes Sep 9 '15 at 15:12
  • Indeed, as simple as that. Thanks a lot indeed. – HcN Sep 9 '15 at 15:28
9

LaTeX uses \l@<section> for formatting an entry in the table of contents. The second argument is the page number. Thus, it can be defined as macro and compared in the next call.

The following example also works with hyperref.

Also only those \l@... commands should be redefined, that actually appear in the table of contents. Otherwise a page number, which would appear on a section level, which is not put into the table of contents, would not be visible for the next entry on the same page, that is in the table of contents.

\documentclass[10pt,a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage{lipsum}

\makeatletter
\def\toc@page{}

% Chapters should have a page number.
% \l@chapter is redefined to remember the page number
\let\saved@l@chapter\l@chapter
\renewcommand*{\l@chapter}[2]{%
  \def\toc@page{#2}%
  \saved@l@chapter{#1}{#2}%
}

\let\saved@l@section\l@section
\renewcommand*{\l@section}[2]{%
  \def\toc@new@page{#2}%
  \ifx\toc@new@page\toc@page
    \expandafter\@firstoftwo
  \else
    \def\toc@page{#2}%
    \expandafter\@secondoftwo
  \fi
  {%
    \saved@l@section{#1}{}%
  }{%
    \saved@l@section{#1}{#2}%
  }%
}

\let\saved@l@subsection\l@subsection
\renewcommand*{\l@subsection}[2]{%
  \def\toc@new@page{#2}%
  \ifx\toc@new@page\toc@page
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {%
    \saved@l@subsection{#1}{}%
  }{%
    \saved@l@subsection{#1}{#2}%
  }%
}
\makeatother


\begin{document}
\tableofcontents

\chapter{Chapter 1}
\lipsum[1]
\section{Section 1}
\lipsum[2]
\section{Section 2}
\lipsum[3-5]
\section{Section 3}
\subsection{Subsection A}
\lipsum[6]
\section{Section 4}
\lipsum[7]

\end{document}

Result

With gray page numbers

Making the page numbers gray instead, only requires a small modification:

\documentclass[10pt,a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage{lipsum}
\usepackage{color}
\definecolor{tocpagegray}{gray}{.5}

\makeatletter
\def\toc@page{}

% Chapters should have a page number.
% \l@chapter is redefined to remember the page number
\let\saved@l@chapter\l@chapter
\renewcommand*{\l@chapter}[2]{%
  \def\toc@page{#2}%
  \saved@l@chapter{#1}{#2}%
}

\let\saved@l@section\l@section
\renewcommand*{\l@section}[2]{%
  \def\toc@new@page{#2}%
  \ifx\toc@new@page\toc@page
    \expandafter\@firstoftwo
  \else
    \def\toc@page{#2}%
    \expandafter\@secondoftwo
  \fi
  {%
    \saved@l@section{#1}{\textcolor{tocpagegray}{#2}}%
  }{%
    \saved@l@section{#1}{#2}%
  }%
}

\let\saved@l@subsection\l@subsection
\renewcommand*{\l@subsection}[2]{%
  \def\toc@new@page{#2}%
  \ifx\toc@new@page\toc@page
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {%
    \saved@l@subsection{#1}{\textcolor{tocpagegray}{#2}}%
  }{%
    \saved@l@subsection{#1}{#2}%
  }%
}
\makeatother

\begin{document}
\tableofcontents

\chapter{Chapter 1}
\lipsum[1]
\section{Section 1}
\lipsum[2]
\section{Section 2}
\lipsum[3-5]
\section{Section 3}
\subsection{Subsection A}
\lipsum[6]
\section{Section 4}
\lipsum[7]

\end{document}

Result with gray page numbers

With gray page numbers and gray dots

\documentclass[10pt,a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage{lipsum}
\usepackage{color}
\definecolor{tocpagegray}{gray}{.5}

\makeatletter
\def\toc@page{}

% Chapters should have a page number.
% \l@chapter is redefined to remember the page number
\let\saved@l@chapter\l@chapter
\renewcommand*{\l@chapter}[2]{%
  \def\toc@page{#2}%
  \saved@l@chapter{#1}{#2}%
}

\let\saved@l@section\l@section
\renewcommand*{\l@section}[2]{%
  \def\toc@new@page{#2}%
  \ifx\toc@new@page\toc@page
    \expandafter\@firstoftwo
  \else
    \def\toc@page{#2}%
    \expandafter\@secondoftwo
  \fi
  {%
    \begingroup
      \let\leaders\toc@leaders@gray
      \saved@l@section{#1}{\textcolor{tocpagegray}{#2}}%
    \endgroup
  }{%
    \saved@l@section{#1}{#2}%
  }%
}

\let\saved@l@subsection\l@subsection
\renewcommand*{\l@subsection}[2]{%
  \def\toc@new@page{#2}%
  \ifx\toc@new@page\toc@page
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {%
    \begingroup
      \let\leaders\toc@leaders@gray
      \saved@l@subsection{#1}{\textcolor{tocpagegray}{#2}}%
     \endgroup
  }{%
    \saved@l@subsection{#1}{#2}%
  }%
}

\let\org@leaders\leaders
\newcommand*{\toc@leaders@gray}[2]{%
  \org@leaders\hbox{\textcolor{tocpagegray}{#2}}%
}
\makeatother

\begin{document}
\tableofcontents

\chapter{Chapter 1}
\lipsum[1]
\section{Section 1}
\lipsum[2]
\section{Section 2}
\lipsum[3-5]
\section{Section 3}
\subsection{Subsection A}
\lipsum[6]
\section{Section 4}
\lipsum[7]

\end{document}

Result with gray page numbers and dots

With removal of unnecessary dots

If the page number is omitted, then the dots leading to the non-existent page number are no longer necessary. The following example removes them. Package hyperref is loaded this time.

\documentclass[10pt,a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage{lipsum}
\usepackage{etoolbox}
\usepackage[colorlinks]{hyperref}

\makeatletter
\def\toc@page{}

% Chapters should have a page number.
% \l@chapter is redefined to remember the page number
\let\saved@l@chapter\l@chapter
\renewcommand*{\l@chapter}[2]{%
  \def\toc@page{#2}%
  \saved@l@chapter{#1}{#2}%
}

\let\saved@l@section\l@section
\renewcommand*{\l@section}[2]{%
  \def\toc@new@page{#2}%
  \ifx\toc@new@page\toc@page
    \expandafter\@firstoftwo
  \else
    \def\toc@page{#2}%
    \expandafter\@secondoftwo
  \fi
  {%
    \begingroup
      \let\leaders\@gobbletwo
      \saved@l@section{#1}{}%
    \endgroup
  }{%
    \saved@l@section{#1}{#2}%
  }%
}

\let\saved@l@subsection\l@subsection
\renewcommand*{\l@subsection}[2]{%
  \def\toc@new@page{#2}%
  \ifx\toc@new@page\toc@page
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {%
    \begingroup
      \let\leaders\@gobbletwo
      \saved@l@subsection{#1}{}%
    \endgroup
  }{%
    \saved@l@subsection{#1}{#2}%
  }%
}
\makeatother

\begin{document}
\tableofcontents

\chapter{Chapter 1}
\lipsum[1]
\section{Section 1}
\lipsum[2]
\section{Section 2}
\lipsum[3-5]
\section{Section 3}
\subsection{Subsection A}
\lipsum[6]
\section{Section 4}
\lipsum[7]

\end{document}

Result without unnecessary dots

With unnecessary dots and with page numbers at new pages

The following modification sets labels to detect the page, where the entry of the table of contents is located. Then it checks, if the page number has changed, which indicates a new page in the table of contents. Then the page number is set, even if the page number already appears on the previous page.

\documentclass[10pt,a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage{lipsum}
\usepackage{etoolbox}
\usepackage[colorlinks]{hyperref}

\usepackage{zref-abspage}

\makeatletter
\def\toc@page{}
\def\toc@abspage{}
\newcounter{toc@abspage}
\renewcommand*{\thetoc@abspage}{%
  ta@\the\value{toc@abspage}%
}
\newcommand*{\toc@abspage@label}{%
  \zref@labelbyprops{\thetoc@abspage}{abspage}%
}
\newcommand*{\toc@abspage@check}{%
  \stepcounter{toc@abspage}%
  \edef\toc@abs@page{\zref@extractdefault{\thetoc@abspage}{abspage}{}}%
  \zref@refused{\thetoc@abspage}%
  \ifx\toc@abs@page\toc@abspage
  \else
    \def\toc@page{}%
    \let\toc@abspage\toc@abs@page
  \fi
}

% Chapters should have a page number.
% \l@chapter is redefined to remember the page number
\let\saved@l@chapter\l@chapter
\renewcommand*{\l@chapter}[2]{%
  \toc@abspage@check
  \def\toc@page{#2}%
  \saved@l@chapter{#1}{#2\toc@abspage@label}%
}

\let\saved@l@section\l@section
\renewcommand*{\l@section}[2]{%
  \toc@abspage@check
  \def\toc@new@page{#2}%
  \ifx\toc@new@page\toc@page
    \expandafter\@firstoftwo
  \else
    \def\toc@page{#2}%
    \expandafter\@secondoftwo
  \fi
  {%
    \begingroup
      \let\leaders\@gobbletwo
      \saved@l@section{#1}{\toc@abspage@label}%
    \endgroup
  }{%
    \saved@l@section{#1}{#2\toc@abspage@label}%
  }%
}

\let\saved@l@subsection\l@subsection
\renewcommand*{\l@subsection}[2]{%
  \toc@abspage@check
  \def\toc@new@page{#2}%
  \ifx\toc@new@page\toc@page
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {%
    \begingroup
      \let\leaders\@gobbletwo
      \saved@l@subsection{#1}{\toc@abspage@label}%
    \endgroup
  }{%
    \saved@l@subsection{#1}{#2\toc@abspage@label}%
  }%
}
\makeatother

\begin{document}
\tableofcontents

\chapter{Chapter 1}
\lipsum[1]
\section{Section 1}
\lipsum[2]
\addtocontents{toc}{\protect\newpage}
\section{Section 2}
\lipsum[3-5]
\section{Section 3}
\subsection{Subsection A}
\lipsum[6]
\section{Section 4}
\lipsum[7]

\end{document}
  • 1
    Many thanks (again). It works perfectly, but as suggested, the toc does not look great and is fairly misleading. Is there a way to modify your code to colour redundant page numbers in gray ? (See the edited question). – HcN Sep 8 '15 at 18:32
  • @HcN The version without dots would be an alternative. – Heiko Oberdiek Sep 8 '15 at 18:52
  • Your code seems the one that gives the best results on my thesis, although I still have a tiny problem on a new page - maybe a subsection thing. (I did edit the post) – HcN Sep 8 '15 at 20:37
5

You can try this:

\documentclass[10pt,a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage{lipsum}

\newcount\tocpgnum
\let\contentslineori=\contentsline
\def\contentsline#1#2#3{%
   \ifnum\tocpgnum=#3
      \contentslineori{#1}{#2}{}%
   \else
      \contentslineori{#1}{#2}{#3}%
      \tocpgnum=#3
   \fi
}

\begin{document}
\tableofcontents

\chapter{Chapter 1}
\lipsum[1]
\section{Section 1}
\lipsum[2]
\section{Section 2}
\lipsum[3-5]
\section{Section 3}
\lipsum[6]
\section{Section 4}
\lipsum[7]

\end{document}
  • A LaTeX answer? This is new! (at least for me). I up-vote your plain answers, bu this one I won't. (Just kidding). – Gonzalo Medina Sep 8 '15 at 18:41
  • 2
    Add after \lipsum[7]: \newpage\subsubsection{foo}\section{foo}. The subsubsection "foo" would get the visible page number "4", but it is not included in the table of contents. The next section on the same page does not know this and removes the page number, because it thinks, the page is already printed in the previous entry. – Heiko Oberdiek Sep 8 '15 at 18:50
1

Here is to show how to handle this with package etoc.

For simplicity I have used the technique from the etoc manual section another compatibility mode; else one would need to set up more complete styles (for the case of gray leader dots one can do it as here copying the \toc@leaders@gray method from Heiko's answer). Example of setting up etoc styles are given in the manual, for example, Part I, section 6 A second example.

\documentclass[10pt,a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage{lipsum}
\usepackage{hyperref}
\hypersetup{linktoc=all}
\usepackage{etoc}
\usepackage{color}
\definecolor{tocpagegray}{gray}{.5}

\makeatletter

\let\savedchapterline\l@chapter
\let\savedsectionline\l@section
\let\savedsubsectionline\l@subsection

\def\saved@previouspage {0}

\etocsetstyle{chapter}
  {}
  {\xdef\HcN@zz{\etocthepage}}
  {\ifx\HcN@zz\saved@previouspage
    \savedchapterline{\numberline{\etocnumber}\etocname}
                     {\textcolor{tocpagegray}{\etocpage}}%
   \else
    \savedchapterline{\numberline{\etocnumber}\etocname}
                     {\etocpage}%
   \fi
   \global\let\saved@previouspage\HcN@zz
  }
  {}%

\etocsetstyle{section}
  {}
  {\xdef\HcN@zz{\etocthepage}}
  {\ifx\HcN@zz\saved@previouspage
    \savedsectionline{\numberline{\etocnumber}\etocname}
                     {\textcolor{tocpagegray}{\etocpage}}%
   \else
    \savedsectionline{\numberline{\etocnumber}\etocname}
                     {\etocpage}%
   \fi
   \global\let\saved@previouspage\HcN@zz
  }
  {}%

\etocsetstyle{subsection}
  {}
  {\xdef\HcN@zz{\etocthepage}}
  {\ifx\HcN@zz\saved@previouspage
    \savedsubsectionline{\numberline{\etocnumber}\etocname}
                     {\textcolor{tocpagegray}{\etocpage}}%
   \else
    \savedsubsectionline{\numberline{\etocnumber}\etocname}
                     {\etocpage}%
   \fi
   \global\let\saved@previouspage\HcN@zz
  }
  {}

\makeatother


\begin{document}
\tableofcontents

\chapter{Chapter 1}
\lipsum[1]
\section{Section 1}
\lipsum[2]
\section{Section 2}
\lipsum[3-5]
\section{Section 3}
\subsection{Subsection A}
\lipsum[6]
\section{Section 4}
\lipsum[7]

\end{document}

enter image description here

  • Works great, thanks ! It has the side effect to increase the gap around the "part" entries in the toc. Is it related to etoc ? – HcN Sep 9 '15 at 12:53
  • can you try with the addition of \etocsetstyle{part}{}{}{\savedpartline{\etocnumber\hspace{1em}\etocname}{\etocpage}}{}, after having done \let\savedpartline\l@part, all of that in the preamble code between \makeatletter and \makeatother (assuming you are using book or article class). – user4686 Sep 9 '15 at 13:11
  • and yes the increased gap is probably related to etoc in such a case because the style used for Parts is the custom one of etoc, not the default provided by the document class. My previous comment shows how to reproduce this default. And actually that bit of code should be extended to look like the chapter, section, subsection settings in my code with the \ifx.. conditional, etc... – user4686 Sep 9 '15 at 13:15
  • Miktek returns '! Undefined control sequence. <argument> \etocp ‌​age' once the toc is compiled. The gap is indeed reduced, but the it displays the word "age" in place of the page number. Using either the book or article class does not help. – HcN Sep 9 '15 at 15:10
  • @HcN it appears you have a spurious space, yes I also get such an extra space from copying pasting the code in my comment above; after pasting (perhaps in some good text editor) make sure to suppress the space after the p letter. It should be \etocpage not \etocp age. – user4686 Sep 9 '15 at 16:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.