39

I use lstlistings to include code in my document. I'd like my code to be framed and its frame to be adjusted to the size of the actual code content. Here is what I have as of now :

\lstset{numbers=left, numberstyle=\small, numbersep=8pt, frame = single, language=Pascal, framexleftmargin=15pt}

\begin{lstlisting} PROGRAM afficher_bonjour; BEGIN WRITE('Bonjour'); END. \end{lstlisting}

The frame is being drawn across the entire width of the page instead of being shrinked to the listing contents. There's a lot of useless empty space on the right.

I could manually set the linewidth of the listing or wrap it in a manually sized minipage. This however results in a lot of manual work when using many listings and I would like to avoid that.

Is there any way to have the frame size or the linewidth of a listing automatically be fitted to the listing's content?

LukeG
  • 103
guigui
  • 411
  • 1
  • 4
  • 5
  • 4
    This question appears to be off-topic because it is about a feature request for listings. – jub0bs Mar 01 '14 at 18:52
  • 5
    The question is on-topic: it is not requesting a new listings feature, but simply a way to achieve a typesetting goal: i.e., a tightly-wrapped box around a listing. @Daniel's answer below, for example, gives one possible solution to this question that doesn't involve changing the listings package. – davidg Jul 03 '14 at 12:28
  • @davidg non-of the solutions below (with auto-adjustment of width) work for verbatim that extends over one page. The text is chopped off if it is longer than one page. – Nasser Aug 27 '14 at 20:03
  • As you can see below, the ground of missing for the accusation that the question is a request for a new feature for listings. Oh, well... – Yossi Gil Sep 12 '14 at 09:18
  • Sounds weird that it's closed! came here with some hope to solve the same problem! what a pitty – Prelude Oct 20 '18 at 21:40

4 Answers4

25

Another option is to use the linewidth option for lstlisting to control the width:

\documentclass{article}
\usepackage{listings}

\lstset{
numbers=left, 
numberstyle=\small, 
numbersep=8pt, 
frame = single, 
language=Pascal, 
framexleftmargin=15pt}

\begin{document}

\begin{lstlisting}
PROGRAM afficher_bonjour; 
BEGIN WRITE('Bonjour'); 
END.
\end{lstlisting}

\begin{lstlisting}[linewidth=5.4cm]
PROGRAM afficher_bonjour; 
BEGIN WRITE('Bonjour'); 
END.
\end{lstlisting}

\end{document}​

enter image description here

Gonzalo Medina
  • 505,128
  • Thank you both for your solution. However, I'd like the horizontal space to be computed automatically. I have lots of codes to be framed and dont want to have to adjust manually the size of my minipage or my linewidth. – guigui Sep 04 '12 at 20:35
  • 2
    @guigui That would require two passes, so what you're asking for is essentially a feature request for listings. – jub0bs Mar 01 '14 at 18:52
12

tcolorbox package provides environments for framed and colored boxes. One of its libraries is designed to interact with listings package and one of its capture modes hbox automatically adjust frames to their contents. Combining both elements it's easy to create framed listings with adjusted width.

And, of course, you can decorate your listings with all other enhancements provided by tcolorbox.

Update: Although OP doesn't mention it, it's not possible to automatically break long listings between pages when using hbox.

\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{listings,skins}

\lstdefinestyle{mystyle}{
numbers=left, 
numberstyle=\small, 
numbersep=8pt, 
language=Pascal
}

\newtcblisting{mylisting}[2][]{
    arc=0pt, outer arc=0pt,
    listing only, 
    listing style=mystyle,
    title=#2,
    #1
    }

\begin{document}

\begin{mylisting}{}
PROGRAM afficher_bonjour; 
BEGIN WRITE('Bonjour'); 
END.
\end{mylisting}

\begin{mylisting}[hbox]{}
PROGRAM afficher_bonjour; 
BEGIN WRITE('Bonjour'); 
END.
\end{mylisting}

\begin{mylisting}[hbox,enhanced,drop shadow]{Pascal program}
PROGRAM afficher_bonjour; 
BEGIN WRITE('Bonjour'); 
END.
\end{mylisting}

\end{document}​

enter image description here

Ignasi
  • 136,588
  • 2
    fyi, this solution does not work, as it chops off any verbatim if it is over one page long. – Nasser Aug 27 '14 at 20:01
4

You should place the entire lstlisting inside an environment that restricts the horizontal width, like a minipage:

enter image description here

\documentclass{article}
\usepackage{listings}% http://ctan.org/pkg/listings
\begin{document}
\lstset{numbers=left, numberstyle=\small, numbersep=8pt, frame = single, language=Pascal, framexleftmargin=15pt}

\begin{lstlisting}
PROGRAM afficher_bonjour; 
BEGIN WRITE('Bonjour'); 
END.
\end{lstlisting}

\noindent\begin{minipage}{.5\linewidth}
\begin{lstlisting}
PROGRAM afficher_bonjour; 
BEGIN WRITE('Bonjour'); 
END.
\end{lstlisting}
\end{minipage}
\end{document}​
Werner
  • 603,163
  • 2
    Thank you both for your solution. However, I'd like the horizontal space to be computed automatically. I have lots of codes to be framed and dont want to have to adjust manually the size of my minipage or my linewidth. – guigui Sep 04 '12 at 20:35
4

The frame= key of the listings package always typesets the frame with respect to the current line width. Hence, I suggest to use another command or environment to draw the frame.

A basic solution (without further packages) would be to render the listing inside an \fbox, which, however, as a macro does not accept verbatim material as argument. So the listing has to by typesetted in an lrbox first.

Alternatively, some framing environment may be used (in the example below I use adjustbox, but you literally have dozens of possibilities here), which would not require the detour over an lrbox.

Finally (not presented below) you my define your own PASCAL environment with \lstnewenvironment{PASCAL}{<begin code>}{<end code>} (see listings documentation) that combines either method with the listings environment to gain maximum comfort.

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{listings}

\usepackage{adjustbox} % For Option 2 only

\begin{document}
  \lstset{numbers=left, numberstyle=\small, numbersep=8pt, language=Pascal}

% Option 1: Typeset in an LR-box and use \fbox{} to draw the frame 
\newsavebox{\Lst}

\begin{lrbox}{\Lst}
\begin{lstlisting}
PROGRAM afficher_bonjour; 
BEGIN WRITE('Bonjour'); 
END.
\end{lstlisting}
\end{lrbox}

% draw frame an Listing. The \hskip enlarges the box to have numbers within the frame
\noindent\fbox{\hskip15pt\usebox{\Lst}}

% Option 2: Use some framing environment. There are lots of possibilities!
% I have just use adjustbox, which is a kind of swiss army knife for boxing
\begin{adjustbox}{padding=15pt 0pt 0pt 0pt, fbox}
\begin{lstlisting}
PROGRAM afficher_bonjour; 
BEGIN WRITE('Bonjour'); 
END.
\end{lstlisting}
\end{adjustbox}

\end{document}

enter image description here

Daniel
  • 37,517