3

When including source code from files (in order to keep it automatically up-to-date), There is no way to influence the formatting by editing the source code. When a paragraph in the document changes, the listing might become hard to read.

This is because source code is ooften rganized into "paragraphs" (e.g. the function signatures and their comments below) and I would prefer not to break them. Is there a way to force lstlisting to only page-break e.g. on empty lines? Below is a simple example with lstinputlisting:

\RequirePackage{filecontents}
\begin{filecontents*}{stack.mli}
(***********************************************************************)
(*                                                                     *)
(*                                 OCaml                               *)
(*                                                                     *)
(*             Xavier Leroy, projet Cristal, INRIA Rocquencourt        *)
(*                                                                     *)
(*   Copyright 1996 Institut National de Recherche en Informatique et  *)
(*     en Automatique.                                                 *)
(*                                                                     *)
(*   All rights reserved.  This file is distributed under the terms of *)
(*   the GNU Lesser General Public License version 2.1, with the       *)
(*   special exception on linking described in the file LICENSE.       *)
(*                                                                     *)
(***********************************************************************)

(** Last-in first-out stacks.
   This module implements stacks (LIFOs), with in-place modification.
*)

type 'a t
(** The type of stacks containing elements of type ['a]. *)

exception Empty
(** Raised when {!Stack.pop} or {!Stack.top} is applied to an empty stack. *)


val create : unit -> 'a t
(** Return a new stack, initially empty. *)

val push : 'a -> 'a t -> unit
(** [push x s] adds the element [x] at the top of stack [s]. *)

val pop : 'a t -> 'a
(** [pop s] removes and returns the topmost element in stack [s],
   or raises {!Empty} if the stack is empty. *)

val top : 'a t -> 'a
(** [top s] returns the topmost element in stack [s],
   or raises {!Empty} if the stack is empty. *)

val clear : 'a t -> unit
(** Discard all elements from a stack. *)

val copy : 'a t -> 'a t
(** Return a copy of the given stack. *)

val is_empty : 'a t -> bool
(** Return [true] if the given stack is empty, [false] otherwise. *)

val length : 'a t -> int
(** Return the number of elements in a stack. Time complexity O(1) *)

val iter : ('a -> unit) -> 'a t -> unit
(** [iter f s] applies [f] in turn to all elements of [s],
   from the element at the top of the stack to the element at the
   bottom of the stack. The stack itself is unchanged. *)

val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b
(** [fold f accu s] is [(f (... (f (f accu x1) x2) ...) xn)]
    where [x1] is the top of the stack, [x2] the second element,
    and [xn] the bottom element. The stack is unchanged.
    @since 4.03 *)
\end{filecontents*}
\documentclass{article}
\usepackage{listings}
\begin{document}
\section{Stack}
\lstset{
  basicstyle={\ttfamily\lst@ifdisplaystyle\footnotesize\fi},
  language=[Objective]Caml
}
\lstinputlisting{stack.mli}
\end{document}

In the example above, I get a break between copy and its comment, although bnreaking one line earlier would be much better.

2 Answers 2

1

According to https://tex.stackexchange.com/a/73305/89417 a solution to prevent page breaks in listings is to use a minipage. Putting every code paragraph in a separate minipage will therefore break in between paragraphs. You can easily automate this using any scripting language, e.g., perl:

print "\\noindent\\begin{minipage}{\\linewidth}\\begin{lstlisting}\n";
while(<>){
    print $_ eq "\n" ? "\\end{lstlisting}\\end{minipage}\n\n\\noindent\\begin{minipage}{\\linewidth}\\begin{lstlisting}\n" : $_;
}
print "\\end{lstlisting}\\end{minipage}\n";

This script converts empty lines into the end and start of a minipage, and puts an extra start and end to match the first and last paragraph.

Then, in LaTeX, you can call this script (assuming Linux, run with --shell-escape):

\documentclass{article}
\usepackage{listings}
\usepackage[margin=1.5in]{geometry} % make OCaml comment block fit on a line
\begin{document}
\section{Stack}
\lstset{
  basicstyle={\ttfamily\lst@ifdisplaystyle\footnotesize\fi},
  language=[Objective]Caml
}
\input{|"perl format_listing.pl < stack.mli"}
\end{document}

Result:

enter image description here

0

If there is only one page break, one easy way is to use \enlargethispage.

This moves the val copy line on to the next page.

\documentclass{article}
\usepackage{listings}
\begin{document}
\section{Stack}
\lstset{
  basicstyle={\ttfamily\lst@ifdisplaystyle\footnotesize\fi},
  language=[Objective]Caml
}
\enlargethispage{-\baselineskip}
\lstinputlisting{stack.mli}
\end{document}

enter image description here

2
  • The quoted file is just a MWE. In reality I have several pagebreaks. Nevertheless, the idea of manually tweaking page sizes might be a good one. Is there a way to tweak pages that are not "this" page?
    – choeger
    Apr 24, 2017 at 20:56
  • @choeger \afterpage{\enlagethispage{...}] might work, perhaps... afterpage package, but probably in that case something based on code line numbers is probably more convenient than this \enlargethispage suggestion. Apr 24, 2017 at 21:07

You must log in to answer this question.

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