# How can I embed \tablecontents within another macro and make it create a .toc file on first run?

I wrote a wrapper for \tableofcontents \listoftables \listoffigures that determine whether or not to add those lists based on the number of occurences of each type. In other words, I added a quantitative dependency.

The problem is that embedding \tableofcontents in another macro postpones writing the .toc .lot .lof files. I am already pushing 3 runs and I do not want another run. I want to have my cake and eat it too.

# Non-embedded First Output Files

toc.aux
toc.log
toc.pdf
toc.toc


# Embedded First Run Output Files

Note that embedding a \tableofcontents macro in another macro does not create a \jobname.toc file after the first run.

toc.aux
toc.log
toc.pdf


# Problematic Code

\documentclass{article}
\usepackage{fontspec}
\usepackage{xparse}% for \NewDocumentCommand
\usepackage{atveryend}% to add stuff to end of aux reliably

\newcounter{runningsectioncounter}
\setcounter{runningsectioncounter}{0}

% Inject count stepper into section
\makeatletter
{-3.5ex \@plus -1ex \@minus -.2ex}%
{2.3ex \@plus.2ex}%
{\normalfont\Large\bfseries}}

% Contents Logic
\NewDocumentCommand\mycontents{}{%
\ifnum 3<0\csname totalsectioncount\endcsname\relax\tableofcontents\newpage\fi
\newpage
}%

% Write totals to aux after \end{document}
\AfterLastShipout{%
\immediate\write\@mainaux{%
\string\gdef\string\totalsectioncount{\the\c@runningsectioncounter}
}%
}%
\makeatother

\begin{document}
\mycontents{}% <== embedded
%\tableofcontents{}% <== non-embedded

% TeX loop to generate sections for fun
\newcount\step
\step=0
\loop
\section{Section (ID: \the\step)}
\ifnum \step < 5\relax
\repeat

\end{document}


# My Second Attempt

Works, actually.

\documentclass{article}
\usepackage{fontspec}

\makeatletter
% Contents Logic
\protected@edef\mycontents{%
\tableofcontents
\newpage
}%
\makeatother

\begin{document}
\mycontents{}% <== embedded
%\tableofcontents{}% <== non-embedded

% TeX loop to generate sections for fun
\newcount\step
\step=0
\loop
\section{Section (ID: \the\step)}
\ifnum \step < 5\relax
\repeat

\end{document}

• This won't work unless you use \makeatletter and \makeatother around your definition… – Lupino Nov 20 '17 at 12:05
• @Lupino Correction noted and added. Thanks. – Jonathan Komar Nov 20 '17 at 12:08
• edef shouldn't work here since it likes to expand \tableofcontents whilst it is still in the preamble (it will throw a "Missing \begin{document}" error.) Also, I cant reproduce your problem. Both LuaLaTeX and xelatex seem to work for me (using def instead of \NewDocumentCommand and with out the additional pair of braces after the macro name in the definition). Could you give us a hint on what version of tex you are using? – Lupino Nov 20 '17 at 12:12

If I understand correctly, you want the TOC to be created only if at least 4 sections.

There are two problems:

• (moved from comment) the .toc file gets created only if \tableofcontents is executed. On first compilation you are not executing \tableofcontents, hence you end up needing three runs. Remark \usepackage{etoc}, \etocnotocifnotoc in your preamble replacing your code, and normal use of \tableofcontents will print the TOC in only 2 runs, if present. But alas etoc does not hook into LOF and LOT.

• your patch of \section affects \tableofcontents too as it uses it so your counter is stepped by 1 from its usage.

Here is possibly what you need, keeping with the already in place logic

\documentclass{article}
%\usepackage{fontspec}
\usepackage{xparse}% for \NewDocumentCommand
\usepackage{atveryend}% to add stuff to end of aux reliably

%\usepackage{etoc}
%\etocnotocifnotoc

\newcounter{runningsectioncounter}
\setcounter{runningsectioncounter}{0}

% Inject count stepper into section
\makeatletter
\@startsection {section}{1}{\z@}%
{-3.5ex \@plus -1ex \@minus -.2ex}%
{2.3ex \@plus.2ex}%
{\normalfont\Large\bfseries}}

% Contents Logic
\NewDocumentCommand\mycontents{}{%
\ifnum 3<0\csname totalsectioncount\endcsname\relax
\tableofcontents
\else
\newwrite\tf@toc
\immediate\openout\tf@toc=\jobname.toc\relax
\fi
\newpage
}%

% Write totals to aux after \end{document}
\AfterLastShipout{%
\immediate\write\@mainaux{%
\string\gdef\string\totalsectioncount{\the\c@runningsectioncounter}
}%
}%
\makeatother

\begin{document}
\mycontents

% TeX loop to generate sections for fun
\newcount\step
\step=0
\loop
\section{Section (ID: \the\step)}
\ifnum \step < 5\relax
\repeat

\end{document}


With 3 sections or less, no TOC gets printed. With more, TOC gets printed completely after two runs.

I'm having problems to recreate your outcome. Both xelatex and lualatex produce the output you seek. That is, if you omit the second pair of braces after your macro name:

\documentclass{article}
\usepackage{fontspec}

% Contents Logic
\def\mycontents{%
\tableofcontents
\newpage
}%
...

• I am using xelatex. The extra {} were do to my original xparse definition and I forgot to remove them. However, removing them does not solve the problem. The output I seek, to be clear, is a \jobname.toc file after the first run. You are right, there is no problem. My problem was a misunderstanding of the order of things. jfbu was right all along. The problem lies within a conditional that I have since removed from the question, because I failed to see the relevance. I will fix repair my question, but jfbu identified the issue. – Jonathan Komar Nov 20 '17 at 12:25

I tried \protected@edef to fully expand the contents of the macro \mycontents, which I had hoped would also call \tableofcontents.

This accidentally worked. It has nothing to do with \protected@edef. It has everything to do with the fact that I also removed the section count conditional.

# Explanation

Why does my conditional not yield TRUE after the first run? This has to do with the fact that TeX is linear. At the time \mycontents is called, the counter runningsectioncounter is still set to 0. This means that \tableofcontents would not be called and a \jobname.toc file is not created. Silly mistake.