3

I am basically trying to patch \part of scrreprt to do something with the optional argument (if present) or the mandatory argument instead. In the example below the short caption would be added in red to the TOC and the long caption in blue (underneath its respective part).

But my code below basically doesn't do anything. This seems very related to this problem, and I have tried something similar with regexpatch, but without success. I am trying to get to a solution where \part can be used by other packages, e.g. hyperref without interference.

\documentclass{scrreprt}

\usepackage{xcolor}
\usepackage{xpatch}

\makeatletter

\catcode`\#=12

\xapptocmd{\@part}%
    {#1}%
    {\addcontentsline{toc}{chapter}{\textcolor{red}{#1}}}%  
    {}%

\xapptocmd{\@part}%
    {#2}%
    {\addcontentsline{toc}{chapter}{\textcolor{blue}{#2}}}% 
    {}%

\catcode`\#=6

\makeatother

\begin{document}

\tableofcontents

\part{Only Long Caption}

\part[Short Caption]{Long Caption}

\end{document}
  • You've got things mixed up somewhat, obviously. What do you want to happen with the content already written to the ToC? You still want that written, or not? – Werner Nov 13 '14 at 22:33
  • Yes, still written. I want to use the short and long caption in addition to their normal behaviour. (and yes, I got things mixed up :-) ) – Jörg Nov 13 '14 at 22:34
  • Your first instruction says: “Add #1 at the end of \@part and execute \addcontentsline... if the patch succeeds”. I guess you want \xpatchcmd instead. – egreg Nov 13 '14 at 22:41
  • I've tried many things, something like \xpatchcmd{\@part}{##1}{\addcontentsline{toc}{chapter}{\textcolor{red}{##1}}}{}, but clearly I am not quite understanding it – Jörg Nov 13 '14 at 22:41
  • @cfr Every macro is defined with \def (and \edef is \def under cover). – egreg Nov 13 '14 at 22:54
6

In order for the patching to work as expected, you need to understand how the function you're patching is constructed. Here is \@part as it's defined in scrreprt.cls:

\def\@part[#1]#2{%
  \ifnum \scr@osectarg=\z@
    \@scr@tempswafalse
  \else
    \scr@istest#1=\@nil
  \fi
  \if@scr@tempswa
    \setkeys{KOMAarg.section}{tocentry={#2},head={#2},#1}%
  \else
    \ifcase \scr@osectarg\relax
      \setkeys{KOMAarg.section}{tocentry={#1},head={#1}}%
    \or
      \setkeys{KOMAarg.section}{tocentry={#2},head={#1}}%
    \or
      \setkeys{KOMAarg.section}{tocentry={#1},head={#2}}%
    \or
      \setkeys{KOMAarg.section}{tocentry={#1},head={#1}}%
    \fi
  \fi
  \ifnumbered{part}{%
    \refstepcounter{part}%
    \@maybeautodot\thepart%
    \ifx\scr@ds@tocentry\@empty\else
      \addparttocentry{\thepart}{\scr@ds@tocentry}%
    \fi
  }{%
    \ifx\scr@ds@tocentry\@empty\else
      \addparttocentry{}{\scr@ds@tocentry}%
    \fi
  }%
  \begingroup
    \setparsizes{\z@}{\z@}{\z@\@plus 1fil}\par@updaterelative
    \raggedpart
    \interlinepenalty \@M
    \normalfont\sectfont\nobreak
    \ifnumbered{part}{%
      \size@partnumber{\partformat}%
      \partheadmidvskip
    }{}%
    \size@part{#2}\strut
    \ifx\partmark\@gobble
      \@mkboth{}{}\par
    \else
      \expandafter\partmark\expandafter{\scr@ds@head}\par
    \fi
  \endgroup
  \@endpart
}

It seems best to insert new ToC-related entries at the point where \@part issues \begingroup. For this we only need etoolbox to patch in the following way:

\usepackage{etoolbox}
\makeatletter
% \pdfstrcmp{<string1>}{<string2>}
% \pdfstrcmp compares two strings and expands to 0 if the strings are equal, to -1 if the first string
%   ranks before the second, and to 1 otherwise
\patchcmd{\@part}% <cmd>
    {\begingroup}% <search>
    {\ifnum\pdfstrcmp{#1}{#2}=0
       \addcontentsline{toc}{chapter}{\protect\textcolor{blue}{#2}}%
     \else
       \addcontentsline{toc}{chapter}{\protect\textcolor{red}{#1}}%
     \fi%
     \begingroup}%  
    {}{}%

\makeatother

The above inserts two \addcontentsline macros immediately before \begingroup. They are conditional on whether #1 matches #2 or not (using e-TeX's \pdfstrcmp). If they're the same, it means the user didn't supply an optional argument.

Note how content written to the ToC is \protected in order to avoid expansion. This is typical when writing to files to ensure things don't go horribly wrong.

Here is a complete minimal example:

enter image description here

\documentclass{scrreprt}

\usepackage{etoolbox,xcolor}

\makeatletter
% \pdfstrcmp{<string1>}{<string2>}
% \pdfstrcmp compares two strings and expands to 0 if the strings are equal, to -1 if the first string
%   ranks before the second, and to 1 otherwise
\patchcmd{\@part}% <cmd>
    {\begingroup}% <search>
    {\ifnum\pdfstrcmp{#1}{#2}=0
       \addcontentsline{toc}{chapter}{\protect\textcolor{blue}{#2}}%
     \else
       \addcontentsline{toc}{chapter}{\protect\textcolor{red}{#1}}%
     \fi%
     \begingroup}%  
    {}{}%

\makeatother

\begin{document}

\tableofcontents

\part{Only Long Caption}

\part[Short Caption]{Long Caption}

\end{document}

If you want the above to work with hyperref, you need to patch \H@old@part instead of \@part.

| improve this answer | |
  • Thanks! Sorry, I probably wasn't clear, but when "short caption" is given it should only return "short caption". So under Part 2 there should be only "Short Caption" – Jörg Nov 13 '14 at 22:50
  • @Jörg: See my updated answer... – Werner Nov 14 '14 at 0:11
  • Suggestion: Use \addchaptertocentry to use the internal addxcontentsline by package tocbasic. – Johannes_B Nov 14 '14 at 8:32
  • @Johannes_B Interesting, could you provide an example? – Jörg Nov 14 '14 at 12:36
  • @Jörg addchaptertocentry is explained in the documentation, and it is just substituting the \addcontentsline. Nothing to show really. But i have the feeling that you are trying to achieve something that my be very very easy to handle. – Johannes_B Nov 16 '14 at 15:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.