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}
And with the visible hyphen (\hyphenchar\font=`\-
):
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:
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.
Now the string in the project
tag is so long that it must be broken between characters.
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}