groff
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: breaks and the no-break control character


From: G. Branden Robinson
Subject: Re: breaks and the no-break control character
Date: Fri, 5 May 2023 13:24:55 -0500

At 2023-05-04T20:21:01-0500, Dave Kemper wrote:
> Discussion about the request invocation 'br in
> http://savannah.gnu.org/bugs/?62776#comment14 made me also wonder
> about 'sp, another seemingly paradoxical invocation.  But like 'br,
> this seems clearly enough documented in the info manual:
> 
> "Several other requests imply breaks: ... 'sp', ....  If the no-break
> control character is used with any of these requests, GNU 'troff'
> suppresses the break; instead the requested operation takes effect at
> the next break."
> 
> However, the actual effect is perhaps not quite what one would expect
> from reading this:
> 
> $ cat sp.test
> Foo.
> .sp 2
> Bar.
> .pl \n(nlu
> $ nroff -ww sp.test
> Foo.
> 
> 
> Bar.
> $ sed "s/^\\.sp/'sp/" sp.test | nroff -ww
> 
> 
> Foo.  Bar.
> $

Yes.  Forgetting that you didn't post this as a ticket comment and
unable to find it, I came up with my own very similar reproducer.

$ cat sp-with-and-without-break.roff
foo
.sp 2
bar
.br
baz
'sp 2
qux
.pl \n(nlu
$ DWBHOME=. ./bin/nroff sp-with-and-without-break.roff 
foo


bar


baz qux
$

As you might have guessed, that's DWB 3.3 nroff output.  groff's is the
same.

> The first run produces unsurprising results.  What the second seems to
> show is that groff detects a break (presumably upon EOF, since .pl
> doesn't cause one), then processes the queued sp request, and only
> THEN flushes its pending output.  This is the opposite of what I would
> have assumed upon reading "the requested operation takes effect at the
> next break," since in my mental conception, part of what constitutes a
> "break" is outputting pending text.  But I suppose technically "at the
> next break" is ambiguous about whether any queued request(s) happen(s)
> before or after the break itself.
> 
> Does this behavior surprise anyone else?  (Heirloom troff does the
> same thing.)  Does anyone else think these sentences in the manual
> don't capture the nuance of the situation?  And does that even matter,
> given that "'sp" is kind of a weird thing to say anyway?

It _did_ surprise me.  My first inclination was to propose yet another
radical reform, because my mental model was that because breaking
implies moving the drawing position down by one vee anyway (and
performing the device's equivalent of a carriage return), then "'sp N"
should move the drawing position down by N-1 vees.  This would break
compatibility with other troffs, and with respect to such a fundamental
formatting operation (albeit a dusty corner of _syntax_) that even I
hesitated.

But there may be an easier way to explain/rationalize this.

We already say this in our Texinfo manual:

  Output line properties like page offset, indentation, and adjustment
  are not determined until the line has been broken.

(...and someday we should say it in roff(7) or groff(7), too.)

We can assert that the position of the text baseline is one of those
properties of the output line that is not determined until the line has
been broken.  And what the `sp` request really does is decide where your
next text baseline is going to be.

This even begins to make sense to me when I consider that a common
operation in non-man-page typesetting is the placement of superscripts
and subscripts.  In mathematical typography particularly, these can be
chained.  The me(7) package has explicit support for growing the height
of the output line--in other words, moving the text baseline down--to
accommodate the placement of glyphs that would crowd the ordinary 1v of
distance between text baselines.  And further, the "height of a text
line" is a formally complex piece of machinery, with several different
elements that ultimately construct it.

Buried under the description of `vs` request in our Texinfo manual is
the following disquisition.

  When a break occurs, GNU 'troff' performs the following procedure.

     * Move the drawing position vertically by the "extra pre-vertical
       line space", the minimum of all negative '\x' escape sequence
       arguments in the pending output line.

     * Move the drawing position vertically by the vertical line
       spacing.

     * Write out the pending output line.

     * Move the drawing position vertically by the "extra post-vertical
       line space", the maximum of all positive '\x' escape sequence
       arguments in the line that has just been output.

     * Move the drawing position vertically by the "post-vertical line
       spacing" (see below).

     Prefer 'vs' or 'pvs' over 'ls' to produce double-spaced documents.
  'vs' and 'pvs' have finer granularity than 'ls'; moreover, some
  preprocessors assume single spacing.  *Note Manipulating Spacing::,
  regarding the '\x' escape sequence and the 'ls' request.

We seem to have an ugly bit of non-orthogonality in this area.

quantity                                register access

extra pre-vertical line spacing         n/a
vertical (line) spacing                 .v
extra post-vertical line spacing        .a
post-vertical line spacing              .pvs

Also I'm not convinced of the accessibility of the terminology in use.

If I want to know within an output line how much my line's already been
jacked by some tetration-wielding naïf who hasn't learned Knuth's
up-arrow notation, apparently in groff I'm SOL.

Hmm, in DWB 3.3 troff too.  Apparently `.a` is not updated until _after_
the line is output.

Okay, I think I see how this was supposed to work now.  Since the
addition of pre- and post- line spacing with \x was already using
saturating arithmetic[1] in both directions (above = negative, below =
positive), you didn't really _need_ to be able to access these
quantities on the same output line; just demand what you needed with
`\x` and let the formatter do its thing.

_But_, when typesetting adjacent lines that resort to extra line
spacing, then extra post-line spacing on line N might mean that you
don't need as much, or even _any_, or line N+1: you will already have
"headroom" for your tetrated superscripts or giant brackets, assuming
the glyphs from the two different lines don't outright collide.[2]

Thanks for the trip down the rabbit hole, Dave--I'll have my revenge. ;)

More seriously, our documentation should do more to motivate the
existence of these features.

Regards,
Branden

[1] possibly an abuse of terminology
[2] which we should be able to detect and warn about since we know where
    all the glyph bounding boxes are on the page[3]
[3] On the gripping hand I've heard that collision detection is not
    necessarily a trivial problem--I'm not sure; I never did video games
    or simulators for robots.  I think I had something isomorphic to
    this problem in an interview once.  I remember it involved
    unbounded resolution (i.e., there was no limit to how finely you
    could partition the space to look for intersections/collisions, so
    there was no brute-force approach).  After drawing some sketches and
    describing in limited terms my grasp of binary space partitioning, I
    ventured my suspicion that it was intractable or an open problem in
    computer science, and didn't get the job.  If I'd been more glib
    maybe I'd have said something about Hilbert curves.

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]