6

Is there a way to globally prevent all lists from having a page break inserted between the first and second items or between the last and second-last item? I'm fine with page breaks that are after the second item and before the second-last item, but I do not want the first item or the last item to be alone.

I know that I can use "\nopagebreak\@nobreaktrue" to prevent a page break at a specific location, but I don't want to have to insert it manually, nor do I know how to insert it automatically via macros.

(I've searched everywhere for many hours but couldn't find a solution, and I'm a beginner in LaTeX so I can't figure out how to solve it myself.)

  • Creating a \firstitem macro should be fairly easy, but \lastitem is more difficult. The next to last item might cause a page break before \lastitem is expanded. – John Kormylo Jun 16 '14 at 4:33
  • 1
    @JohnKormylo: Is there really no penalty for such things? I tried but couldn't find any; apparently \widowpenalty and \orphanpenalty are only for paragraphs. Can you show how to create a macro that solves the problem for the first item of every list? – user21820 Jun 16 '14 at 4:39
  • A better solution would be to put all the items into saveboxes and count them, then put the first two and last two useboxes into minipages. – John Kormylo Jun 16 '14 at 15:21
  • @JohnKormylo: But that wouldn't "globally prevent" the problem, and in that case wouldn't "\nopagebreak\@nobreaktrue" be better than your last suggestion? – user21820 Jun 16 '14 at 16:15
  • Sorry, this is proving more difficult than I thought. \item functions like \par; the text that follows is treated like normal text instead of arguments. – John Kormylo Jun 17 '14 at 18:15
3

I've adjusted \pagetest so that if you reduce the rule to 6.31in you get all 5 items on one page.

\documentclass{article}

\newcommand{\pagecheck}[1]% #1 = legnth to end of page
{\ifvmode\vspace{-\parskip}\else\newline\fi% check for blank line between items
\rule{0pt}{#1}\vspace{-#1}}

\newlength{\pagetest}
\setlength{\pagetest}{0.55in}% adjustable

\makeatletter
\newcommand{\newaux}[2]% #1 = label, #2 = text
{\expandafter\gdef\csname AUX@#1\endcsname{#2}}

\newcommand{\getaux}[1]% #1 = label
{\@ifundefined{AUX@#1}{0}{\csname AUX@#1\endcsname}}

\newcommand{\writeaux}[2]% #1 = label, #2 = text
{\@bsphack
\write\@auxout{\string\newaux{#1}{#2}}%
\@esphack}
\makeatother

\newcounter{items}%
\newcount\itemtest
\newcount\itemno

\let\OLDitemize\itemize%
\let\endOLDitemize\enditemize%
\let\OLDitem=\item%

\renewenvironment{itemize}%
{\pagecheck{\pagetest}%
\stepcounter{items}%
\global\itemtest=\getaux{item\arabic{items}}
\global\advance\itemtest by -1
\global\itemno=0
\begin{OLDitemize}}%
{\end{OLDitemize}%
\writeaux{item\arabic{items}}{\the\itemno}}

\def\item{%
\global\advance\itemno by 1
\ifnum\itemno=\itemtest \pagecheck{\pagetest}\fi%
\OLDitem}

\begin{document}

\noindent\rule{\textwidth}{6.32in}% adjustable

\begin{itemize}
\item first
\item second
\item third
\item fourth
\item fifth
\end{itemize}

\end{document}
1

I have always found \pagebreak[3] to be useless. \pagecheck prevents a pagebreak over a given distance. For short items 0.5in should be adequate.

\documentclass{article}
\usepackage{lipsum}

\newcommand{\pagecheck}[1]% #1 = legnth to end of page
{\ifvmode\vspace{-\parskip}\else\newline\fi% check for blank line between items
\rule{0pt}{#1}\vspace{-#1}}

\begin{document}
\noindent\rule{\textwidth}{1pt}

\pagecheck{3in}
\begin{itemize}
\item \lipsum[1]
\item \lipsum[2]
\item \lipsum[3]
\pagecheck{3in}
\item \lipsum[4]
\item \lipsum[5]
\end{itemize}

\end{document}

If you absolutely have to make it automatic, one could write the number of items for each itemize onto auxout, so that the next time latex is run it would know where the next to last item in each itemize is located.

  • Yes I want to have it absolutely automatic, as I am using the list environment for something that I want to be completely flexible, where each list item would be really an item, not a paragraph. If it isn't too much trouble I'd like to see how you were intending to do it with a double LaTeX compilation. – user21820 Jun 18 '14 at 9:12
  • I'm still working on it. The only thing left is to replace myitemize with itemize. – John Kormylo Jun 18 '14 at 14:53
  • BTW, I modified \pagecheck to handle the case where there are blank lines between \items. – John Kormylo Jun 20 '14 at 15:43
1

I can show how to set this feature in plain TeX with OPmac. The \begitems and \enditems are redefined. First one reads the data from REF file (this is similar like aux in LaTeX). The result of such reading is the \lastitem macro where the number of items in the current items-list is stored. The second one (\enditems) saves the \itemnum (i.e. the number of items) to the REF file in the form:

\sdef{ilist:number_of_list}{number_of_items}

Finally, the internal \startitem is redefined in order to put \nobreak if \itemnum=2 or if \itemnum=\lastitem.

\input opmac
\newcount\itemlistnum
\def\readnumitems{\edef\itemlistn{\the\itemlistnum}%
   \tmpnum=0\csname ilist:\itemlistn\endcsname
   \edef\lastitem{\the\tmpnum}}
\def\writenumitems{\openref\immediate\wref\sdef{{ilist:\itemlistn}{\the\itemnum}}}
\addto\begitems{\global\advance\itemlistnum by1 \readnumitems}
\def\enditems{\par\writenumitems\egroup\iiskip}
\def\startitem{\par \advance\itemnum by1
   \ifnum\itemnum=2 \nobreak \fi
   \ifnum\itemnum=\lastitem \nobreak \fi
   \noindent\llap{\printitem}\ignorespaces}

%%% The test:

\begitems
* First
* Second
  \begitems \style n
  * nested first
  * nested second
  \enditems
* Third
* Last
\enditems

\begitems
* First
* Second
* Third
* Next
* Last
\enditems

\bye
  • 1
    Thanks for answering! I wasn't expecting any more since I've long since given up on having fine control over LaTeX. In the end I just used \@itempenalty=1000 which worked in most cases. But I'm sure your answer could be useful to other people having the same problem. Now the only thing is that I don't know whether to accept an answer just to get the question off the unanswered list, even though I didn't want to use any of them haha.. – user21820 May 1 '15 at 3:40
  • 1
    Yes, fine control over LaTeX is almost impossible. No LaTeX package writers are able to control all aspects. The XeLaTeX example "Hello world" (with OTF fonts) generates more than 2 millions lines to the .log when \tracingall. It is impossible to control this by human. On the other hand, plain TeX is simple controllable. – wipet May 1 '15 at 4:43

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.