You are not logged in.

#1 2014-10-30 15:53:00

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,332
Website

[SOLVED] LaTex - custom TOC spacing depending on adjacent levels

I'm modifying the report.cls from texlive-core to fit some very particular formatting requirements.  The only bit left is to format the table of contents line spacing.  The contents should be double spaced except between any two entries of the same level (e.g. two chapters when there are no sections in the first of the two, or multiple sections when there are no subsections, etc).

Here is a minimal example:

\documentclass{report}

\makeatletter
\renewcommand*{\maketitle} {
	\renewcommand*{\baselinestretch}{2} \reset@font
	\@starttoc{toc}}
\makeatother

\begin{document}
\maketitle

\chapter{One}
	\section{Alhpa}
	\section{Bravo}
	\section{Charlie}
\chapter{Two}
	\section{Alhpa}
		\subsection{Sub 1}
		\subsection{Sub 2}
	\section{Bravo}
	\section{Charlie}
\chapter{Three}
\chapter{Four}
\chapter{Five}

\end{document}

This compiles to this pdf but I'd like it to look like this pdf

I created the second one by removing the baselinestretch command (to single space the toc) then manually editting the .toc file and adding a line like the following between any two lines that were not of the same depth:

\contentsline {section}{\hbox to \linewidth}{}

This works, but is a hassle, particularly because the .toc file is regenerated every time I rebuild and I have to again manually edit it.

Another approach would be to instead include those lines as needed in the document as follows:

\addtocontents{toc}{\hbox to \linewidth{~}}

This also works, but has two major downsides: it's easy to screw it up if sections are added or removed.  And second, it rather defeats the purpose of making a class file to handle the formatting.

I'm currently thinking about renewing the \@starttoc command.  The default \@starttoc essentially just includes the .toc file as-is.  I may be able to have the \@starttoc command read the .toc file line-by-line and insert extra lines where needed.  But if anyone has any better suggestions, or knows an easy way to do this, I'd appreciate any suggestions.

Last edited by Trilby (2014-10-31 00:59:09)


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

#2 2014-10-30 19:33:12

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,332
Website

Re: [SOLVED] LaTex - custom TOC spacing depending on adjacent levels

I've made a bit of very painful progress on this.  The following starttoc command will manually read the toc file and get the "depth" of each entry.  It was much harder than I first suspected to just define these two temporary variables \Cur and \Prev to store the current and previous toc depths - but that much worked.  But for some reason every conditional test I try to compare \Cur and \Prev fails.  Current revision, which when added to the above code outputs an additional line for each entry listing the previous and current depth levels.  This works, but I can't compare these two variables:

-- faulty code sample removed --

EDIT: nevermind, this was a major failure.  The apparent proper storing of the \Prev and \Cur vairables was an illusion.  The expandafter in setting Prev was actually printing it.  The variables are never set properly.

Last edited by Trilby (2014-10-31 01:00:21)


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

#3 2014-10-31 00:58:49

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,332
Website

Re: [SOLVED] LaTex - custom TOC spacing depending on adjacent levels

Got it!  I've learned more about LaTex today than I ever thought I would.  The most important lesson I learned is that it is great for document preparation, but sucks as a programming language.  The following addition to a preamble or class file will double space between different levels while keeping single spacing between 'siblings':

\makeatletter

\let\addcontentsline@original\addcontentsline
\renewcommand{\addcontentsline}[3]{
	\addtocontents{#1}{#2}{}
	\addcontentsline@original{#1}{#2}{#3}
}

\def\@starttoc#1{%
	\begingroup
	\newcount\linecnt
	\newcount\linecur
	\newcount\levelcur
	\newcount\levelnext
	\newread\myread
	\openin\myread=\jobname.#1
	\@whilesw\unless\ifeof\myread\fi{%
		\advance\linecnt by \@ne
		\read\myread t\expandafter o\csname line-\number\linecnt\endcsname
	}
	\closein\myread
	\advance\levelnext by \@ne
	\advance\levelnext by \@ne
	\@whilesw\ifnum\linecur<\linecnt\fi{%
		\advance\linecur by \@ne
		\advance\linecur by \@ne
		\advance\levelcur by \@ne
		\advance\levelnext by \@ne
		\def\Level{\csname line-\number\levelcur\endcsname}
		\def\LevelNext{\csname line-\number\levelnext\endcsname}
		\def\Line{\csname line-\number\linecur\endcsname}
		\Line
		\ifthenelse{\equal{\Level}{\LevelNext}}{}{\vspace{\baselineskip}}
		\advance\levelcur by \@ne
		\advance\levelnext by \@ne
	}
	\if@filesw
		\expandafter\newwrite\csname tf@#1\endcsname
		\immediate\openout \csname tf@#1\endcsname \jobname.#1\relax
	\fi
	\@nobreakfalse
	\endgroup
}

\makeatother

This works by modifying the default add to contents line to first save the depth indicator (chapter, section, subsection, etc) in a single line, then the actual entry in the next.  This is then read in in @starttoc - if the current and next levels don't match and extra baselineskip is added.

If there is a more elegant solution, I'd love to hear about it.  But this gets the job done.


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

Board footer

Powered by FluxBB