Thank you Branden for those historical insights.
Off-topic to Alejandro's initial question but related to the subject of
justifying text set in monospace, do we owe this typographic gesture to
the early *roff formaters or was it already a thing in previous
publication tool, either software or hardware ?
Are you aware of theory or paper on the subject ?
Martin
Le Fri, May 02, 2025 at 07:01:39AM -0500, G. Branden Robinson a écrit :
> Hi Alex,
>
> At 2025-05-02T12:56:51+0200, Alejandro Colomar wrote:
> > I'd like to understand why groff(1) formats differently a paragraph
> > depending on the previous ones. I sometimes experience different
> > placement of spaces for an unchanged paragraph. I use a script to
> > diff manual pages at different commits, which is useful to quickly see
> > the effects of a commit in a formatted page. That script sometimes
> > shows suprious space changes (produced by groff(1)) for parts of the
> > page that haven't been changed, and which one would expect should not
> > be formatted differently.
>
> What you're observing is an artifact of the adjustment process that pads
> out filled text lines to a consistent width. It's a feature of *roff
> formatters going back essentially forever--as in, to the early 1970s.
>
> And it is indeed not a man page-specific phenomenon.
>
> groff_diff(7) briefly mentions it:
>
> When adjusting output lines to both margins, AT&T troff at first
> adjusts spaces starting from the right; GNU troff begins from the
> left. Both implementations adjust spaces from opposite ends on
> alternating output lines in this adjustment mode to prevent
> “rivers” in the text.
>
> Some typography people refer to this practice as achieving "uniform
> grayness". Imagine your eyes defocused so that the text of a printed
> page is a smear of gray--if every line were supplemented with space
> favoring either the left or right side, you would perceive the opposite
> side as being "blacker". As far as I understand the concept, not being
> a trained typographer, it's the same thing, or tautologically related.
> Rivers create anisotropies in your grayness.
>
> I have proposed the term "adjustment parity", a property that tells you
> whether an output line requiring adjustment gets adjusted from the left
> or the right. Roughly, if you change filled text in a *roff document
> that uses adjustment such that you add or delete an _even_ number of
> lines, the adjustment of subsequent lines won't change. If you add or
> delete an odd number of lines, it will. However, that's a *truly* rough
> statement because a change prior to groff 1.23.0 made GNU troff ignore,
> for purposes of adjustment parity, lines that don't get adjusted at all.
> I'll put some more background in a footnote.[1]
>
> When diffing changes to man pages for the groff and ncurses projects
> (and occasional others to which I contribute), I disable adjustment when
> rendering the pages before and after, using the `-d AD=l` option.
>
> groff_man(7):
>
> Options
> The following groff options set registers (with -r) and strings
> (with -d) recognized and used by the man macro package. To ensure
> rendering consistent with output device capabilities and reader
> preferences, man pages should never manipulate them.
>
> -dAD=adjustment‐mode
> Set line adjustment to adjustment‐mode, which is typically
> “b” for adjustment to both margins (the default), or “l”
> for left alignment (ragged right margin). Any valid
> argument to groff’s “.ad” request may be used. See
> groff(7) for less‐common choices.
>
> As you can see, I turn off adjustment when pasting man page contents
> into emails as well.[2]
>
> For example, the script I use to diff groff man pages before pushing a
> set of commits has this stuff in it.
>
> BFLAG=
> #BFLAG=-b
> ...
> : ${AD:=l}
> ...
> ARGS="$BFLAG -ww -dAD=$AD -rCHECKSTYLE=3 -rU1 -Tutf8 -e -t -mandoc"
> ...
> for P in *.[157]
> do
> if [ "$P" = groff_mmse.7 ]
> then
> LOCALE=-msv
> else
> LOCALE=
> fi
>
> echo $0: $P >&2
> echo "groff $ARGS $LOCALE $P" > "$P.cR.txt"
> groff $ARGS $LOCALE "$P" >> "$P.cR.txt"
> ...
> done
>
> I then diff(1) the ".cR.txt" file I saved from my last push
> (corresponding to "origin/master") to the tip of the trunk.
>
> I will point out something about your diff, though.
>
> > @@ -118,11 +130,11 @@ .SH DESCRIPTION
> > this operation yields an
> > .B EINVAL
> > error.
> > -.RE
> > .IP
> > -Since Linux 6.7, using this subcode requires the
> > +Since Linux 6.7, using this selection mode requires the
> > .B CAP_SYS_ADMIN
> > capability.
> > +.RE
> > .TP
> > .BR subcode = TIOCL_PASTESEL
> > Paste selection.
>
> This change involving movement of the `RE` macro call can potentially
> change the output as well.
>
> > There are several paragraphs which shouldn't report changes: every
> > paragraph that doesn't start with "Since Linux 6.7," should be
> > unchanged.
>
> ...unless the moved `RE` call creates a surprise.
>
> > Is this a bug? Is it a feature?
>
> It's a feature. Some people do hate adjustment of nroff output, though,
> which is why I added a feature to groff man(7) to support disabling it.
>
> The history of this practice is inconsistent. Seventh Edition Unix
> (1979) disabled adjustment of man pages when rendering in nroff mode,[3]
> and BSD retained that disablement until death. SunOS commented it as
> early as SunOS 2.0 (1985), thus restoring adjustment in nroff mode, and
> retained that all the way through Solaris 10 (2005). When James Clark
> wrote groff starting in about 1989, his man(7) implementation closely
> emulated SunOS. With the Solaris 11 release in 2010, Oracle discarded
> its AT&T-descended troff in favor of the then-current groff release.
> They're still on groff 1.22.2 (2013) today, and so they've been
> adjusting their man pages in nroff mode for at least 40 years, as has
> groff for about 35). I don't know what other System V Unices did.
>
> Some people have lobbied me to turn the default for adjustment off in
> nroff mode for man pages, but I've resisted, in part for consistency
> with groff's own entire history and the expectations of the once large
> (but now aging) population of Sun Unix users, but also because I feel
> that groff's defaults in nroff mode should be as similar to troff mode
> as practical, to minimize surprises when switching among output devices.
>
> As of groff 1.23.0 (2023) the default adjustment setting in groff man(7)
> (and mdoc(7)) is completely under user control.
>
> Regards,
> Branden
>
> [1]
>
> commit 69efbe0a69a8e7de8904d78e3de8c7e8a58a8b92
> Author: G. Branden Robinson <[email protected]>
> Date: Sat Sep 4 23:20:54 2021 +1000
>
> [troff]: Don't adjust nonadjustable lines.
>
> This means that the direction from which an output line in adjustment
> mode "b" (or its "n" synonym) is filled with supplemental space is not
> changed if that output line does not require adjustment. This will
> result in whitespace changes to documents using that adjustment mode,
> and these changes will be plainly visible on low-resolution output
> devices like terminals.
>
> To illustrate, in the following "A" means an output line requiring
> adjustment; "F" a line that is "full" and does not; and "L" and "R"
> indicate distribution of adjustment spaces from the left and right,
> respectively.
>
> groff 1.22.4 groff 1.23.0
> ------------ ------------
> A L A L
> A R A R
> F L F R
> A R A L
>
> * src/roff/troff/env.cpp (distribute_space): Return early if either the
> amount of desired space to be distributed or the count of space nodes
> in the output line to distribute it among is zero.
>
> * tmac/tests/an_TH-repairs-ad-damage.sh: Update test to expect space to
> be distributed differently.
>
> Fixes <https://savannah.gnu.org/bugs/?61089> and
> <https://savannah.gnu.org/bugs/index.php?60673>.
>
> [2] $ type mailman
> mailman is a function
> mailman ()
> {
> local cmd=;
> case "$1" in
> -*)
> opts="$opts $1";
> shift
> ;;
> esac;
> set -- $(man -w "$@");
> cmd=$(zcat --force "$@" | grog -Tutf8 -b -ww -P -cbou -rU0 -rLL=72n
> -rHY=0 -dAD=l $opts);
> zcat --force "$@" | $cmd | less
> }
>
> [3] https://minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/lib/tmac/tmac.an
>
> Also see variously:
>
> https://minnie.tuhs.org/cgi-bin/utree.pl?file=32V/usr/lib/tmac/tmac.an
>
> https://minnie.tuhs.org/cgi-bin/utree.pl?file=3BSD/usr/lib/tmac/tmac.an.new
>
> https://minnie.tuhs.org/cgi-bin/utree.pl?file=4BSD/usr/lib/tmac/tmac.an.new
>
> https://minnie.tuhs.org/cgi-bin/utree.pl?file=4.3BSD/usr/lib/tmac/tmac.an.new
>
> https://minnie.tuhs.org/cgi-bin/utree.pl?file=4.3BSD-Tahoe/usr/lib/tmac/tmac.an.new
>
> https://minnie.tuhs.org/cgi-bin/utree.pl?file=4.4BSD/usr/share/tmac/tmac.groff_an