3
\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
  • It's definitely clearer now, and @GuM seems to have understood your question, but unfortunately it's not clear to me what the problem is. In your example MWE at the top, if I remove \endfilbreak (or replace/define it with nothing), then I get 3 pages, with 1–4 on the first page, 5–9 on the second page, and 10 on the third page. So your example does not actually illustrate any problem, because it seems that an empty definition of \endfilbreak matches the thing you want (“\lipsum[6-10] should always come right after \lipsum[5]”). Do you have a more illuminating example perhaps? – ShreevatsaR Apr 30 '18 at 00:17
  • @ShreevatsaR You are completely right in regards to the MWE. I'm sorry I made such a messy and unclear question. Again: I have updated it, and please let me know if it's readable now.

    The comment about GuM not understanding the question was from his previous answer. His answer now works as expected! :)

    – Andreas Storvik Strauman Apr 30 '18 at 06:41
  • It's getting clearer, and I'm sorry to keep nagging you about this especially when @GuM seems to have understood your question and given you what you want. There are two problems I still face: (1) I think in “with \lipsum[13-19] preceding it (on page 3)” you mean “following” instead of “preceding” (the opposite). Otherwise it seems magical…. (2) You want to replace the last \filbreak with a \stopfilbreak, but it is still the case that if I replace the last \filbreak with nothing, then everything seems to satisfy your requirements. So empty definition of \stopfilbreak still works? – ShreevatsaR Apr 30 '18 at 07:48
  • I did men preceding and not following, yes. Thanks. I guess an empty filbreak would technically work in this case. However, you don't a priori know whether \lipsum[11-12] would fit or not. – Andreas Storvik Strauman Apr 30 '18 at 07:53
  • Ah I see; finally I understand! (I think.) Your question is the following: you intend to enclose some stuff (like \lipsum[11-12]) within some macros, with the intended meaning being: “fit this stuff on the same page if possible, else break the page here and put it on a new page”. And of course, what comes later should not be affected. Is that correct? (You propose \filbreak ...\stopfilbreak as the intended form of these macros, but if I understand your true goal correctly, then you just care about these semantics/behaviour, and the macros don't necessarily have to take this exact form.) – ShreevatsaR Apr 30 '18 at 08:03
  • Yes. Exactly. It does not have to be \filbreak used, but to my use, having them as macros are necessary. I hope it's okay with you if I insert your formulation into my question? – Andreas Storvik Strauman Apr 30 '18 at 08:08
  • Yes sure, of course. BTW I think a related question has been asked before, with a great answer by @GuM there as well. (A very different approach though.) Maybe he can elaborate how the approaches differ, if he feels up to it. Thanks for your patience and making the question clear for me. :-) – ShreevatsaR Apr 30 '18 at 08:12

1 Answers1

4

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…

GuM
  • 21,558
  • 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 06: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 06: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