Is there a way to get table of contents I can click on?
I'm looking for something like Table of Contents module in Jupyter notebooks where I can jump between sections easily, here's what my scratch-space usually looks like
AFAIK there's nothing built-in.
On the other hand I use this sort-of functionality all the time. Here's a quick way to generate a table of contents palette:
nbTOC[nb_] :=
Button[
Mouseover[#, Style[#, "HyperlinkActive"]] &@First@NotebookRead@#,
SelectionMove[#, All, CellContents],
Appearance -> None,
BaseStyle -> "Hyperlink",
Alignment -> Left,
ImageSize -> 100
] & /@
Cells[CellStyle -> {"Title", "Chapter", "Section", "Subsection",
"Subsubsection"}] // CreatePalette[
Panel[
Column[#,
Dividers -> Center],
ImageSize -> 100
],
FrontEnd`ClosingSaveDialog -> False,
WindowTitle -> "Table of Contents",
Magnification -> 1.5
] &;
nbTOC[Optional[Automatic, Automatic]] :=
nbTOC@EvaluationNotebook[]
It assumes you just want to navigate to the "Title"
, "Chapter"
, "Section"
,etc. cells and that the CellObject
available at the time the palette was generated will still exist.
The other way I've done this is, at click time, searched for a cell with the same contents and style as the original cell in the notebook. That way it'll work even after the notebook has been closed and reopened.
{"Title", "Chapter", "Section", "Subsection", "Subsubsection"}
for the cell styles you actually have
$\endgroup$
I made a nbTOC based on b3m2a1's nbTOC to make it more ready to use. Improvements are listed below:
Here is the function:
ClearAll[openSelectedCellGroup];
openSelectedCellGroup[nb_NotebookObject]:=Module[{},
If[CurrentValue[First@Cells[NotebookSelection[nb]],"CellGroupOpen"]===Closed,
FrontEndTokenExecute[nb,"OpenCloseGroup"]]];
ClearAll[nbTOC];
Options[nbTOC]={
"width"->250,
"indentUnit"->10,
"fontSizeList"->{16,14,12,12,10,10},
"colorList"->{Darker@Red,Darker@Blue,Darker@Darker@Green,Darker@Orange,Black,Darker@Magenta},
"fontWeightList"->{Bold,Bold,Bold,Bold,Bold,Bold}};
nbTOC[notebookObj_NotebookObject,opts:OptionsPattern[]]:=Module[
{defaultCellStyleList,cellList,cellInfoList,currentCellStyleList,
width,indentUnit,fontSizeList,colorList,fontWeightList,
cellStyleAssocFormatStyle,cellStyleAssocButtonImageMargin,buttonList,
cellName,buttonImageMargin,tocNotebookObj,createNewTOCwindows},
width=OptionValue["width"];
indentUnit=OptionValue["indentUnit"];
fontSizeList=OptionValue["fontSizeList"];
colorList=OptionValue["colorList"];
fontWeightList=OptionValue["fontWeightList"];
defaultCellStyleList={"Title","Subtitle","Chapter","Section","Subsection","Subsubsection"};
cellList=Cells[notebookObj,CellStyle->defaultCellStyleList];
cellInfoList=List@@@(NotebookRead/@cellList)[[;;,1;;2]];
currentCellStyleList=DeleteDuplicates@cellInfoList[[;;,-1]];
currentCellStyleList=Cases[defaultCellStyleList,Alternatives@@currentCellStyleList];
cellStyleAssocFormatStyle=Association@Table[
currentCellStyleList[[i]]->With[{i=i},Style[#,fontSizeList[[i]],fontWeightList[[i]],colorList[[i]]]&],
{i,1,Length@currentCellStyleList}];
cellStyleAssocButtonImageMargin=Association@Table[
currentCellStyleList[[i]]->indentUnit*(i-1),
{i,1,Length@currentCellStyleList}];
buttonList=Table[
cellName=Row[{"",(Last[cellInfoList[[i]]]/.cellStyleAssocFormatStyle)[First@cellInfoList[[i]]]}];
(*For unknown reason, Row[{"",xxx}] will make TOC more compact*)
buttonImageMargin=Last[cellInfoList[[i]]]/.cellStyleAssocButtonImageMargin;
With[{cell=cellList[[i]]},
Button[
cellName,
Do[
SelectionMove[cell,All,CellGroup,k];
openSelectedCellGroup[notebookObj]
,{k,1,6}];(*There are at most 6 level of TOC. Open them all from bottom to top*)
SelectionMove[cell,All,CellGroup];
If[Length@Cells[NotebookSelection[notebookObj],CellStyle->{"Title","Subtitle","Chapter","Section","Subsection","Subsubsection"}]==1,
(*If there are no more sections below, then open all sub cell groups, this will open all Out cells*)
FrontEndTokenExecute["SelectionOpenAllGroups"],
(*If there are more sections below, then only open one level further*)
openSelectedCellGroup[notebookObj]];
(*moving back to cell title*)
SelectionMove[cell,All,CellContents]
,
Appearance->None,BaseStyle->"Hyperlink",Alignment->Left,
FrameMargins->{{buttonImageMargin, 0}, {0, 0}},
ImageSize->width]],
{i,1,Length@cellList}];
createNewTOCwindows[]:=Module[{},NotebookClose[tocNotebookObj];nbTOC[notebookObj]];
PrependTo[buttonList,
Button[Style["Click to update",White,Bold,15],createNewTOCwindows[],Background->Black]];
tocNotebookObj=CreatePalette[Column[buttonList,Dividers->Center],FrontEnd`ClosingSaveDialog->False,
WindowMargins->{{Automatic,-5},{Automatic,0}},WindowElements->{"VerticalScrollBar"},WindowTitle->"TOC",Magnification->0.85];
(*SetOptions[EvaluationNotebook[],WindowSize\[Rule]{1047,Automatic},WindowMargins\[Rule]{{0,0},{0,0}}]*)];
nbTOC[opts:OptionsPattern[]]:=nbTOC[EvaluationNotebook[],opts];
Note that I deliberately make non-fixed font style for each level. So if the notebook only contains Section, Subsection, Subsubsection. We will have red biggest font for Section and so on like this
You can create tables of contents programmatically BUT there are a few large problems:
the tables are only somewhat “live”. In particular when you change the type of a subsection (eg change from cmd-3 to cmd-4 formatting) it’s hit or miss whether the live ToC will update to show this.
more serious is that constructing the ToC becomes something that you need to mark as an initialization cell, and so every time you open your document there’s some friction because you have to force initialization cells to execute before you can do what you want to do. I have been surprised at how much friction this induces.
the most obvious ways to construct a ToC (ie the sort of code you will find on the internet) mean that the ToC is a shared construct (single name) when you duplicate a document. This can become very messy if you want to have two versions of the document open simultaneously, eg to compare the current version with an older version.
More generally, I don’t know how Wolfram and the Mathematica employees do it! While writing in MMA is very productive in many ways (I much prefer it to, eg, LyX) it’s just HORRIBLE for large documents. Lack of live ToC is one problem, diff’s between versions is another problem, no version control (eg no easily managed connection to git, like XCode has) is a third problem. Yes, you can (and probably should) write in MMA compared to the alternatives, but the fact that it’s better than everything else, doesn’t mean it’s great; it means that everything else is even worse…
AuthorTools`
package has some stuff that might be able to fit your needs. Both of these would require some work though. $\endgroup$