Go to the previous, next section.

Developing with Hyperbole

This chapter is only for people who are familiar with Emacs Lisp and wish to customize Hyperbole, to extend it, or to develop other systems using Hyperbole as a base.

Hook Variables

Hyperbole provides a number of hook variables that allow you to adjust its basic operations to meet your own needs, without requiring you to change the code for those operations.

We find it best to always set the value of hook variables either to nil or to a list of function names of no arguments, each of which will be called in sequence when the hook is triggered.

Given the name of a function, a Hyperbole hook variable triggered within that function has the same name as the function with a -hook appended. Hyperbole provides the following hook variables:

hyperb:init-hook
For customization at Hyperbole initialization time. Use this to load any personal Hyperbole type definitions you might have. It is run after Hyperbole support code is loaded but before Hyperbole session initializations take place.

action:act-hook
Run before each Hyperbole button activation. The variable hbut:current contains the button to be activated when this is run.

ebut:create-hook
To add to the Hyperbole explicit button creation process.

ebut:delete-hook
To add to the Hyperbole explicit button deletion process.

ebut:modify-hook
Executed when an explicit button's attributes are modified.

hibtypes:begin-load-hook
Executed prior to loading of standard Hyperbole implicit button types. Used to load site-specific low priority implicit button types since lowest priority ibtypes are loaded first.

hibtypes:end-load-hook
Executed after loading of standard Hyperbole implicit button types. Used to load site-specific high priority implicit button types since highest priority ibtypes are loaded last.

htype:create-hook
Executed when a Hyperbole type (e.g. action type or implicit button type) is added to the environment.

htype:delete-hook
Executed when a type is deleted from the environment.

kotl-mode-hook
Executed when a Koutline is created or read in or when kotl-mode is invoked.

wrolo-display-hook
Executed when rolodex matches are displayed.

wrolo-mode-hook
Executed when a rolodex match buffer is created and put into wrolo-mode.

wrolo-yank-reformat-function
A variable whose value may be set to a function of two arguments, START and END, indicating the region of the rolodex entry yanked into the current buffer by the rolo-yank command. The function may reformat this region to meed user-specific needs.

Hyperbole also makes use of a number of external Emacs hook variables.

find-file-hooks
This is called whenever a file is read into a GNU Emacs buffer. Hyperbole uses it to highlight any buttons within files when run under any NEXTSTEP or X window system-based versions of GNU Emacs.

write-file-hooks
This is called whenever a GNU Emacs buffer is written to a file. Hyperbole uses it to save any modified button data associated with the file's directory.

Hyperbole mail and news facilities also utilize a number of external hook variables. These hide button data and highlight buttons if possible. See the various support files for details.

Creating Types

To define or redefine a single Hyperbole type, you may either:

The functions from the htype class may be applied to any Hyperbole types, if needed.

The following subsections explain the specifics of Hyperbole type definitions which are beyond standard practice for Emacs Lisp programming. See the definitions of the standard types in `hactypes.el' and `hibtypes.el' for examples.

Action Type Creation

New forms of explicit buttons may be created by adding new action types to a Hyperbole environment. The file, `hactypes.el', provides many examples of working action types.

An action type is created, i.e. loaded into the Hyperbole environment, with the (defact) function (which is an alias for (actype:create)). The calling signature for this function is given in its documentation; it is the same as that of (defun) except that a documentation string is required. (An interactive calling form is also required if the action type has formal parameters and is to be used in explicit button definitions. Implicit buttons never use an action type's interactive form. It is good practice to include an interactive form since the type creator cannot know how users may choose to apply the type.)

An action type's parameters are used differently than those of a function being called. Its interactive calling form is used when an explicit button is created to prompt for type-specific button attributes. The rest of its body is used when a button with that action type is activated. Then the button attributes together with the action type body are used to form an action that is executed in response to the button activation. The action's result is returned to the action caller unless it returns nil, in which case t is returned to the caller to ensure that it registers the performance of the action.

An action type body may perform any computation using Emacs Lisp and Hyperbole functions.

The interactive calling form for an action type is of the same form as that of a regular Emacs Lisp function definition (see the documentation for the Emacs Lisp (interactive) form). It may additionally use Hyperbole command character extensions when the form is given as a string. Each such extension character must be preceded by a plus sign, +, in order to be recognized since such characters may also have standard interactive form meanings.

The present Hyperbole extension characters are:

+I
Prompts for an existing Info node name and file.

+K
Prompts for an existing kcell identifier, either a full outline level identifier or a permanent idstamp.

+M
Prompts for a mail message date and the file name it resides in. The mail parameters prompted for by this character code are likely to change in the future.

+V
Prompts for a Hyperbole view specification. Not yet available for use.

Arguments are read by the functions in Hyperbole's hargs class, rather than the standard Lisp read functions, in order to allow direct selection of arguments via the Action Key.

If an action type create is successful, the symbol that Hyperbole uses internally to reference the type is returned. Nil is returned on failure so that you may test whether or not the operation succeeds.

Once you have defined an action type within your present Hyperbole environment, you can create new explicit buttons which use it. There is no explicit button type beyond its action type, so no further work is necessary.

Call (actype:delete) to remove an action type from a Hyperbole environment. It takes a single parameter which should be the same type symbol used in the type definition call (not the Hyperbole symbol returned by the call).

Implicit Button Types

An implicit button type is created or loaded via the (defib) function (which is an alias for (ibtype:create)). The calling signature for this function is given in its documentation; it is the same as that of (defun), but with a number of constraints. The parameter list should always be empty since no parameters will be used. A documentation string is required. The type's body follows this.

The body of an implicit button type is a predicate which determines whether or not point is within an implicit button of the type. If not, the predicate returns nil. If so, it may optionally setup to flash the button and then perform one or more actions. A call of the form: (ibut:label-set label start-pos end-pos) is used to setup the button flashing, if desired. This is then typically immediately followed by an action invocation of the form: (hact 'actype &rest actype-arguments). It is imperative that all actions (non-predicate code) be invoked through the (hact) function rather than directly or your ibtypes will not work properly. (Hyperbole first tests to see if any ibtype matches the current context before activating any type, so it ensures that (hact) calls are disabled during this testing.) Any action types used may be created before or after the implicit button type definition but obviously should be defined before any implicit buttons of the given type are activated; an error will result, otherwise.

If an implicit button type create is successful, the symbol that Hyperbole uses internally to reference the type is returned. Nil is returned on failure so that you may test whether or not the operation succeeds. Implicit button type names and action type names may be the same without any conflict. In fact, such naming is encouraged when an implicit button type is the exclusive user of an action type.

Call (ibtype:delete) to remove an implicit button type from a Hyperbole environment. It takes a single parameter which should be the same type symbol used in the type definition call (not the Hyperbole symbol returned by the call). This will not delete the action type used by the implicit button; that must be done separately.

By default, a request for help on an implicit button will display the button's attributes in the same manner as is done for explicit buttons. For some implicit button types, other forms of help will be more appropriate. If an Emacs Lisp function is defined whose name is formed from the concatenation of the type name followed by :help, e.g. my-ibtype:help, it is used to respond to requests for help on buttons of that type. Any such function should take a single argument of an implicit button construct. (This is what (ibut:at-p) returns when point is within an implicit button context.) The button may be queried for its attributes using functions from the hbut and hattr classes. See the `hib-kbd.el' file for an example of a custom help function.

Explicit Button Technicalities

Button Label Normalization

Hyperbole uses a normalized form of button labels called button keys (or label keys) for all internal operations. See the documentation for the function (hbut:label-to-key) for details of the normalization process. The normalized form permits Hyperbole to recognize buttons that are the same but whose labels appear different from one another, due to text formatting conventions. For example, all of the following would be recognized as the same button.

  <(fake button)>     <( fake      button)>

  Pam>  <(fake
  Pam>    button)>

  ;; <(fake
  ;;   button)>

  /* <( fake      */
  /*    button )> */

The last three examples demonstrate how Hyperbole ignores common fill prefix patterns that happen to fall within the middle of a button label that spans multiple lines. As long as such buttons are selected with point at a location within the label's first line, the button will be recognized. The variable hbut:fill-prefix-regexps holds the list of fill prefixes recognized when embedded within button labels. All such prefixes are recognized (one per button label), regardless of the setting of the GNU Emacs variable, fill-prefix, so no user intervention is required.

Operational and Storage Formats

Hyperbole uses a terse format to store explicit buttons and a more meaningful one to show users and to manipulate during editing. The terse format consists solely of button attribute values whereas the edit format includes an attribute name with each attribute value. A button in edit format consists of a Lisp symbol together with its attribute list which holds the attribute names and values. In this way, buttons may be passed along from function to function simply by passing the symbol to which the button is attached. Most functions utilize the pre-defined hbut:current symbol by default to store and retrieve the last encountered button in edit format.

The hbdata class handles the terse, stored format. The hbut, ebut, and ibut classes work with the name/value format. This separation permits the wholesale replacement of the storage manager with another, with any interface changes hidden from any Hyperbole client programming.

Programmatic Button Creation

A common need when developing with Hyperbole is the ability to create or modify explicit buttons without user interaction. For example, an application might require the addition of an explicit summary button to a file for each new mail message a user reads that contains a set of keywords. The user could then check the summary file and jump to desired messages quickly.

The Hyperbole class ebut supports programmatic access to explicit buttons. See it within the `hbut.el' file for full details. The documentation for (ebut:create) explains the set of attributes settings necessary to create an explicit button. For operations over the whole set of buttons within the visible (non-narrowed) portion of a buffer, use the (ebut:map) function.

Encapsulating Systems

A powerful use of implicit button types is to provide a Hyperbole-based interface to external systems. The basic idea is to interpret patterns output by the application as implicit buttons.

See the `hsys-*' files for examples of how to do this. Encapsulations are provided for the following systems (the systems themselves are not included with Hyperbole):

@bullet{World-Wide Web}
The world-wide web system originally developed at CERN, that now spans the Internet universe. This is automatically loaded by Hyperbole so that a press of the Action Key follows a URL.

@bullet{WAIS}
The Wide Area Information Systems full text-retrieval system orginally developed at Thinking Machines and then later at WAIS Inc.

@bullet{HyperBase}
A hypertextual storage manager that stores textual nodes as records with locking so that multiple users can read and edit hypertexts.

Embedding Hyperbole

[NOTE: We have never done this ourselves, though we have done similar things which leads us to infer that the task should not be difficult.]

The standard Emacs-based Hyperbole user interface has purposely been separated from the Hyperbole backend to support the development of alternative interfaces and the embedding of Hyperbole functionality within other system prototypes. The Hyperbole backend functionality that system developers can make use of is called its Application Programming Interface (API). The API may be used to make server-based calls to Hyperbole when Emacs is run as a non-interactive (batch) process, with its input/output streams attached to another process.

The public functions and variables from the following files may be considered the present Hyperbole API:

`hact.el', `hargs.el', `hbmap.el', `hbut.el', `hhist.el', `hmail.el', `hmoccur.el', `hpath.el', `htz.el', `hypb.el', `set.el', `wconfig.el', `wrolo.el', and `wrolo-logic.el'.

Note when looking at these files, that they are divided into sections that separate one data abstraction (class) from another. A line of dashes within a class separates public parts of the class from the private parts that follow the line.

This API does not include the Hyperbole outliner, as it has been designed for interactive use, rather than programmatic extensibility. You can certainly study its code, below the `hyperbole/kotl/' directory and learn to program it, however.

Go to the previous, next section.