Break lines at any character in minted

The code is set in a environment Verbatim of package fancyvrb. The breaklines feature is an addition of package minted. The overlong lines are processed in macro \FV@SaveLineBox. The example patches this macro to add support for normal hyphenation. In font \ttfamily the hyphenation is usually disabled via a negative \hyphenchar, see question "Hyphenate \ttfamily without hyphen dash".

With invisible hyphen (OT1 or T1 encoding):

\documentclass{article}
\usepackage{minted}
\usepackage{ragged2e}
\setminted{breaklines}
%\usepackage[T1]{fontenc}
%\usepackage{lmodern}

\usepackage{etoolbox}
\makeatletter
\patchcmd{\FV@SaveLineBox}{%
  \strut#1\strut
}{%
  \hyphenchar\font=%
    % Invisible hyphen:
    \if\expandafter\@car\f@encoding\relax\@nil O 255 \else 23 \fi
    % Visible hyphen:
    % `\- %
  \strut
  \nobreak % prevent line break by next \hspace
  \hspace{0pt}% allow hyphenation of first word
  #1%
  \nobreak % without the following \strut would prevent hyphenation of previous word
  \strut
}{}{%
  \errmessage{\noexpand\FV@SaveLineBox could not be patched}%
}
\makeatother

\begin{document}
\begin{minted}{xml}
<?xml version="1.0"?>
abracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraab
<project name="Package tcolorbox" default="documentation" basedir=".">
  <description>
    Apache Ant build file (http://ant.apache.org/)
  </description>
</project>
\end{minted}
\end{document}

Result with invisible hyphen

And with the visible hyphen (\hyphenchar\font=`\-):

Result with visible hyphen

Thus the solution does not break the lines at each character, but follows the hyphenation patterns of the current language.


Here's an approach that scans through each line and attempts to insert potential breaks at all possible locations, using \discretionary. Heiko Oberdiek's approach will probably be superior when the long strings are natural language and have existing hyphenation patterns. But it seems to allow at most one break, and doesn't break strings that mix letters and numbers. My approach will be more fragile if you are doing fancy things with verbatim, although the typical things (mathescape, etc.) seem to work.

All of the code is written as an extension of fancyvrb. A refined version of this code will probably go into the next version of minted and pythontex. Eventually, I plan to separate out this and other code into a package that extends and patches fancyvrb.

\documentclass[11pt]{article}

\usepackage[T1]{fontenc}

\usepackage{minted}
\setminted{style=default}

\makeatletter

%%%% First, a general solution for verbatim text, potentially with mathescape.
%%%% This doesn't allow breaks within macro args, because we can't know in
%%%% general (at least not without a lot of work) if a macro arg needs to be
%%%% left literal or have potential breaks inserted.
%%%% This reads a line into a temp macro, inserting potential break points.

%Characters inserted at break
\def\FancyVerbBreakChars{\discretionary{-}{}{}}

\def\FV@BreakAnywhere{%
  \def\FV@Tmp{}%
  \FV@BreakAnywhere@i
}

\def\FV@EndBreakAnywhere{\FV@Tmp}

\begingroup
\catcode`\$=3%
\gdef\FV@BreakAnywhere@i{%
  \@ifnextchar\FV@EndBreakAnywhere%
   {}%
   {\ifx\@let@token$\relax
      \let\FV@BreakAnywhere@Next\FV@BreakAnywhere@Math
    \else
      \ifx\@let@token\bgroup\relax
        \let\FV@BreakAnywhere@Next\FV@BreakAnywhere@Group
      \else
        \let\FV@BreakAnywhere@Next\FV@BreakAnywhere@Token
      \fi
    \fi
    \FV@BreakAnywhere@Next}%
}

\gdef\FV@BreakAnywhere@Math$#1${%
  \g@addto@macro{\FV@Tmp}{$#1$}%
  \FV@BreakAnywhere@i}
\endgroup

\def\FV@BreakAnywhere@Group#1{%
  \g@addto@macro{\FV@Tmp}{{#1}}%
  \FV@BreakAnywhere@i
}

\begingroup
\catcode`\a=11%
\catcode`\+=12%
\gdef\FV@BreakAnywhere@Token#1{%
  \ifcat\noexpand#1a\g@addto@macro{\FV@Tmp}{\FancyVerbBreakChars#1}%
  \else
    \ifcat\noexpand#1+\g@addto@macro{\FV@Tmp}{\FancyVerbBreakChars#1}%
    \else
      \g@addto@macro{\FV@Tmp}{#1}%
    \fi
  \fi
  \FV@BreakAnywhere@i
}
\endgroup

\patchcmd{\FV@SaveLineBox}%
 {\strut#1\strut}%
 {\strut\FV@BreakAnywhere#1\FV@EndBreakAnywhere\strut}%
 {}%
 {\errmessage{\noexpand\FV@SaveLineBox could not be patched}}


%%%% Next, a way to allow breaks in macro args.
%%%% This is needed for the Pygments style macros.
%%%% This is basically just a wrapper for what's already been defined,
%%%% used again as needed within macros.

\let\FancyVerbBreakAnywhereStart\FV@BreakAnywhere
\let\FancyVerbBreakAnywhereStop\FV@EndBreakAnywhere

% This assumes `default` Pygments style
% This needs `\setminted{style=default}` in the preamble, so that the
% style macros will already exist.
% Don't try breaks in Pygments `esc`apes, since they may contain 
% arbitrary LaTeX that my approach can't handle.
\let\OldPYG\PYGdefault
\def\PYGdefault#1#2{%
  \ifstrequal{#1}{esc}%
    {\OldPYG{#1}{#2}}
    {\OldPYG{#1}{\FancyVerbBreakAnywhereStart #2\FancyVerbBreakAnywhereStop}}}

\makeatother


\begin{document}


\begin{minted}[breaklines]{xml}
<?xml version="1.0"?>
abracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabra
<project name="Package tcolorbox" default="documentation" basedir=".">
<description>
Apache Ant build file (http://ant.apache.org/)
</description>
</project>
\end{minted}


\begin{minted}[breaklines]{xml}
<?xml version="1.0"?>
abracadabraabracadabra34534abracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabra34534abracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabra34534abracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabra
<project name="Package tcolorboxtcolorboxtcolorboxtcolorboxtcolorboxtcolorbox" default="documentation" basedir=".">
<description>
Apache Ant build file (http://ant.apache.org/)
</description>
</project>
\end{minted}


\begin{minted}[breaklines]{xml}
<?xml version="1.0"?>
abracadabraabracadabra34534abracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabra34534abracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabra34534abracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabraabracadabra
<project name="Package tcolorboxtcolorboxtcolorboxtcolorboxtcolorboxtcolorboxtcolorbox" default="documentation" basedir=".">
<description>
Apache Ant build file (http://ant.apache.org/)
</description>
</project>
\end{minted}

\end{document}

Here is the original code block:

enter image description here

And here is the code with a much longer first string that mixes letters and numbers. One of the strings in the project tag is also longer, but since there is a space, it can still fit onto one line after a normal break.

enter image description here

Now the string in the project tag is so long that it must be broken between characters.

enter image description here


Minted provides such break by breaksymbol = =\small\carriagereturn. This breaksymbol defines the symbol to break. So you can use this symbol where ever you want a break. For example, we use carriage return. You can put a carriage return the place you want a break.

\usepackage{minted}
\usepackage{dingbat}

\begin{document}

\begin{minted}[breaklines, breaksymbolleft=\carriagereturn]{xml}
<?xml version="1.0"?>
abracadabraabracadabraabracadabr
aabracadabraabracadabraabracadab
raabracadabraabracadabraabracada
braabracadabra
<project name="Package tcolorbox" default="documentation" basedir=".">
<description>
Apache Ant build file (http://ant.apache.org/)
</description>
</project>
\end{minted}
\end{document}

Tags:

Minted