11

When a monospace segment is used within an otherwise variable-width justified paragraph, very often the monospaced part is wrapped "one word too late", resulting in many lines being overfull hboxes.

There are already a few questions regarding text breaking in \texttt, but all of them were solved with hyphenation, which is not what I want here. There is ample chance for line breaks at whitespace and indeed LaTeX selects one, it just isn't the correct one.

MWE (set this in LuaLaTeX - the others have the same problem, but since it is font dependent, it might be at slightly different positions):

\documentclass[english]{article}
\usepackage{fontspec}
\usepackage{microtype}
\usepackage{lipsum}
\begin{document}
Run a command: \texttt{python3 ../install\_path/script.py -{}-arg foo -{}-another parameter {*}.txt}, then continue.

\lipsum[1][1-4]
\begin{flushleft}
Run a command: \texttt{python3 ../install\_path/script.py -{}-arg foo -{}-another parameter {*}.txt}, then continue.
\par\end{flushleft}
\end{document}

Resulting layout, with Lorem Ipsum to show the paragraph width. Notice how --another should be on the second line and there is no reason not to wrap after foo. In flushleft in paragraph 3, that actually works as expected: LuaLaTeX output

It is theoretically possible to go through the document and fix every single instance with manual breaks, and then redo that whenever anything at all changes. There are however a lot of them and I don't really want to do that. Basically, I want all \textt to be wrapped at whitespace without overflowing the line. I suspect one way could be done by defining a "local sloppyness", but I don't know how to do that to test.

Thank you for your time.


I feel I should clarify one thing: I'm well aware that variable spaces in a monospaced font are... unconventional. The monospace font is used for visual distinction here, not to actually properly align. I use listings for that, don't worry.

3
  • To be entirely honest I would put the codes on separate lines, and maybe using some dedicated package. That's much easier to read than having something like --another going into the second line.
    – campa
    Jun 9, 2021 at 17:43
  • 2
    Is breaking those texttt portions at any character OK, or do you insist on breaking at spaces or hyphenation patterns? p.s. sloppypar environment may be an option Jun 9, 2021 at 18:53
  • @StevenB.Segletes I want to break only at spaces. I don't use automatic hyphenation, so that's not an issue either way. \sloppy is good, but it means I have to know in advance that there will be a problem... I don't really like special-casing things too much if it can be avoided.
    – Martok
    Jun 9, 2021 at 20:02

3 Answers 3

9

Locally set \spaceskip to a flexible value. Monospaced fonts usually have rigid interword space, for good reasons. But TeX has the built-in method for overriding the value in the metric file (or, in this case, the OpenType/TrueType font).

Allowing a small \hspace before the content helps move some of the required spacing out of the code section itself.

\documentclass{article}
\usepackage{fontspec}
\usepackage{microtype}
\usepackage{lipsum}

\newcommand{\inlinecode}[1]{%
  \texttt{%
    % set flexible interword space
    \setlength{\spaceskip}{0.5em plus 1em minus 0.1em}%
    % add some space with not as much flexibility, but only
    % if some space precedes
    \ifdim\lastskip>0pt \unskip\hspace{0.5em plus 0.5em minus 0.1em}\fi
    #1
  }%
}

\begin{document}

Run a command: \inlinecode{python3 ../install\_path/script.py --arg foo --another parameter *.txt}, then continue.

\lipsum[1][1-4]

\inlinecode{Some code, but no initial space}

\texttt{Some code}

\end{document}

enter image description here

By the way, you don't need -{}- nor {*}.

3
  • That is pretty straightforward and achieves exactly what I intended, thank you! I have queued an edit for one additional feature I added after some testing: Allowing a \hspace as in Steven's answer below at the start of the block allows TeX to offset the \inlinecode from normal text and use less space within the code. It barely changes the example I posted, but looks cleaner in my working document. If not required, it is simply collapsed.
    – Martok
    Jun 9, 2021 at 22:07
  • @Martok I took the advice, but changed the proposal: you want to add space only if some space before \inlinecode already exists.
    – egreg
    Jun 9, 2021 at 22:08
  • True, that didn't even occur to me.
    – Martok
    Jun 9, 2021 at 22:10
3

There is a reason not to break at that point, to do so would require stretching inter-word space than the user-setable limits allow. This is your choice, not anything forced by latex.

If you allow inter-word spacing to stretch more, for example using \sloppy then it breaks where you wanted

Note that it is the inter-word spacing at the start of the line, in the non monospace text that needs to stretch here.

enter image description here

\documentclass[english]{article}
\usepackage{fontspec}
\usepackage{microtype}
\usepackage{lipsum}
\begin{document}
{\sloppy
Run a command: \texttt{python3 ../install\_path/script.py -{}-arg foo -{}-another parameter {*}.txt}, then continue.

\lipsum[1][1-4]

}
\begin{flushleft}
Run a command: \texttt{python3 ../install\_path/script.py -{}-arg foo -{}-another parameter {*}.txt}, then continue.
\par\end{flushleft}
\end{document}
5
  • But why not use the sloppypar environment? Then, it's not necessary to remember that blank line. (Without which, what you suggest won't work the way one expects.) Jun 9, 2021 at 20:23
  • \spaceskip...
    – egreg
    Jun 9, 2021 at 20:33
  • @egreg sure (I'm assuming the monospace wants a fixed space, otherwise why use monospace) but xspace in the tt region is a possibility as are several less sloppy alternatives to sloppy. Main point here is that latex soes not "break somewhere for no reason" Jun 9, 2021 at 21:22
  • @DavidCarlisle What I meant was that it doesn't break even if there is a reason (the line is full). I think the accepted method looks better in my document, but what I originally had in mind was something like "allow a ragged right side, but only if it is required to wrap a certain TT group, keep lines before and after justified". Is this possible?
    – Martok
    Jun 10, 2021 at 11:20
  • 1
    TeX does a least cost optimisation over the paragraph, it only goes over-full if there is no feasible solution, in doing so the word spacing is preserved and in its eyes things are better than breaking and over-stretching the space (as you have specified how much stretch). To allow the line to break ragged before the tt section use \hspace{0pt plus 1fill}\linebreak[1]\hspace{0pt plus -1fill}\texttt{a b c} then if the line break doesn't happen no space is added but if it does you get fill space at the end of the line, then break then the negative space is discarded and you get tt. @Martok Jun 10, 2021 at 11:39
3

Here I encapsulate a tokcycle environment in the \strxtt macro, which adds stretchable glue at every space it encounters. In theory, you could \let\texttt\strxtt to avoid changing your document input.

The stretchable space is only inside the \strxtt material, and does not affect the spacing of surrounding text. In this regard. it differs from paragraph level solutions, such as \sloppy.

\documentclass[english]{article}
%\usepackage{fontspec}
\usepackage{microtype}
\usepackage{lipsum}
\usepackage{tokcycle}
\xtokcycleenvironment\stretchtt
  {\addcytoks{##1}}
  {\processtoks{##1}}
  {\addcytoks{##1}}
  {\addcytoks{ \hspace{0pt plus 2ex minus 2pt}}}
  {\ttfamily}
  {}
\newcommand\strxtt[1]{\stretchtt#1\endstretchtt} 
\begin{document}
Run a command: \strxtt{python3 ../install\_path/script.py -{}-arg foo -{}-another parameter {*}.txt}, then continue.

\lipsum[1][1-4]
\begin{flushleft}
Run a command: \texttt{python3 ../install\_path/script.py -{}-arg foo -{}-another parameter {*}.txt}, then continue.
\par\end{flushleft}
\end{document}

enter image description here

You must log in to answer this question.

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