6

In a document I'm working on, I'd like whitespace to be added before a custom environment, but only if that environment doesn't immediately follow a sectioning command (\section, \subsection, etc). I figured I could set up a paragraph counter via the everyhook package, and use the etoolbox package's \pretocmd macro to patch \@startsection to reset the paragraph counter. That seemed to work fine, but I noticed some odd behavior in the spacing produced... after some debugging, I whittled it down to a strange interaction between everyhook and fancyhdr. Here's a minimal example demonstrating what's happening:

\documentclass[12pt]{article}
\usepackage{blindtext}
\usepackage{everyhook}
\usepackage{fancyhdr}

\newcounter{paranum}
\PushPreHook{par}{\stepcounter{paranum}}

\pagestyle{fancy}

\begin{document}
  \section*{Heading}

  \theparanum: \blindtext

  \theparanum: \blindtext

  \theparanum: \blindtext

  \section*{Heading}

  \theparanum: \blindtext

  \theparanum: \blindtext

  \theparanum: \blindtext
\end{document}

This generates

this image (click here)

Everything counts along fine on the first page, but on the second, the count jumps from 5 to 12. Removing the \pagestyle{fancy} command fixes this. Why? And more importantly, how can I keep using the fancyhdr package while also being able to accurately number paragraphs?

2 Answers 2

5

Call

\usepackage[excludeor]{everyhook}

which will suppress evaluating the \everypar tokens inside the output routine.

It's possible to get the same behavior without fancyhdr: just say

\pagestyle{myheadings}

and

\section*{Heading}
\markright{\protect\parbox{3cm}{abc}}

The paragraph built inside the \parbox will cause the hook to be executed and the counter stepped. With the excludeor option this doesn't happen.

2
  • Thanks! I figured it had something to do with paragraphs being created inside the header, but I had no idea how to fix it. Is there a relatively straightforward reason why this affects the counter on the second paragraph of the second page in my example, and not the first paragraph?
    – Dan
    Sep 12, 2012 at 8:14
  • 1
    Yes: the output routine acts asynchronously. TeX gathers more material than fits on a page in order to find the best break point and always entire paragraphs are stored. So your paragraph 5 is typeset (in memory) and only after that operation the output routine acts.
    – egreg
    Sep 12, 2012 at 8:24
3

As you'd "like whitespace to be added before a custom environment, but only if that environment doesn't immediately follow a sectioning command", I suggest to simply add a test for the @nobreak switch at the start of your environment. @nobreak is true only immediately after headings.

\documentclass{article}

\newcommand*{\sometext}{Lorem ipsum dolor sit amet, consectetuer
    adipiscing elit. Etiam lobortis facilisis sem. Nullam nec mi et
    neque pharetra sollicitudin. Praesent imperdiet mi nec ante. Donec
    ullamcorper, felis non sodales commodo, lectus velit ultrices augue,
    a dignissim nibh lectus placerat pede.}

\makeatletter
\newenvironment{testenv}{%
  \itshape
  \if@nobreak
  \else
    \vspace{50pt}%
  \fi
}{%
}
\makeatother

\usepackage{blindtext}

\begin{document}

\section*{Heading}

\sometext

\begin{testenv}
\sometext
\end{testenv}

\section*{Heading}

\begin{testenv}
\sometext
\end{testenv}

\end{document}

enter image description here

2
  • Did not know about \@nobreak. This a much better solution than the one I came up with. Is \@nobreak only set after headings, or are there other cases where it is also set and might cause issues?
    – Dan
    Sep 12, 2012 at 8:22
  • 1
    @Dan Quoting source2e, p. 54: "The @nobreak switch is set true used when in vertical mode and no page break should occur. (Right now, it is used only by the section heading commands to inhibit page breaking after a heading.)"
    – lockstep
    Sep 12, 2012 at 8:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .