At 2025-11-21T20:28:49+0100, onf wrote:
> there seems to be an off by one bug in sv's geometry in groff.
> 
> Given the input,
>   .de x
>   . br
>   ..
>   .wh 2v x
>   Lorem
>   .br
>   .sv 1v
>   ipsum
>   .br
>   dolor
> 
> groff gives the output
>   Lorem
>   ipsum
>   dolor
> 
> whereas both Heirloom troff and Plan 9 troff give
>   Lorem
> 
>   ipsum
>   dolor
> 
> Groff gives the same output when the wh line is
> changed to
>   .wh 2v+1u x
> 
> (in troff mode; in nroff mode, +1v is needed due to lower resolution)

Strictly, +0.5v plus 1 motion quantum should do the trick.  At least it
does for me (approximating "one motion quantum" as ".03v").

groff(7):
   Motion quanta
       An output device’s basic unit u is not necessarily its smallest
       addressable length; u can be smaller to avoid problems with
       integer roundoff.  The minimum distances that a device can work
       with in the horizontal and vertical directions are termed its
       motion quanta, stored in the .H and .V registers, respectively.
       Measurements are rounded to applicable motion quanta.  Half‐
       quantum fractions round toward zero.

$ grep vert font/devutf8/DESC.proto
vert 40

1/40 = 0.025 ≅ 0.03

At 2025-11-23T22:13:29+0100, onf wrote:
> Actually, CSTR #54 does not specify what should happen when sv's
> argument equals distance to next trap:
>   .sv N
>       Save a contiguous vertical block of size N. If the distance to the
>       next trap is greater than N, N vertical space is output. No-space
>       mode has no effect. If this distance is less than N, no vertical
>       space is immediately output, but N is remembered for later output
>       (see os). Subsequent sv requests will overwrite any still
>       remembered N.
> 
> Groff's documentation explicitly defines ne's geometry as equivalent to
> that of sv. However, notice the justification for ne's behavior in CSTR
> #54:
>   .ne N
>       [...] If the distance D to the next trap position [...] is less
>       than N, a forward vertical space of size D occurs, which will
>       spring the trap. [...] If D < V, another line could still be
>       output and spring the trap. [...]
> 
> In other words, the reason that ne does nothing when .t == N is because
> another line can fit in before the trap will be sprung.

That makes sense.

> However, in sv's case, what we're interested in is whether the given
> SPACE can fit in before springing the trap, not some text, so in that
> case we need the opposite behavior.

Hmmm.  That seems plausible.

The questions I have are:

* If we've broken compatibility with AT&T troff in this regard, what has
  that cost us?  What exhibits of `sv` and `os` usage in practical
  documents can we lay our hands on?  It may be that `sv` and `os` were
  developed first, and then someone noticed that `sv` was being used a
  lot without any `os` subsequently, so `ne` was created.  Just a guess.

* What's more conceptually consistent?  To have `ne` do the exact same
  computation as `sv`, or not?

* Do we want to make groff's compatibility mode work like AT&T troff in
  this respect, even if we don't conform in non-compatibility mode?  If
  so, this would become an example of an "engine level", rather than a
  syntactical, behavior change to which I recently referred.[1]

The most important question to me is the first.  If someone can show me
a practical (preferably historical) document that renders correctly with
AT&T troff but not with groff, I'm inclined to give that a lot of
weight.

Without such an exhibit, I don't see this issue as demanding resolution
in the short term.  (At the moment, I'm kind of preoccupied with cutting
a release candidate of groff 1.24.0.)

Regards,
Branden

[1] https://lists.gnu.org/archive/html/groff/2025-12/msg00012.html (fn3)

Attachment: signature.asc
Description: PGP signature

Reply via email to