19

I have a problem with a lstlisting environment. I want to use it for displaying several very long lines that can not be reformatted. Independently of the option breakatwhitespace=true or false my lines are not broken down so that the end is far outside of the printable area.

How to specify that line breaks are allowed at any character? Or is it possible to specify the characters (besides whitespace) that can be used for a line break?

Alternative: inserting a special (not-printed) character that indicates "break line here" - doe something like this exists?

\begin{lstlisting}[]
Test1: 33b7a2f7c4cc93c46dd4ee2ed81aa1eb-9409135542c79d1ed50c9fde07fa600a_cce5a2fe76bfbd0c48d79fb43a7106f0_263e9a8711c1400fb2a716a1b820ac9a
Test2: 33b7a2f7c4cc93c46dd2423423423423-9409135542c79d1ed50c9fde07fa600a_cce5a2fe76bfbd0c48d79fb43a7106f0_263e9a8711c1400fb2a716a1b820ac9a
\end{lstlisting}

Update:

The answer from egreg works fine. Additionally I found a different approach which works directly with a lstlisting environment:

\begin{lstlisting}[breakatwhitespace=true, literate={\-}{}{0\discretionary{-}{\\}{}}]
  ...
\end{lstlisting}

It allows to break the lines also at hyphenations. It has some drawbacks especially that the line breaks are looking different from the others in the environment. But may be for others this code may be helpful...

Found here: LaTeX: Lstinline and Hyphenations

1
  • 3
    As per the documentation \lstset{breaklines=true,breakatwhitespace=false} should have worked, but don't seem to me for some reason. Nov 2, 2011 at 15:28

4 Answers 4

13
\begin{lstlisting}[language=TeX,breaklines]
...
\end{lstlisting}

works, depending however on the language used. For instance, with TeX as language.

Another solution, similar to the one proposed by projetmbc is

\makeatletter
{\obeylines\gdef\bt@eol{^^M}}
\newenvironment{breakabletexttt}
  {\ttfamily\hfuzz=0.4em
   \list{}{\leftmargin=2em
           \itemindent=-\leftmargin
           \listparindent=-\leftmargin
           \parsep=0pt}
   \item\relax\obeylines\breakable@texttt}
  {\endlist}
\def\breakable@texttt#1{%
  \ifx#1\end
  \expandafter\end
  \else
    \expandafter\ifx\bt@eol#1%
      #1%
    \else
      \string#1\hskip1sp
    \fi
    \expandafter\breakable@texttt
  \fi}
\makeatother

Then

\begin{breakabletexttt}
<long line 1>
<long line 2>
...
\end{breakabletexttt}

will print the lines breaking them when at the right margin. The \hfuzz=0.4em allows at most one character to stick out (the line width should be made an integer multiple of the monospaced font characters, or a flexible space should be added between characters instead of \hskip1sp).

EDIT: the following variant will respect spaces

\makeatletter
{\obeylines\gdef\bt@eol{^^M}}
\newenvironment{breakabletexttt}
  {\ttfamily\hfuzz=0.4em
   \list{}{\leftmargin=2em
           \itemindent=-\leftmargin
           \listparindent=-\leftmargin
           \parsep=0pt}
   \item\relax\obeylines\obeyspaces\expandafter\breakable@texttt\@gobble}
  {\endlist}
\def\breakable@texttt{\futurelet\@let@token\breakable@texttti}
\def\breakable@texttti#1{%
  \ifx\@let@token\end
  \expandafter\end
  \else
    \expandafter\ifx\bt@eol\@let@token
      \par
    \else
      \string#1\hskip1sp
    \fi
    \expandafter\breakable@texttt
  \fi}
\makeatother

It's important to code as

\begin{breakabletexttt}
line
...
\end{breakabletexttt}

with a new line after the \begin.

6
  • 4
    Bizarre that it needs a language=TeX setting to break lines. How would you do this if you had some other language language=Java Nov 2, 2011 at 15:31
  • 1
    @PeterGrill I believe it depends on the routines to check for keywords. With Java it doesn't work.
    – egreg
    Nov 2, 2011 at 15:42
  • @egreg: Using this code all existing spaces in my code are gone
    – Robert
    Nov 3, 2011 at 16:12
  • @Robert See edit
    – egreg
    Nov 3, 2011 at 18:29
  • @egreg: Is there a way to make this environment work with all types of characters (tabs, curly brackets, underscores, ...)?
    – Robert
    Nov 8, 2011 at 9:21
2

I give you one partial solution given to me here. The problem is that it does not work with special character like _. One partial solution is to change locally the catcode of _.

I've asked one question about this so as to automatiser automate this here.

% Source : http://forum.mathematex.net/latex-f6/forcer-le-retour-a-la-ligne-dans-texttt-t13246.html#p127511

\documentclass{article}
    \makeatletter
        \newcommand\breakabletexttt[1]{\texttt{\breakable@texttt#1\@nil}}
        \def\@gobble@fi#1\fi{\fi#1}
        \def\breakable@texttt#1#2\@nil{%
            #1\hspace{0pt plus 0.1pt minus 0.1pt}%
            \ifx\relax#2\relax
            %
            \else
            \@gobble@fi\breakable@texttt#2\@nil
            \fi
        }
    \makeatother


\begin{document}

\catcode`_=11
\breakabletexttt{33b7a2f7c4cc93c46dd4ee2ed81aa1eb?9409135542c79d1ed50c9fde07fa600a?cce5a2fe76bfbd0c48d79fb43a7106f0?263e9a8711c1400fb2a716a1b820ac9a}
\catcode`_=8        

\end{document}

Finally, here is one possible solution :

% Sources : 
%   * http://forum.mathematex.net/latex-f6/forcer-le-retour-a-la-ligne-dans-texttt-t13246.html#p127511
%   * https://tex.stackexchange.com/questions/33465/changing-the-catcode-of-in-one-command

\documentclass{article}
    \makeatletter
        \newcommand\breakabletexttt{\begingroup\catcode`\_12 \breakabletexttt@i}
        \newcommand\breakabletexttt@i[1]{\texttt{\breakable@texttt#1\@nil}\endgroup}
        \def\@gobble@fi#1\fi{\fi#1}
        \def\breakable@texttt#1#2\@nil{%
            #1\hspace{0pt plus 0.1pt minus 0.1pt}%
                \ifx\relax#2\relax
            \else
                \@gobble@fi\breakable@texttt#2\@nil
            \fi
        }
    \makeatother


\begin{document}


\breakabletexttt{33b7a2f7c4cc93c46dd4ee2ed81aa1eb?9409135542c79d1ed50c9fde07fa600a?cce5a2fe76bfbd0c48d79fb43a7106f0?263e9a8711c1400fb2a716a1b820ac9a}

\end{document}
2
  • It chokes on _.
    – egreg
    Nov 2, 2011 at 15:29
  • I've given one partial solution.
    – projetmbc
    Nov 2, 2011 at 16:00
2

I tried the solution in the update to the question but that didn't work when I tried it in a \lstset (it didn't compile). Afer a little searching, I came up with this and it seems to do the trick:

\lstset{various options,
        breaklines=true,
        literate={\-}{}{0\discretionary{-}{}{-}},
        various other options}
1

In addition to the other answers, I'd like to share what I came up with when trying to answer a similar question asked on the LaTeX IRC channel. Defining a new environment for just breaking code lines at arbitrary points seems a bit unfortunate, as you lose all the nice extra features the listings package provides.

As mentioned in the comments to earlier answers, line breaking seems to depend on the listing's language setting. So it seems natural to just define a new, plain language style, without any keywords and such, which can break lines at arbitrary characters.

I couldn't find out how listings exactly determines possible line break positions. From playing with the alsoletter/alsodigit/alsoother options, it seems that breaks are allowed only at the boundary of two different character classes; sequences of characters of the same class will never be broken, apparently. This means that we cannot use those options to define a new style but have to (mis)use the literate trick instead:

\documentclass{article}

\usepackage{listings}
\usepackage{xcolor}

\makeatletter
\def\@tempA#1#2\@end{%
    \@tempA@{#1}%
    \ifx\relax#2\relax
    \else
        \@tempA#2\@end
    \fi
}
\def\@tempA@#1{{\noexpand#1}{{\char`\noexpand#1 \allowbreak}}1 }
\edef\@tempB{\noexpand\lstdefinelanguage{logfile}{%
    columns=fixed,%
    keepspaces=true,%
    breaklines=true,%
    literate=\@tempA 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!()*+,-./:;<=>?@[]_|`^"'\&\$\\\~\#\%\{\}\@end
}}
\@tempB
\makeatother

\begin{document}

\newlength\lstbasewidth
\settowidth\lstbasewidth{\ttfamily\small X}
\lstset{
    basicstyle=\ttfamily\small,
    language=logfile,
    breakindent=4\lstbasewidth,
    basewidth=\lstbasewidth,
    postbreak=\llap{\scriptsize\textcolor{blue}{$\hookrightarrow$}\kern0.25em}
}

\begin{lstlisting}
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./
0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123456789:;<=>?
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
\end{lstlisting}

\end{document}

Output

output

The example defines new language style logfile (showing log files with long lines in it was what was originally asked for in the channel). The idea is quite simple: Map each printable character x to an entry {x}{{\char`x \allowbreak}}1 in the literate option list. To avoid a lot of boilerplate code, we use the \@tempA macro that traverses a list of characters and expands each to the given entry format, and \@tempB to finally define the new style with the fully expanded entry list.

The setup that happens in the document body just adds some visual indications where line breaks happened, with arrows and a fixed indentation width of 4 characters. Note that the style hasn't been tested well yet, especially in conjunction with different packages or extended character sets.

1
  • Thanks! I just had this issue and went through all the answers, but only yours solved it for me! Sep 27, 2020 at 20:31

You must log in to answer this question.

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