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.)

6
  • 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. Jun 16, 2014 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, 2014 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. Jun 16, 2014 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, 2014 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. Jun 17, 2014 at 18:15

3 Answers 3

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
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.

3
  • 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, 2014 at 9:12
  • I'm still working on it. The only thing left is to replace myitemize with itemize. Jun 18, 2014 at 14:53
  • BTW, I modified \pagecheck to handle the case where there are blank lines between \items. Jun 20, 2014 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
2
  • 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, 2015 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, 2015 at 4:43

You must log in to answer this question.

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