groff
[Top][All Lists]
Advanced

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

[Groff] The ultimative underline macro


From: Werner LEMBERG
Subject: [Groff] The ultimative underline macro
Date: Thu, 18 Dec 2003 16:07:55 +0100 (CET)

Here comes the ultimative underline macro!  Try it for example with
this code:


.so ul.tmac
.ll 5i
.in 1i
.ti 2i
.Underline This is a test of the `.Underline' macro. \
  As you can see, it works across lines without problems.
.Underline Note, however, that you need the current CVS \
  version of groff to get correct spacing right after a \
  period at the end of underlined text \[en] in older \
  versions of groff, the `\[rs]?' escape wasn't \
  transparent with respect to end-of-sentence recognition.
It works also across page breaks, and it isn't affected by
vertical position traps.
'in .5i
'll -.5i
.Underline Consequently, it can be used with all macro packages, \
  provided it doesn't use the diversion trap.
Actually, none of the macro packages which are distributed with
groff use the diversion trap.

The
.Underline line length
and
.Underline indentation
can be changed without
.Underline any restriction;
I think that such a macro has many applications.


    Werner


======================================================================


.\" ul.tmac
.\"
.\"   Version 1.0  2003-Dec-18
.\"
.\"   written by Werner LEMBERG <address@hidden>
.\"
.\"
.\" This file defines a macro `.Underline' which underlines its arguments
.\" continuously.  It is completely transparent to justifying, this is,
.\" the text to be underlined (and the text surrounding it) is typeset
.\" identical to normal text, without any distortion in filling.
.\"
.\" Note that you can use `.Underline' in diversions; it works also across
.\" page breaks and is robust against vertical position traps.
.
.
.\" The vertical position and thickness of the underline segments can
.\" be controlled with the following two strings.
.
.ds Underline-thickness (\En[.ps]s / 15u)
.ds Underline-offset (\En[.ps]s / 5u)
.
.
.eo
.
.de \"
..
.
.
.de Underline
.  \" If we aren't in our `ul-div' diversion, start it now, reset the
.  \" .Underline and diversion line counters, and set the diversion trap.
.  \" Otherwise just increase the .Underline counter.
.  ie '\n[.z]'ul-div' \
.    nr ul-count +1
.  el \{\
.    di ul-div
.    dt 1u ul-do
.    nr ul-count 0
.    nr ul-line 0
.  \}
.
.  nr ul-active 1
.
.  \" Embed code to set various registers before and after the text.
.  \" This code is evaluated when the diversion is reread the first time.
.  \"
.  \" Saving \n[.k] as horizontal positions is sufficient since the
.  \" indentation is set to zero while rereading.  On the other hand, we
.  \" need the (normal) indentation and line length values while filling
.  \" the diversion, to get the start and end positions of normal lines in
.  \" case an underline segment is broken across lines.
\?\
\R'ul-.i-\n[ul-count] \n[.i]'\
\R'ul-.l-\n[ul-count] \n[.l]'\
\R'ul-.ll-\n[ul-count] \n[.ll]'\
\R'ul-start-pos-\n[ul-count] \En[.k]'\
\?\
\$*\
\?\
\R'ul-end-pos-\n[ul-count] \En[.k]'\
\?
.
.  nr ul-active 0
..
.
.
.de ul-do
.  \" Switch to another environment to preserve the partially filled line.
.  ev ul-env
.  evc 0
.
.  \" Emit vertical space possibly truncated by the diversion trap.
.  if \n[.trunc] \
.    sp \n[.trunc]u
.
.  \" Save the .Underline and `active' counters as array elements, indexed
.  \" by the diversion line counter.
.  nr ul-count-\n[ul-line] \n[ul-count]
.  nr ul-active-\n[ul-line] \n[ul-active]
.
.  \" End diversion if there isn't a broken underline segment.  Otherwise,
.  \" move trap down to handle next line.
.  ie !\n[ul-active] \{\
.    dt
.    di
.
.    \" Prepare diversion handling.
.    in 0
.    nf
.
.    \" Copy the diversion to set the embedded number registers.
.    di ul-div1
.    ul-div
.    di
.    rn ul-div1 ul-div
.
.    \" Process diversion again.  The trick is to insert underline
.    \" segments *before* the corresponding text line is emitted.
.    nr ul-max-line \n[ul-line]
.    nr ul-count 0
.    nr ul-line 0
.
.    di ul-div1
.    \" Call .ul-do1 manually the first time.
.    ul-do1
.    ul-div
.    di
.
.    \" Finally emit underlined text.
.    ul-div1
.  \}
.  el \
.    dt (\n[.d]u + 1u) ul-do
.
.  nr ul-line +1
.
.  \" Restore previous environment.
.  ev
..
.
.
.de ul-do1
.  if (\n[ul-line] <= \n[ul-max-line]) \{\
.    nr ul-last \n[ul-count]
.
.    \" Get saved counters from the array.
.    nr ul-count \n[ul-count-\n[ul-line]]
.    nr ul-active \n[ul-active-\n[ul-line]]
.
.    \" Set line thickness.
\Z'\
\D't \*[Underline-thickness]''\c
.
.    \" A typical diversion to be handled looks like this:
.    \"
.    \"    xxxx -0--- xxxx -1----- xxxxxxxx -2--
.    \"    -2------- xxxxxx xxxxx -3----- xxxxxx
.
.    while (\n[ul-last] < \n[ul-count]) \{\
\Z'\
\h'\n[ul-start-pos-\n[ul-last]]u'\
\v'\*[Underline-offset]'\
\D'l (\n[ul-end-pos-\n[ul-last]]u - \n[ul-start-pos-\n[ul-last]]u) 0'\
\v'-\*[Underline-offset]''\c
.      nr ul-last +1
.    \}
.
.    ie \n[ul-active] \{\
.      \" An underline segment broken across lines.
\Z'\
\h'\n[ul-start-pos-\n[ul-count]]u'\
\v'\*[Underline-offset]'\
\D'l (\n[ul-.ll-\n[ul-count]]u - \n[ul-start-pos-\n[ul-count]]u) 0'\
\v'-\*[Underline-offset]''\c
.
.      \" Set start position to the indentation value of next line.
.      nr ul-start-pos-\n[ul-count] \n[ul-.i-\n[ul-count]]
.      \" Update length of next line.
.      nr ul-.ll-\n[ul-count] \n[ul-.l-\n[ul-count]]
.    \}
.    el \{\
.      \" The last underline segment in the diversion.
\Z'\
\h'\n[ul-start-pos-\n[ul-count]]u'\
\v'\*[Underline-offset]'\
\D'l (\n[ul-end-pos-\n[ul-count]]u - \n[ul-start-pos-\n[ul-count]]u) 0'\
\v'\*[Underline-offset]''\c
.    \}
.  \}
.
.  \" Move trap down to handle next line or remove trap.
.  ie \n[ul-active] \
.    dt (\n[.d]u + 1u) ul-do1
.  el \
.    dt
.
.  nr ul-line +1
..
.
.ec
.
.\" EOF

reply via email to

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