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
signature.asc
Description: PGP signature
