2

I am using XeTeX. I need to redefine the \section and \subsection commands in order to use some macros which don't behave well with the titlesec and/or sectsty packages. I found some code to do this, which comes up repeatedly over the net, and which seems to originate from the resume.sty source {link here}.

Despite the rather awful decision tree at the beginning, the actual code looks as you'd expect: put some glue, insert the section title, then some more glue, and get on with it, after suggesting where good and bad breaks would be. However, if I follow a \section{foo} call immediately by another \section{bar} or \subsection{baz}, it inserts too much whitespace/glue (the \vskip-\lastskip doesn't seem to 'grip'). I have also redefined \subsection in precisely the same fashion, but omitted it from the MWE here as the inbuilt command reproduces the behaviour exactly (easy enough to reconstruct if necessary by copy/paste/substitute).

It would be wonderful if someone can either see the reason why the code does this, or provide an alternative way to place section headings that can:

  • have some defined amount of leading (glue/whitespace) before and after (but remove the 'after' leading in between consecutive section/subsection calls)
  • take other macros, which call, eg, zpos and etoolbox, and behave
  • be extended to preserve the functionality of the MWE below (the 'if starred this then if two args that' tree, counter increments, and TOC updates, can be omitted from solutions, as they're trivial to build, but they are ultimately necessary to include)

Apologies for drawn out MWE, but I've commented the code to try to explain what's going on (I've left the full code in, as mutations of it do appear all over, and people with a similar problem might use the long and rather unique macro names, which tend not to change between examples, to winnow down Google results: I did).

Illustrations

The image on the left is what is produced by the MWE code below. The image on the right uses the exact same document content, using the inbuilt \section definition, and is the desired behaviour for the redefined command (ignore actual text size, weight, etc, the problem is the leading).

MWE Image Fixed image

MWE code

\documentclass{article}

\makeatletter
%We want to take a minimum of one command, with an optional command which holds
%a different title for the TOC; if starred, then don't insert number
%So, numbered or not?
\def\section{\@ifstar\unnumberedsection\numberedsection}
%One or two args?
\def\numberedsection{\@ifnextchar[%]%
\numberedsectionwithtwoarguments\numberedsectionwithoneargument}
\def\unnumberedsection{\@ifnextchar[%]%
\unnumberedsectionwithtwoarguments\unnumberedsectionwithoneargument}
%If one arg, duplicate it to make two, so only one set of commands needs be
%written
\def\numberedsectionwithoneargument#1{\numberedsectionwithtwoarguments[#1]{#1}}
\def\unnumberedsectionwithoneargument#1{\unnumberedsectionwithtwoarguments[#1]{#1}}

% Unstarred case, ie insert number:
\def\numberedsectionwithtwoarguments[#1]#2{%
%Check that previous paragraph ends sanely
\ifhmode\par\fi%
%Remove previous glue, to avoid huge spaces
\vskip-\lastskip%
%Insert some glue to separate heading; here's a good place to break the page
\vskip 3ex\@plus 1ex \@minus 0.5ex\goodbreak%
%Increment section number counter
\refstepcounter{section}%
%Insert formatted heading command here (plus number)
%In my actual usage, it has some other formatting macros, but this MWE reproduces
%the problem, so I know it's not them causing it
\begingroup \parindent=0pt {\Large \bfseries \thesection\  #2}
%We don't want to separate the heading from the text which follows
\nobreak\endgroup%
%Let it breathe a bit!
\vskip 2ex\@plus 0.67ex \@minus 0.5ex%
%No, we still /really/ don't want to separate it; nor indent the para which
%follows
\nobreak\noindent%
%Add it to the TOC
\addcontentsline{toc}{section}{%
\protect\numberline{\thesection}%
#1}%
%For ease of use, disregard whether the text has a blank line following the call
%to '\section'
\ignorespaces}

%Do exactly the same with the unnumbered case, except don't include a number
%This is closer to the original code I found, so can be used to verify it's none
%of my modifications, eg stretch and squeeze on vskips
\def\unnumberedsectionwithtwoarguments[#1]#2{%
\ifhmode\par\fi
\removelastskip
\vskip 3ex\goodbreak
%Insert formatted heading command here without number
\begingroup \parindent=0pt {\Large \bfseries #2}\par%
\nobreak\endgroup%
\vskip 2ex\nobreak\noindent%
\addcontentsline{toc}{section}{%
#1}%
\ignorespaces}
\makeatother

\begin{document}

\section{A new section}
\ldots which behaves as it should.

\subsection{A new subsection}
\ldots which also behaves, but:

\section{A new section}
\subsection{followed immediately by a subsection}
\ldots inserts too much white space.

\section{Two sections}
\section{One after the other}

\section*{Verify unnumbered}
\subsection*{Also a problem}

\section*{And check unnumbered without following subsection}
\noindent\ldots which is fine.  The fact that the subsection -- section
combination works suggests perhaps a problem with the final vskip in the macro?
\end{document}
  • Why aren't you using any of the latex commands for supporting sectioning? (\@startsection and friends) – David Carlisle Jul 2 '14 at 11:54
  • If I use them, I get errors resulting from undefined commands on the formatting macros I want to include in the section heading (as they depend on packages loaded after the \@startsection begins expanding and writing to the .aux etc., as the LaTeX commands are either inbuilt or in article.cls which is loaded first in the process) Even defining these other macros using \DeclareRobustCommand results in all kinds of other pain relating to zpos etc. This problem, ie insert some whitespace and delete it in certain well-defined cases, seems a much easier one to solve, and more general. – spog Jul 2 '14 at 12:00
  • sorry that description doesn't fit what happens: any formatting commands in the section heading will be expanded when the heading is encountered but presumably all packages are loaded in whatever order, in the preamble so way before then. a large part of \@startsection is concerned with exactly this problem of putting suitable spaces before and after possibly consecutive headings, so using \@startsection is likely to be the answer unless you can show an example where it doesn't work. – David Carlisle Jul 2 '14 at 12:40
2

You should use \@startsection unless there is good reason not to, as that incorporates code to handle consecutive headings and to dea lwith headings that are more than one line, or followed by a blank line, neither if which are handled by this code

\vskip-\lastskip%
%Insert some glue to separate heading; here's a good place to break the page
\vskip 3ex\@plus 1ex \@minus 0.5ex\goodbreak%

This may or may not remove space (depending if the existing space is guarded by a penalty) and if the existing space was larger or smaller than the 3ex being added.

If you used \addvspace as used by the standard sectioning and display environment code then the previous space is checked and the maximum of the existing space and the new value is used.

\begingroup \parindent=0pt {\Large \bfseries \thesection\  #2}
%We don't want to separate the heading from the text which follows
\nobreak\endgroup%

This ends the group before the paragraph is set so the \parindent=0pt setting does nothing, and if the heading goes over more than one line, it will be set on a small (normalsize) baseline even though it is using \Large text.

\nobreak\noindent%

\noindent starts the following paragraph so if the source has a blank line following the section head (or a following heading as in your example) then this paragraph will be ended by the \par and the actual text following the heading will be indented. See the \@afterheading code used by latex section headings to suppress indentation/

% For ease of use, disregard whether the text has a blank line following the call

This comment is wrong: \ignorespaces ignores space tokens but not \par from a blank line (if you used \@startsection a following \par is handled correctly)

  • Your insistence on the value of \@startsection encouraged me to see if I could do it another way; turns out it was a rogue \ifthenelse in my formatting macro which didn't play with \@startsection (premature expansion etc), so I did it another way, with \@startsection and etoolbox, without the loss of generality which concerned me. Correct answer because \@startsection is the better solution for headings etc thanks to the organic handling of spacing with sensible penalties and so forth, but the actual lesson is to use conditionals from etoolbox not ifthen. – spog Jul 2 '14 at 15:06

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.