LaTeX Custom ToC

Over the last few weeks, I have been working on a python script that can convert an XML file generated by EasyChair to a Book of Abstracts used at conferences. One of the problems I faced was that I had to create a custom Table of Contents with the title of the submitted abstracts and their page number, and its authors below.

1 Abstracts
   This is an abstract ................... 1
   Author 1, Author 2, Author 3

Luckily, LaTeX allows for adding custom entries to the table of contents. So there is no need to mess around with adding the abstracts as real sections, and messing up the lay-out to keep them in a correct format. This is commonly done with \addcontentstoline{toc}{section}{title}. In-text example:

\chapter{Abstracts}
\newpage

\addcontentstoline{toc}{section}{This is an abstract}

\center{
  \large{\textbf{This is an abstract}}
  Author 1, Author 2, Author 3
}

After which we should see the following:

This is an abstract ................... 1

Now comes the tricky part, though, as adding the authors to the section title is obviously not something we would want. We cannot use the \addcontentstoline either, as that would result in the following:

This is an abstract ................... 1
Author 1, Author 2, Author 3 .......... 1

Yeah, not really aesthetically pleasing. We do not specifically have to add to a section though, as \addcontents{toc}{text} can be used to add the list of authors. Adding some spacing here and there would look something like:

%...

\addcontentstoline{toc}{section}{This is an abstract}
\addcontents{toc}{\protect\vspace{0.2em}}
\addcontents{toc}{Author 1, Author 2, Author 3}

\center{
  \large{\textbf{This is an abstract}}
  Author 1, Author 2, Author 3
}

This works, and looks pretty good already. There’s two assumptions we are making with this, though. We assume that the title does not continue on a second line, and the same goes for the list of authors. Well, surprise! In reality papers can have a department worth of authors and titles that try to capture exactly what’s in the abstract. We would hope that LaTeX handles this in automation, but no, unfortunately it does not. Instead, it spews out this masterpiece of indentation:

    This is an abstract with a very long title
        and continues here ..................... 1
    Author 1, Author 2, Author 3, Author 4, Author
5, Author 6, Author 7

Great, so the indentation of the title on the second line is acceptable, but in combination with the unindented author list, everyone is bound to weep at the sight of the abomination that is your Table of Contents. I decided to level everything to the same indentation. The approach to tackle this can be different, and probably a bit neater, but I came up with this: in the preamble we change the indentation of the sections that form our titles, as such:

% ...

\setlength{\cftsecnumwidth}{0pt}
\renewcommand{\cftsecaftersnumb}{\hspace{1.5em}}

%...

I guess it would be possible to do the same had we included our author list in a subsection, but for now I just went with an \hspace* for the author line, like so:

%...

\addcontentstoline{toc}{section}{This is an abstract}
\addcontents{toc}{\protect\vspace{0.2em}}
\addtocontents{toc}{Authors part I \newline}
\addtocontents{toc}{\hspace*{1.2em} Authors part II}
\addtocontents{toc}{\protect\vspace{1em}}

\center{
  \large{\textbf{This is an abstract}}
  Author 1, Author 2, Author 3
}

With this approach I had to split the list of author names with python once it became too long, making sure that the second part of the list was placed on a newline. As I was scripting the whole thing anyway, this was not really a problem. The code could for example be:


def format_toc(titl, name_l):
    """
    Accepts title and authors of the abstract, and will
    convert these into a formatted unicode LaTeX toc entry.
    :param titl: str unicode abstract title (no linebreaks)
    :param name_l: list str with authors
    :return: str unicode ToC entry for the abstract
    """
    if len(name_l) > 4:
    	name_l.insert('\\newline', 4)
   	parts = (', '.join(name_l)).split('\\newline')
   	newl = "\\newline" if len(parts) > 1 else ''
   	extl = ("\\addtocontents{toc}{\\hspace*{1.2em}" + \
   	       parts[1] + "}") if len(parts) > 1 else ''
   	toc = '''
   			\\addcontentsline{toc}{section}{\\emph{"%s"}}
   			\\addtocontents{toc}{\\protect\\vspace{0.2em}}
   			\\addtocontents{toc}{ %s \\hfill %s }
   			\\addtocontents{toc}{\\hspace*{1.2em}" %s "}
   			%s
   			\\addtocontents{toc}{\\protect\\vspace{1em}}
 		''' % (titl, parts[0], newl, extl)
    return titl

Note: I have edited the function a bit to a more final and ‘neater’ version in this post, as opposed to the much crappier version on github. It’s the result that counts, for now at least.