This is my oldest question on SO. It still hasn't generated a useful answer there, so I thought I'd give it a try here.

The question was: I don't seem to be able to find the method to generate the table of contents for a Mathematica notebook. AuthorTools, an old v5.1 utility package is still hidden in Mathematica, but it doesn't work for me. The TOC should contain correct section numbers (if present in the stylesheet) and list page numbers (this requires taking page size settings into account).

-
 What exactly do you mean by "page number"? since notebooks do not have pages? do they? Or is this for print purpose only? How is one going to know the page number since the final print size depends on the paper size and final formatting for printout? for my Mathematica cheat sheet, I build table of content 'by hand'. i.e. I use cell tags, and then add an HTML link at the top to an internal tag, which is the cell tag. The cell tage I add at the start of each section I want to put in the table of content. But no page numbers, as this is only for HTML generation purposes and not for print. – Nasser Jan 22 '12 at 12:41 ...if you like, I can write down the steps and example, but I have a feeling you are looking for an automated way, and I do not know of an automated way. I add each entry in the TOC manually each time by inserting internal links.... – Nasser Jan 22 '12 at 12:46 @Nasser This is for printing purposes (and making PDF's). So I want the TOC to be interpreted in terms of the page settings in File>Printing settings>Page Setup. Mathematica is aware of the page breaks because you can have them shown using the option File>Printing settings>Show page breaks. And indeed, I'm looking for an automatic method. It used to be possible, and it looks like all MMA books written in MMA have there TOC made up with MMA. So, how do they do it? – Sjoerd C. de Vries Jan 22 '12 at 12:49 Ok, I hope you find a solution for this, because I need something like also very badly. As I said, I add each TOC entry by hand for my Mathematica cheat sheet notebook, and it is no fun having to do it each time. If I move things, I have to update the links by hand. Here is a link to generated HTML so you can see how it looks like. 12000.org/my_notes/faq/mma_notes/MMA.htm – Nasser Jan 22 '12 at 12:56 I was going to ask this as well. I also want to know how to generate a list of all the functions used in a notebook, to check coverage of topics for a chapter, for example. – cormullion Jan 22 '12 at 16:46

A bit of warning from the OP: this code locked-up my Mathematica session, so be sure to save everything before you try this. Update: Problem seems to be related to a problem MMA has with paginating a particular notebook of mine (see comments).

This code creates a separate TOC for a notebook saved at the location bookUrl. It works by iterating over all the cells in the book. If a cell is encountered whose type is in typeList, a tag is added to the cell and a line is written to the TOC notebook. We use CounterBox["Page", {bookUrl, tag}] to print the appropriate page number.

Note that due to the nature of CounterBox, the page numbers are only shown in the TOC is the notebook of the book is open and ShowPageBreaks -> True is set, but you should be able to print the TOC to a pdf.

createToc[bookUrl_, typeList_] :=
Module[{toc, book, createCell, counter, cell, type, tag},

(*create TOC file and open book*)
toc = CreateDocument[];
book = NotebookOpen[bookUrl];
SetOptions[book, ShowPageBreaks -> True];

(* helper file for creating cell *)
createCell[text_, tag_, level_] := Cell[BoxData[
TagBox[GridBox[{{"", text, CounterBox["Page", {bookUrl, tag}]}},
GridBoxAlignment -> {"Columns" -> {Left, Left, Right}},
GridBoxItemSize -> {"Columns" -> {2 level - 1, 35 - 2 level, 5}}],
"Grid"]], "Text"];

(* iterate over cells to set tags and write lines to TOC *)
Scan[(counter[#] = 0) &, typeList];
SelectionMove[book, Before, Notebook];
SelectionMove[book, Next, Cell];
If[Length[cell] >= 2,
type = cell[[2]];
If[MemberQ[typeList, type],
counter[type] += 1;
tag = type <> ToString[counter[type]];
SetOptions[NotebookSelection[book],
CellTags -> Union[Flatten[{Options[NotebookSelection[book],
CellTags][[1, 2]], tag}]]];
SelectionMove[book, All, CellContents];
NotebookWrite[toc,
Position[typeList, type][[1, 1]]]]];
SelectionMove[book, Next, Cell]]];
SetSelectedNotebook[toc]];


To see the code in action, lets create a very simple document with 2 sections and 3 subsections on 3 pages

book = CreateDocument[];
NotebookWrite[book, Cell["This is section 1", "Section"]];
NotebookWrite[book, Cell["This is a subsection", "Subsection"]];
NotebookWrite[book, Cell["This is some text", "Text"]];
NotebookWrite[book,
Cell["Another section which begins on a new page", "Section",
PageBreakAbove -> True]];
NotebookWrite[book,
Cell["Subsection 2.1", "Subsection", PageBreakBelow -> True]];
NotebookWrite[book, Cell["Subsection 2.2", "Subsection"]];
bookUrl = ExpandFileName["book1.nb"];
NotebookSave[book, bookUrl];


Then createToc[bookUrl, {"Section", "Subsection"}] creates something like this

-
 It looks very promising but it just locked-up my Mathematica session, so I'm going to insert a warning above first. – Sjoerd C. de Vries Jan 22 '12 at 21:15 @SjoerdC.deVries I'm sorry about that. I've only tried it on small examples but for those it seems to work fine on my machine. – Heike Jan 22 '12 at 21:25 Did some further testing. It's probably not the code itself that is the problem. It seems that setting the pagebreak option (SetOptions[book, ShowPageBreaks -> True]) is a problem for this particular file. Same lock-up happens when you do it manually, with File>Printing settings. It never finishes repagination. I made it under MMA7, using a tweaked Article/JournalArticle style file (mostly counter boxes for section numbering). – Sjoerd C. de Vries Jan 22 '12 at 21:35 I put a minimal version of the problem notebook at dl.dropbox.com/u/3675222/test6.nb. Please don't forget to save your other stuff before you try this. – Sjoerd C. de Vries Jan 22 '12 at 23:29 Maybe we should petition to have something like this done more simply. All this code just to generate a TOC? Surely there should be an easier way. – Eric Jan 28 '12 at 4:36
show 1 more comment