# How to keep last n lines together in listing?

I have a large listing defined with lstlisting (listins-package). Now the listing reaches over three pages. On the last page there is only one line (the last line) of the listing. I looks not very nice because the line only contains a bracket.

Is there a way to ensure that at least n (i.e. three) lines appears on the end of the listing, if the listing ends on a new page?

-
It's a typical relation between breaking boxes and wrong splitting. I think the answer is no. –  Marco Daniel Aug 11 '12 at 9:15

There are possibilities but it is a bit difficult to achieve. The listingspackage contains many hooks but unfortunately none that actually allows implementing this directly (at least I couldn't see one after some quick reading).

Problem is that each line in a listing is effectively a single paragraph and so there is some \parskip between the lines that make up a valid breakpoint. So what is needed is to get some \nobreak in that prevents a break there. This happens in the command \lst@NewLine so the main trick is to patch this command:

\makeatletter

\def\lst@NewLine{%
\ifx\lst@OutputBox\@gobble\else
\par
\ifnum\c@lstnumber > \@nobreaklinepoint \relax  \nobreak \fi  % <-- new code
\noindent \hbox{}%
\fi
\lst@newlinetrue}


Now \@nobreaklinepoint should be the line number of the third last line in the listing. Well, that's problem number two: we don't know the number of lines that the listing will have at this point in the processing. So in order to get this automatically, one would need to record the lines in the listing write them to the aux file (or so) and use the recorded values on the next typesetting run. --- No I haven't done that :-) maybe somebody else has the patience.

Instead I do the simple way out let the user specify this manually:

\def\lstnobreakafterline#1{\gdef\@nobreaklinepoint{#1}}


So if you have a listing with 15 lines and you want to ensure that the the last 3 will always be together you would need to say \lstnobreakafterline{13}. So a little counting is needed, sorry.

Now all of this should happen only for the next listing, so we have to do a little more work:

\lst@AddToHook{ExitVars}{\lstnobreakafterline{\maxdimen}}
\lstnobreakafterline{\maxdimen}
\makeatother


here we can use a built-in hook. We default the number to \maxdimen and we reset it at the end of a listing environment.

Obvious improvement possibilities: instead of \lstnobreakafterline we could define a new keyword which would fit better to the package interface (but it is getting close to midnight) and of course one could determine the number automatically in a two-pass system instead.

And there is one more flaw: \c@lstnumber is actually the line number that listings would use if it numbers the lines. So if numbering continues over several listings (which is possible depending on settings) then this will not restart with 1 on each listing.

Enjoy nevertheless ;-)

-
awesome, thank you very much! –  martin Sep 12 '12 at 6:29