bug-groff
[Top][All Lists]
Advanced

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

[bug #64212] [PATCH] give troff a string register naming the next trap


From: G. Branden Robinson
Subject: [bug #64212] [PATCH] give troff a string register naming the next trap
Date: Thu, 18 May 2023 17:51:01 -0400 (EDT)

Follow-up Comment #2, bug #64212 (project groff):

[comment #1 comment #1:]
> [comment #0 original submission:]
> > if, somehow, there is no next trap at the top level, but
> > that...should be impossible?
> 
> The info documentation for \n[.t] thinks it's possible: "If there are no
traps between the current position and the bottom of the page, it contains the
distance to the page bottom."

Right.  Sorry, I wasn't clear about this; the internal page-bottom trap always
exists, but it has no name.

Consider the following.


$ cat ./EXPERIMENTS/dot-t-within-trap.groff
.de TT
.tm trap: $0=\\$0, .t=\\n(.t, .trap=\\n[.trap]
..
.wh 11i TT
Hello, world!
.tm body1: .t=\n(.t, .trap=\n[.trap]
.br
.tm body2: .t=\n(.t, .trap=\n[.trap]
$ ./build/test-groff -Tascii ./EXPERIMENTS/dot-t-within-trap.groff | cat -s
body1: .t=2640, .trap=
body2: .t=2600, .trap=
Hello, world!



The TT trap was never sprung!

Now, let's change the placement of the trap from 11i (the bottom of a U.S.
letter page in portrait orientation, and the formatter default) to 10i.


$ ./build/test-groff -Tascii ./EXPERIMENTS/dot-t-within-trap.groff | cat -s
body1: .t=2400, .trap=TT
body2: .t=2360, .trap=TT
trap: $0=TT, .t=240, .trap=
Hello, world!



Consider what must have happened: our trap _was_ planted, and in fact if we
move it back to 11i and invoke `ptr` we can see it.


$ ./build/test-groff -Tascii ./EXPERIMENTS/dot-t-within-trap.groff | cat -s
TT      2640
body1: .t=2640, .trap=
body2: .t=2600, .trap=
Hello, world!



The internal trap is not reported, because it has no name.  But it's
there--and, if our documentation is accurate, it is at 2640 units, _before_
the TT trap.  That is why \n[.trap] interpolates an empty value.


 -- Request: .wh dist [name]
     Call macro NAME when the vertical position DIST on the page is
     reached or passed in the downward direction.  The default scaling
     unit is 'v'.  Non-negative values for DIST set the trap relative to
     the top of the page; negative values set the trap relative to the
     bottom of the page.  An existing _visible_ trap (see below) at DIST
     is removed; this is 'wh''s sole function if NAME is missing.

     A trap is sprung only if it is "visible", meaning that its location
     is reachable on the page(1) (*note Page Location
     Traps-Footnote-1::) and it is not hidden by another trap at the
     same location already planted there.
[...]
     It is possible to have more than one trap at the same location
     (although only one at a time can be visible); to achieve this, the
     traps must be defined at different locations, then moved to the
     same place with the 'ch' request.
[...]
 -- Register: \n[.t]
     The read-only register '.t' holds the distance to the next vertical
     position trap.  If there are no traps between the current position
     and the bottom of the page, it contains the distance to the page
     bottom.  Within a diversion, in the absence of a diversion trap,
     this distance is the largest representable integer in basic
     units--effectively infinite.

 -- Request: .ch name [dist]
     Change the location of a trap by moving macro NAME to new location
     DIST, or by unplanting it altogether if DIST is absent.  The
     default scaling unit is 'v'.  Parameters to 'ch' are specified in
     the opposite order from 'wh'.  If NAME is the earliest planted
     macro of multiple traps at the same location, (re)moving it from
     that location exposes the macro next least recently planted at the
     same place.(2)  (*note Page Location Traps-Footnote-2::)
[...]
   (1) A trap planted at '20i' or '-30i' will not be sprung on a page of
length '11i'.

   (2) It may help to think of each trap location as maintaining a
queue; 'wh' operates on the head of the queue, and 'ch' operates on its
tail.  Only the trap at the head of the queue is visible.


I am beginning to think I should start discussing the unnamed internal trap
more explicitly.  I still have a hangover from some earlier documentation
applying the term "pseudo" to it.  It seems clearer to me now that there truly
is nothing ersatz about it.  It exists and behaves like a named trap in most
respects, except insofar as it doesn't have a name.

In fact, the unnamed/implicit/internal trap has a superpower; recall this in
the description of `wh`.

"An existing _visible_ trap (see below) at DIST is removed;"

...which doesn't apply to the implicit trap.  You can shove a named trap in
**front** of it with `wh`, but it will not be deleted.

Observe:


$ cat EXPERIMENTS/expose-implicit-trap.roff
.de TT
.tm I'm a happy trapper on page \\n%.
..
.wh 11i TT
Hello, world!
.bp
.ch TT 10i
Page two.
.bp
Page three.
$ ./build/test-groff -Tascii EXPERIMENTS/expose-implicit-trap.roff | cat -s
I'm a happy trapper on page 2.
I'm a happy trapper on page 3.
Hello, world!

Page two.

Page three.


 
> In all the standard macro packages, it's likely impossible unless the user
goes to some pains to remove the bottom-margin trap.

It's conceivable that a full-service macro package will not set up a
page-bottom trap if no footer is configured and no footnotes occur.  I haven't
verified if any of the ones we ship are so parsimonious, however.

> > Does anybody want this?
> 
> I don't see any harm in adding it even if only people who are debugging
groff internals ever end up using it.

Okay.  I'll ask the list.

The funny situation I ran across is this:

What should the value of \n[.t] (and, for that matter, the proposed \[.trap])
be when you're _already executing a trap_?

As we saw above, when we instrument a trap to report next-trap information, we
got this:


trap: $0=TT, .t=240, .trap=


_groff_ has dutifully updated `\$0` for us, a nice feature even though traps
can't take arguments (and especially helpful since trap-called macros, like
others, can be aliased).  \n[.trap] is empty, and since we're not in a
diversion, does this mean that the next trap is the implicit trap?

Well, there are a couple of ways to find out.  One is to plant another trap.


$ cat EXPERIMENTS/two-traps.groff
.de TT
.tm TT trap: $0=\\$0, .t=\\n(.t, .trap=\\n[.trap]
..
.de UU
.tm UU trap: $0=\\$0, .t=\\n(.t, .trap=\\n[.trap]
..
.wh 10i TT
.wh 10.5i UU
Hello, world!
$ ./build/test-groff -Tascii EXPERIMENTS/two-traps.groff|cat -s
TT trap: $0=TT, .t=120, .trap=UU
UU trap: $0=UU, .t=120, .trap=
Hello, world!



Lovely!

Another is to rudely invade the macro/string/diversion name space and _give_
the unnamed trap a name, at least according to this proposed '\n[.trap]'
feature.


+const char *top_level_diversion::get_next_trap_name()
+{
+  vunits next_trap_pos;
+  trap *next_trap = find_next_trap(&next_trap_pos);
+  if (0 /* nullptr */ == next_trap)
+    return "GBR-NO-NEXT-TOP-LEVEL-TRAP";
+  else
+    return next_trap->nm.contents();
+}
+
$ (cd build && make -j troff)
$ ./build/test-groff -Tascii EXPERIMENTS/two-traps.groff|cat -s
TT trap: $0=TT, .t=120, .trap=UU
UU trap: $0=UU, .t=120, .trap=GBR-NO-NEXT-TOP-LEVEL-TRAP
Hello, world!



As can be seen, what I was really dealing with was a null pointer.  The
implicit trap is neither wave nor particle.  Formatter logic will arrange for
the page bottom to eventually be reached, no matter what.  (In _groff_,
vertical position traps can be disabled, which as our manual notes, means that
the current page "can't be ejected".)

So I stuck a ".vpt 0" at the end of "two-traps.groff" above, and got this:


$ ./build/test-groff -Tascii EXPERIMENTS/two-traps.groff|cat -s
troff: error: can't continue page ejection because vertical position traps
disabled
troff: error: can't continue page ejection because vertical position traps
disabled
Hello, world!



The formatter manages to wrangle itself free of this situation and exit rather
than looping infinitely.  (I wonder why the diagnostic is thrown _twice_...)

So there would seem to be a lot of special casing going on here to stumble
forward with invalid input documents.

Maybe '\n[.trap]', plus a more explicit exploration of the implicit trap in
our documentation, will help people.


    _______________________________________________________

Reply to this item at:

  <https://savannah.gnu.org/bugs/?64212>

_______________________________________________
Message sent via Savannah
https://savannah.gnu.org/




reply via email to

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