.eval does only one thing: It allows you to place arbitrary Lua code until the following .endeval, and the text written to standard output by this Lua code is substituted for the .eval ... .endeval. The usefulness of this tactic will be apparent from an example. Consider the following troff document, tau.ms:
The ratio of the circumference of a circle to
its radius is \(*t \(~=
-- following prints tau, because cos(tau/2) = -1
groff -z -U -ms tau.ms
(The -z avoids generating output, because we are not ready for it yet. The -U runs in “unsafe” mode, i.e., it allows the writing of aux files.) You will find that the groff asks you to run it again:
Rerun groff with -U
Call groff again as follows:
groff -U -ms tau.ms > tau.ps
tau.ps will now look like:
The ratio of the circumference of a circle to its radius is τ ≈ 6.2831853071796.
The first groff call produces a Lua file .trofftemp.lua.3 The second groff call invokes Lua to create an auxiliary file for each .eval that gets sourced back into the document.
It is clear that Lua code via .eval can serve as a very powerful second extension language for troff. This benefit is available even when the document is processed by troff2page: We could run troff2page on the same document, tau.ms, and the resulting tau.html will show the same content.
Furthermore, we can embed .eval-enclosed Lua code inside an .if (or .ie or .el) statement so that it gets executed only for troff or only for troff2page. (Recall we used the number register \n[.troff2page] for this purpose on page 3.) In particular, by calling Lua code only for troff2page, the user has the means to extend troff2page to deal with things that the core program as supplied does not.
Note that when troff2page sees .eval-enclosed Lua code, it runs it in a Lua environment that has not only the basic Lua language but also includes the procedures and data structures defined in troff2page. These extras are not available (and are arguably not useful) to the .eval code seen by troff.
For a more substantial example of .eval’s use, consider defining color names using the HSL (hue/saturation/lightness) scheme rather than the RGB and CMYK schemes provided by groff. For instance, we would like to define the color Venetian red using its HSL spec (357°, 49%, 24%), which to many is a more intuitive description than RGB (91, 31, 34).
While there is an algorithm to convert HSL to RGB, implementing it using groff’s limited arithmetic is tedious. Instead, we’ll define a much easier Lua procedure to do the same, and put it inside an .eval:
local function between_0_and_1(n)
if n < 0 then
return n + 1
elseif n > 1 then
return n - 1
local function tc_to_c(tc, p, q)
if tc < 1/6 then
return p + (q - p)*6*tc
elseif 1/6 <= tc and tc < 1/2 then
elseif 1/2 <= tc and tc < 2/3 then
return p + (q - p)*6*(2/3 - tc)
local function hsl_to_rgb(h, s, l)
h = (h % 360) / 360
if l < 1/2 then
q = l * (s + 1)
q = 1 + s - l*s
local p = 2*l - q
local tr = between_0_and_1(h + 1/3)
local tg = between_0_and_1(h)
local tb = between_0_and_1(h - 1/3)
return tc_to_c(tr, p, q),
tc_to_c(tg, p, q),
tc_to_c(tb, p, q)
function def_hsl_color(name, h, s, l)
local r, g, b = hsl_to_rgb(h, s, l)
io.write(string.format('.defcolor %s rgb %s %s %s\n', name, r, g, b))
Here, the Lua procedure def-hsl-color takes an HSL spec and writes out the equivalent RGB groff definition. (The troff2page distribution provides def-hsl-color in the macro file defhsl.tmac.)
We can call this Lua procedure inside another .eval to define venetianred using its HSL spec:
def_hsl_color('venetianred', 357, .49, .24)
The color name venetianred can now be used like any other groff color name:
Prismacolor’s burnt ochre pencil is a close match for Derwent’s
\fB\m[venetianred]Venetian red\m\fP, and either can be used to
emulate the sanguine chalk drawings of the Old Masters.
Prismacolor’s burnt ochre pencil is a close match for Derwent’s Venetian red, and either can be used to emulate the sanguine chalk drawings of the Old Masters.
troff2page treats troff’s .ig environment, whenever it uses ## as ender, as containing Lua code that can be used to extend troff2page. This syntactic overloading of .ig ## is an innovation introduced by Oliver Laumann’s unroff.
Any Lua code enclosed within .ig ## ... .## will be processed by troff2page but not by troff, which treats it as a multiline comment of course. Note that .ig ## does not pipe its stdout back into the document, as .eval does. This is to maintain the invariant that as far as output is concerned, .ig ##, like other .igs, is always a comment. However, you can add Lua code within .ig ## to influence how troff2page — but not troff! — processes the rest of the document.
For example, let’s define a \*[url ...] string register that simply typesets its URL argument within angle brackets.
.ds url \(la\fC\\$1\fP\(ra
This is adequate for the print output. For troff2page though, we’d like to re-define this macro, in Lua, to create a hyperlink. We enclose this re-definition in a .ig ##, which not only allows it to be in Lua, but also makes it apply only when troff2page reads it:
return link_start(url) .. url .. link_stop()
The procedures defstring, link_start, and link_stop are defined in the troff2page code.
.ig ## can be used to specify settings that are relevant only when troff2page is used on a document, e.g., stylesheet changes. troff2page uses the output-stream Css_stream to write out style information. The user can also write to this stream, e.g.,
color: rgb(61,35,39); /* chocolate */
This sets the HTML headers with a foreground color of chocolate.4