4.  Defining Event Handlers

      In the following list of Scheme primitives, the argument name denotes the name of a troff request, macro, escape sequence etc. (without any initial period or escape character) and can be supplied in form of a Scheme string, a Scheme symbol, or a Scheme character:

(defrequest "ti" ...)

(defrequest 'sp  ...)

(defescape  #\h  ...)
(the primitives defrequest and defescape will be introduced in a moment). An argument named handler is either a procedure (usually a lambda expression) which returns a string, a symbol, or a character; or handler can itself be specified as a string, symbol, or character. In addition, the literal ``#f'' (false) can be supplied as a handler argument to remove any event handler that is currently associated with that event. Each of the ``def'' primitives listed below returns the handler that was previously associated with the corresponding event, or ``#f'' if the event was not handled.

(defrequest name handler)

      Associates the given handler with the given troff request. If handler is a procedure, it is passed the request's name and arguments as strings when called later. Passing the name of the request as the first argument aids in associating the same procedure with several different requests. unroff does not limit the number of arguments to requests, thus, an event handling procedure for a requests that takes a variable number of arguments could be defined like this:

(defrequest 'rm
  (lambda (rm . args) ...))

If the request is invoked with fewer arguments than the procedure has formal arguments, the remaining arguments are bound to the empty string. If the request is invoked with more arguments than the procedure has formal arguments, the last lambda variable is assigned a string consisting of the (space-delimited) arguments left over after the other formal arguments have been bound to the other actual arguments. However, if handler has only one formal argument, an error message is displayed when the request is called with any arguments at all and the event is skipped. For example, consider the following handler for the (non-existing) request ``xx'':

(defrequest 'xx
  (lambda (name a b) ...))
The procedure's arguments a and b will be bound as follows when the request is invoked:
.xx foo              name="xx"  a="foo"  b=""

.xx foo bar baz      name="xx"  a="foo"  b="bar baz"

(defmacro name handler)

      Associates handler with the given troff macro, superseding any definition for this macro established by the ordinary ``.de'' request. The only difference between defrequest and defmacro is the way arguments are bound in case handler is a procedure (troff employs slightly different rules when parsing the call to a request and a macro invocation). The quote character can be used in the latter case to surround arguments containing spaces, while quote characters are treated as normal characters in requests, which allows for the following remarkable troff idiom:

.ds xy "hello
In contrast to event handlers defined for requests, the formal arguments of a handler procedure associated with a macro must match the actual arguments in the normal way, that is, as if the procedure were invoked from within Scheme. A warning message is displayed if the number of macro arguments does not match the number of formal procedure arguments, and the event is skipped.

(defspecial name handler)

      Associates handler with the special character whose name is name. The name must have a length of 2. In addition, an empty name can be specified to define a ``fallback'' handler that is called for special characters for which no handler exists. Like all event handler procedures, handler can have arbitrary side-effects in addition to returning a result; for example, the procedure may display a warning message if the special character cannot be represented in the target language and an approximation must be rendered instead.

(defstring name handler)

      Associates a handler with the specified troff string. As unroff provides a default handler for the request ``.ds'' to implement used-defined strings, defstring is primarily used to give definitions for strings exported by troff macro packages.

(defnumreg name handler)

      This request behaves like defstring, except that it works on number registers. Note that the Scheme primitive number->string may have to be used by handler (if it is a procedure) to convert a numeric result into a string that can be returned from the handler.

In troff input, number registers as well as strings, special characters, and escape sequences can be denoted using the groff ``long name'' syntax, unless troff compatibility has been enabled:

\n[numreg]   \n[string]   \f[font]   \[em]   ...

(defescape name handler)

      Associates an event handler with an escape sequence. name must have a length of 1, unless the empty string is given to define a ``fallback'' event handler (as with defspecial). Handlers defined for certain escape sequences are passed a second argument in addition to the name of the escape sequence. This is true for all escape sequences that have an argument according to the troff specification:

\b  \c  \f  \h  \k  \l  \n  \o  \s  \v  \w  \x  \z
\*  \$  \"
In addition, handlers for these groff escape sequences are passed an additional argument unless troff compatibility is enabled:
\A  \C  \L  \N  \R  \V  \Y  \Z
The form of an escape sequence argument is determined by the troff specification and cannot be programmed; for example, the handler for `\z' is passed a character or a special character, and the handler for `\"' is invoked with the rest of the current input line sans the terminating newline. (The latter can be used to translate troff comments.)

Handlers registered for the escape sequences `\n' and '\s' are passed an optional third argument, one of the Scheme characters #\+ and #\-, if the escape sequence argument begins with a sign. The sign is then stripped from the actual argument.

As `\n' and `\*' are treated as ordinary escape sequences, handlers can be defined for them to achieve some form of fallback for number register and strings. unroff provides suitable default handlers for `\n', `\*', and '\$' as part of the implementation of user-defined number registers, strings, and macros. These handlers can be overridden if desired.

(defchar name handler)

      Associates handler with a character. name must have a length of 1. Each time the specified character is encountered in the troff input, the result (or value) of handler is output in place of the character. Character translations are not applied to the result of event handlers; event procedures can use the Scheme primitive translate (as described below) to execute the character translations established by calls to defchar if desired.

defchar currently has a number of weaknesses. The argument cannot be a special character (that is, name must be a plain character), and the mechanism cannot be used to achieve true output translations as with the troff request ``.tr'' or the groff request ``.char''.

(defsentence handler)

      Defines a handler to be consulted on end of sentence. If handler is a procedure, it is passed the punctuation mark ending the sentence as its argument (in form of a Scheme character). In any case, if an event handler has been specified, its result (or value) is output in place of the end-of-sentence mark and the newline character following it.

(defequation handler)

      Defines a handler for eqn inline equations. If handler is a procedure, it is passed the contents of the inline equation (with the delimiters stripped) as an argument. When an inline equation is encountered in the troff input and a handler has been defined for inline equations, the handler's result (or value) is output in place of the equation.

For inline equations to be recognized, delimiters must be defined first by passing eqn input that includes a ``delim'' directive to the Scheme primitive filter-eqn-line (explained below), as is usually done by the event handler associated with the request ``.EQ''.


Markup created by unroff 1.0,    March 21, 1996,    net@informatik.uni-bremen.de