How to restore normal flow after \filbreak

\documentclass[a4paper]{article}
\usepackage{lipsum}
\begin{document}
\lipsum[1-4]\filbreak
\textbf{This should fit on page 1}~\lipsum[5]\filbreak\lipsum[6-10]\filbreak
\textbf{This should not fit on page 2}~\lipsum[11-12]\filbreak\lipsum[13-19]
\end{document}


The problem arises with the last \filbreak in this example. It flushes \lipsum[13-19] to the next page. I want to replace the last \filbreak it with a command \stopfilbreak, so that since \lipsum[11-12] actualy didn't fit on page 2, then it would put \lipsum[11-12] on page 3 with \lipsum[13-19] following it (on page 3). Now it sets \lipsum[13-19] on page 4.

I want a command \stopfilbreak such that LaTeX interprets "fit the content between \filbreak and \stopfilbreak on the same page if possible, else break the page here and put it on a new page". The content to come after \stopfilbreak should not be affected.

That is: i want a command that restores the normal flow after use of \filbreak

Be aware that it might be so that what would go between \filbreak and \stopfilbreak could be larger than a pagewidth, so minipage would not work.

Below is some background info that I think might be helpful to answer my question:

Background info

Purpose of \filbreak

The TeXbook says that \filbreak means roughly

“Break the page here and fill the bottom with blank space, unless there is room for more copy that is itself followed by \filbreak.”

That is, if we consider content that is "enclosed" by \filbreaks, it inserts this content if there is room on the page, but goes to the next page if there is no room.

\filbreak in practice

\filbreak is defined by \par\vfil\penalty-200\vfilneg. As I understand it, this finishes up the current paragraph, then fills the page with stretchable whitespace and then, at the bottom of the page/top of new page it says that "breaking" here is cheap. If the program then decides to break here, then the \vfilneg doesn't do anything because there is no \vfil to "neg", but if it doesn't then \vfilneg puts the "cursor" back.

I'm not using \filbreak as it was purposed. Everything in my VC-example works as expected, which indicates that I might be asking the wrong question?

• I think your understanding of \filbreak is mistaken or at least imprecise. It does not really check or insert anything; it merely inserts a particular sequence of glue and penalties, which are used by the page builder whenever it decides to look for appropriate places to break the page. Rather than go by the informal description in The TeXbook, see the definition you've included. Anyway, it's not clear what you want exactly: where do you want the page breaks to happen / what would you like the general behaviour to be? – ShreevatsaR Apr 29 '18 at 10:12
• @ShreevatsaR: I see how it could seem like my understanding of \filbreak is wrong. I get that it doesn't "check" anything, I just had problems wording this, which results in that my description of how \filbreak works is imprecise. Maybe it's just confusing to have the Background info in there? I suspect you missed the "TL;DR"-section in the top (maybe because you read all the rest)? I thought it was quite clear there what I wanted to achieve. If I'm wrong, and you did read it, let me know what is unclear so I can clarify! – Andreas Storvik Strauman Apr 29 '18 at 10:21
• It may help to explain again what you want in different words (i.e. show where the page breaks go, in your example, and why). Because: What does “the height of \lipsum[5] is evaluated for inserting space, and then insert the upcoming as if there was nothing happening” mean? (Because height is never evaluated… and what does “nothing happening” mean.) Similarly, not clear what “I want a command \endfilbreak to check only the "height" of \lipsum[5] and then insert the upcoming as if there was nothing happening” means. – ShreevatsaR Apr 29 '18 at 15:18
• I think I've cleared it up now in the question? – Andreas Storvik Strauman Apr 29 '18 at 15:36
• I deleted my answer, because it was completely wrong. The value of \outputpenalty cannot be used in that way to discriminate the two cases. – GuM Apr 29 '18 at 17:26

1 Answer

I had previously posted, and subsequently deleted, an answer that was completely wrong; now I’m replacing it with the following one, which not only makes at least some sense, but also seems to work as expected! (:-)

% My standard header for TeX.SX answers:
\documentclass[a4paper]{article} % To avoid confusion, let us explicitly
% declare the paper format.

\usepackage[T1]{fontenc}         % Not always necessary, but recommended.
% End of standard header.  What follows pertains to the problem at hand.

\usepackage{lipsum}

\makeatletter

\@ifdefinable\@My@filbreak@counter{\newcount\@My@filbreak@counter}
\global \@My@filbreak@counter = 0
\@ifdefinable\@My@filbreak@mark{\newmarks\@My@filbreak@mark}

\renewcommand*\filbreak{%
\par
\global \advance \@My@filbreak@counter \@ne
\marks\@My@filbreak@mark{\number\@My@filbreak@counter}%
\vfil
\penalty -200
\vfilneg
}

\newcommand*\@My@finish@stopfilbreak{}

\newcommand*\stopfilbreak{%
\par
\ifnum \prevdepth >\@m \else \prevdepth \z@ \fi
\nobreak \null
\nobreak \vskip -\baselineskip
\penalty \z@
\begingroup
\output{%
% \typeout{>>> \topmarks\@My@filbreak@mark
%         \space vs \number\@My@filbreak@counter}%
\typeout{t: \the\pagetotal, g: \the\pagegoal}%
\unvbox\@cclv
\ifnum 0\topmarks\@My@filbreak@mark <\@My@filbreak@counter
% the last "\filbreak" is still on the current page
\gdef\@My@finish@stopfilbreak{%
\vfil\break % force page break
}%
\else
% the page has changed since the last "\filbreak"
\gdef\@My@finish@stopfilbreak{%
\penalty\z@ % allow page break but don't force it
}%
\fi
}%
\break
\endgroup
\@My@finish@stopfilbreak
}

\makeatother

\newcommand*{\mylipsum}[1]{\par\textbf{#1}~-- \lipsum*[#1]\par}

% \tracingpages = 1

\begin{document}
\mylipsum{1}
\filbreak
\mylipsum{2}
\filbreak
\mylipsum{3}
\filbreak
\mylipsum{4}
\filbreak
\mylipsum{5}
\filbreak
\mylipsum{6}
\filbreak
\mylipsum{7}
\filbreak
\mylipsum{8}
\mylipsum{9}
\mylipsum{10}
% \mylipsum{11}
\indent One.\par
\indent Two.\par
\indent Three.\par
\indent Four.\par
% \indent Five.\par
% \indent Six.\par
% \mylipsum{12}
\stopfilbreak
\mylipsum{13}
\mylipsum{14}
\mylipsum{15}
\mylipsum{16}
\end{document}


Try uncommenting the line that says % \mylipsum{11}, or the line that reads % \indent Five.\par.

I’m too weary, now, to explain in detail how the code works; perhaps I’ll review this answer tomorrow, for now I simply hint at the general idea. We use a custom \marks system, namely \marks\@my@filbreak@mark, to detect if the last \filbreak before \stopfilbreak occurs on the same page as the latter, and if so we force a page break; otherwise, \stopfilbreaks inserts only a permissible breakpoint.

I’ve left the previous version of this answer accessible through the edit list so that everyboby can contemplate how incredibly stupid it was…

• YASS! Perfect! I would love it if you'd explain how it works too at some point! Thanks! – Andreas Storvik Strauman Apr 30 '18 at 6:21
• It works when I put it in my examples and I can't find anything wrong in a usecase, however, in the first \gdef\@My@finish@stopfilbreak I'm not really sure if it does what I ask? I might have been a bit quick to accept this answer, heh ':) – Andreas Storvik Strauman Apr 30 '18 at 6:59
• @AndreasStorvikStrauman: You mean, the action taken when the last \filbreak is still on the same page? It can be changed: what would you like to occur, intstead of a page break being forced? – GuM Apr 30 '18 at 13:37
• I changed my mind. I think it does exactly what it's supposed to! Maybe. I'll let you know when I've figured it all out ':) – Andreas Storvik Strauman Apr 30 '18 at 17:33