1

I'm trying to add a section* to the toc with addcontentsline. It's a macro as part of a larger group of commands I'm working on. What I want is to add the toc entry based on a section level counter. But using a macro to get the string for the current section level in addcontentsline causes an error I can't figure out. This is a minimal (not)working example of my problem (I'm using overleaf btw.)

\documentclass{article}
\usepackage[utf8]{inputenc}

\usepackage{xifthen} % If else commands

\makeatletter \newcounter{counter@section@level}

\newcommand{\currentSectionString}{ \ifthenelse{\equal{\value{counter@section@level}}{0}}{section}{} }

\makeatother

\begin{document}

\tableofcontents

\currentSectionString % to check the macro itself, works as expected

\section*{Foo} \addcontentsline{toc}{section}{Foo} % works as expected

\section*{Bar} \addcontentsline{toc}{\currentSectionString}{Bar} % does not work

\section{FooBar} % overlapping in toc

\end{document}

David Carlisle
  • 757,742

3 Answers3

2

\ifthenelse is not expandable. You need that argument to expand to section but

\addcontentsline{toc}{\currentSectionString}{Bar}

is like

\addcontentsline{toc}{\def\tmp{section}\tmp}{Bar}

which would not work for the same reason.

You could use an expandable test such as \ifcase

\addcontentsline{toc}{\ifcase\mycounter section\or subsection\else error\fi}{Bar}
David Carlisle
  • 757,742
1

My impression is that you want to automatically add starred sections to the TOC.

\documentclass{article}
\usepackage[utf8]{inputenc}

\NewCommandCopy{\latexsection}{\section} \NewCommandCopy{\latexsubsection}{\subsection}

\RenewDocumentCommand{\section}{sO{#3}m}{% \IfBooleanTF{#1}{% starred section \latexsection{#3}% \checkfortoc{#3}{\addcontentsline{toc}{section}{#3}}% }{% nonstarred section \latexsection[#2]{#3}% }% } \RenewDocumentCommand{\subsection}{sO{#3}m}{% \IfBooleanTF{#1}{% starred subsection \latexsubsection{#3}% \addcontentsline{toc}{subsection}{#3}% }{% nonstarred section \latexsubsection[#2]{#3}% }% } % do the same for the other sectional levels you need

\ExplSyntaxOn \NewDocumentCommand{\checkfortoc}{mm} { \str_if_eq:eeF { #1 } { \contentsname } { #2 } } \ExplSyntaxOff

\begin{document}

\tableofcontents

\section*{Foo}

\section*{Bar}

\section{FooBar}

\end{document}

An additional check is needed for \section, because \tableofcontents does \section*{\contentsname}, but the table of contents should not go in the table of contents.

egreg
  • 1,121,712
  • Thanks for your answer. I went with the other approach because it fits the rest of my code better. You are almost right. It's part of a relative sectioning I'm writing with key-value arguments. – Thorsten Schmitz Jun 27 '21 at 18:51
0

E.g., \addcontentsline{toc}{section}{Foo} beneath other things triggers that during the inputting of the .toc-file the macro \contentsline does
\csname l@section\endcsname\l@section.

Thus the second argument of \addcontentsline must consist of tokens which can be used between \csname..\endcsname, i.e., tokens whose expansion does not yield non-character-tokens.
\ifthenelse-stuff yields non-character-tokens and therefore can be used neither between \csname..\endcsname nor with macro-arguments that at some stage are inserted between \csname..\endcsname. Same for macros whose expansion at some stage yields \ifthenelse-stuff.

If you insist in sticking to \ifthenelse-stuff you need to change the order of processing to have \ifthenelse-stuff done before it comes to processing \addcontentsline—what about this? :

\documentclass{article}
\usepackage[utf8]{inputenc}

\usepackage{xifthen} % If else commands

\makeatletter \newcounter{counter@section@level}% % The optional argument of \DoWithCurrentSectionString denotes tokens that % process "{section}" as argument. \newcommand{\DoWithCurrentSectionString}[1][@firstofone]{% \ifthenelse{\equal{\value{counter@section@level}}{0}}{#1{section}}{% % \ifthenelse{\equal{\value{counter@section@level}}{1}}{#1{subsection}}{% % ... % }% }% }% \makeatother

\begin{document}

\tableofcontents

\noindent\hrulefill

\DoWithCurrentSectionString % to check the macro itself, works as expected

\kern\ht\strutbox\hrule\hfill

\section*{Foo} \addcontentsline{toc}{section}{Foo} % works as expected

\section*{Bar} \DoWithCurrentSectionString[{\addcontentsline{toc}}]{Bar} % does work

\section{FooBar} % overlapping in toc

\end{document}

enter image description here

the .aux-file:

\relax 
\@writefile{toc}{\contentsline {section}{Foo}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{Bar}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {1}FooBar}{1}{}\protected@file@percent }
\gdef \@abspage@last{1}

the .toc-file:

\contentsline {section}{Foo}{1}{}%
\contentsline {section}{Bar}{1}{}%
\contentsline {section}{\numberline {1}FooBar}{1}{}%


For the sake of having fun here is an expandable approach which does with delimited arguments instead of \if...-constructs:

\documentclass{article}
\usepackage[utf8]{inputenc}

\makeatletter \newcounter{counter@section@level} \newcommand{\currentSectionString}{% \expandafter\currentSectionStringSelect\expandafter{\number\value{counter@section@level}}% }% \newcommand\currentSectionStringSelect[1]{% \currentSectionStringFork #1!1!2!3!4!{section}% 0!#1!2!3!4!{subsection}% 0!1!#1!3!4!{subsubsection}% 0!1!2!#1!4!{paragraph}% 0!1!2!3!#1!{subparagraph}% 0!1!2!3!4!{subparagraph}% !!!!% }% @ifdefinable\currentSectionStringFork{% \long\def\currentSectionStringFork#10!1!2!3!4!#2#3!!!!{#2}% }% \makeatother

\begin{document}

\tableofcontents

\noindent\hrulefill

\currentSectionString % to check the macro itself, works as expected

\kern\ht\strutbox\hrule\hfill

\section*{Foo} \addcontentsline{toc}{section}{Foo} % works as expected

\section*{Bar} \addcontentsline{toc}{\currentSectionString}{Bar} % does work

\section{FooBar} % overlapping in toc

\end{document}

enter image description here

the .aux-file:

\relax 
\@writefile{toc}{\contentsline {section}{Foo}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{Bar}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {1}FooBar}{1}{}\protected@file@percent }
\gdef \@abspage@last{1}

the .toc-file:

\contentsline {section}{Foo}{1}{}%
\contentsline {section}{Bar}{1}{}%
\contentsline {section}{\numberline {1}FooBar}{1}{}%
Ulrich Diez
  • 28,770