4    The OLH and CRef Modules

The Emacs On-Line Help (OLH) and Consulting Reference (CRef) modules are Emacs-based interfaces to the Athena On-Line Help and the OLC Consulting Reference systems. They are discussed jointly because they are identical in use and functionality; they actually use an underlying generic menu interface facility, which will itself form a fundamental part of the discussion.

4.1    Using OLH and CRef

The OLH and CRef modules are invoked by typing M-x olh or M-x CRef in Emacs. This loads the corresponding menu structure into Emacs, and displays the top level menu. (See Chapter 2, Figures 2-4 and 2-6.)

The hierarchy of the OLH and CRef menu tree is divided into nodes, which may be either menus or textual information. The items in a menu are known as entries. Entries which are submenus are identified by a ``*'' next to the entry number; entries which are nodes have a ``.'' after the entry number. See Figure 4-1.
 
n: Emacs.Delete_Menu  p: Emacs.Fund_Menu  u: Emacs.Main_Menu  t: Top
--------------------------------------------------------------------

                            On-Line Help
                     << Advanced Techniques >>

             1. Using an Existing Emacs (emacsclient)
         --> 2. Issuing Sophisticated Commands <--
             3* Keyboard Macros
             4* Editing and Compiling Programs in Emacs
             5. Using Shell Commands from within Emacs
             6. More Things to Do within Emacs

              Type RET to view entry, TAB to unselect.

Figure 4-1: Sample Menu (OLH)

 
Entries in a menu can be selected in the intuitive way by typing the number of the number. This ``highlights'' the entry by placing arrows on either side of the entry. (The second entry in Figure 4-1 is selected.) Typing N and P unselects the currently selected entry and selects the entry above or below it. Typing RETURN views the selected entry, yielding another menu if the entry was a submenu, or actual documentation otherwise.

Two other methods of viewing entries in a submenu are provided. As in Emacs' Info mode, typing m allows viewing by typing the title of the entry, with Emacs completion. Also, typing S will perform an equivalent of an incremental search in Emacs, except that typing RETURN will view the entry on the line found, and only titles of menu entries will be matched.

The buffer display is modeled after Emacs' Info mode to provide a glimpse of where the current node is located with respect to other nodes surrounding it. The top line shows the next, previous, and up nodes, which can be reached by typing n, p, and u respectively. For example, following Figure 4-1, if the selected entry is viewed, the ``next'' node would be ``Keyboard Macros'' and the previous node would be ``Using an Existing Emacs (emacsclient)''. The ``up'' node would be ``Advanced Techniques'' because there was a move down one level in the menu tree. The ``top'' node is always the first node displayed, and has no ``up'' node; it is reachable via t.

Because the menu tree can get quite deep, it is easy to lose track of where in the menu hierarchy the current node is located. Typing w (for ``Where am I?'') creates a buffer showing the menus traversed, starting from the top level, to arrive at the current node. (See Figure 4-2.) In this mode, the current node is automatically selected (so that typing RETURN will ``quit'' by revisiting it), and a parent node can be selected and viewed using n and p followed by RETURN.
 
     0. Browser Top Level    
     7. Text Processing    
     1. Emacs Text Editor    
    10. Advanced Techniques    
-->  2. Issuing Sophisticated Commands <--

   Type n and p to move, RET to select, or q to quit.

Figure 4-2: Sample Where Mode Buffer

 
Other commands include visiting a previous node with l; saving the current location in the tree with b (for Bookmark), and later revisiting it with G (for Go to bookmark); and saving the contents of the current buffer in the Emacs kill ring by typing s or in a file by typing C-o. Also, the commands M-x olh-insert-path and M-x CRef-insert-path insert into the current buffer the menu path leading to the most recent node. Finally, OLH provides the a command, which goes directly to the OLC stock answers in OLH.

4.2    Implementation

OLH and CRef use a generic menu browsing facility defined in menu-browser.el, which defines and implements all the commands discussed in the previous section. The data for the menu hierarchy itself are specified in elisp files which define a structure describing the menus and the locations of the files containing the actual documentation.

4.2.1    The Menu Browser

The menu browser interface allows specification of an arbitrary menu hierarchy viewable on-line using the commands described above. It requires specification of a menu tree file describing the structure of the hierarchy.

The tree file defines a variable---olh-tree for OLH and CRef-tree for CRef---holding a browser-node structure.

The browser-node structure is a data type defined using the DEFSTRUCT macro defined in defstruct.el. (See Chapter 3.) The browser-node structure represents a node in the tree; the browser-node in the olh-tree or CRef-tree variables are the top level nodes for the corresponding menu tree. The following fields are declared for the browser-node structure:

menu-title
The title of this node when displayed as part of a menu.

entry-title
The title of this node when viewed as the current node.

file
If an entry, the file name holding the text of the entry.

children
If a menu, a list of the its entries. The entries are one of two types: a browser-node, or a pointer entry. A pointer entry is simply a pointer to an entry somewhere else in the menu hierarchy. It is represented as a list of numbers, corresponding to the menu items that must be selected, starting from the top level menu, to reach the entry.

filsys
If an entry, the locker, if any, which must be attached via Athena's attach command to access the file containing the text of the entry.

insert-function
If an entry, this is a filter function which must be run on the text of the entry before display.

The menu-title and entry-title slots are needed because the actual title of a node may be different from the title it has when displayed as a menu choice.[1] The children slot serves the obvious need of specifying the entries of a menu, recursively, so that the entire tree can be specified using browser-node structures. Its use of pointer entries allows a section of the tree to appear multiple times throughout the hierarchy without repeating the entire browser-node substructure. For an actual text entry, the file is specified using the filsys and file slots, the first describing what Athena locker has to be attached to access the file, the second containing the file name itself.

The insert-function is needed primarily for OLH documents, but can be useful for other documentation systems. OLH documents are not stored in plain text format. The Athena Documentation Staff writes most of their documentation using the EZ and LaTeX text formatters, and the files are stored in the corresponding EZ and DVI formats. The insert-function for these documents runs the ez2ascii and dvi2tty programs to convert EZ and DVI files to plain text.

This mechanism could be useful in other ways, for example to conserve space and store files in a compressed format, using uncompress to view them.

The browser display is initiated with the menu-browser function, and is called by the olh and CRef commands. This function takes a wealth of arguments specifying the various parameters specific to the menu system being displayed. These include, among others, the name of the buffer to be used, the name of the mode displayed in the Emacs mode line, tree structure (in the form of a browser-node structure), and the keymaps used in the buffer [2]. The menu browser keymaps are given as arguments---as opposed to having them hardcoded into the menu browser code---so that individual applications can provide their own additional commands. OLH, for example, copies the default menu browser keymaps and modifies them to include the a command.

4.2.2    Generating the Tree Files

The tree files containing the browser-node structures comprising the menu hierarchy are built outside of Emacs.[3] Because the OLH and CRef documentation database is under continual revision, the tree files must be regularly rebuilt.

Even though the tree files contain actual elisp code, they are easily generated by non-elisp programs because the code only contains a single variable declaration, whose contents are highly recursive. It is therefore not hard to write a program that simply traverses the database in a depth-first manner, and outputs its traversal with a few extra characters, thus forming a valid elisp expression.

The OLH database is implemented using a sophisticated system separating the issues of menu layout, actual file location, and document storage formats. The physical location of documents is independent of the menu structure. The database itself is independent of the operating system storing it. Documents may be stored in one of several different formats, and be viewed in yet another format appropriate to the display requirements of the browser interface.

The CRef database follows a simple directory structure which directly corresponds to the menu structure. Each directory represents an actual menu; the files in the directory correspond to the nodes, with subdirectories representing submenus. Not all files in the directory are part of the menu hierarchy. The contents of the directory which are part of the menu hierarchy, along with their titles and other relevant information, are kept in .index files stored in the directory.

Traversal of the menu hierarchy consists of examining the .index files for the current menu entries, and descending into the appropriate subdirectories.

It is noteworthy that the OLH and CRef databases are implemented in completely different formats. It shows how the menu browser facility can be adapted to different types of menu oriented documentation systems, without regard to database implementation details. All that is necessary is a method of generating the appropriate tree files.

4.3    Analysis

The OLH and CRef modules provide a simple, easy to use interface.

They were written with both consultants and the general user in mind, and are easily integrated with the EOLCR client for efficient documentation referral and look up.

The common menu browser interface allows OLH and CRef to specify a small set of parameters and yet provide a fully featured documentation system. The menu browser code is flexible enough to handle many types of menu based documentation hierarchies, and is also very simple and straightforward, making adding extensions to the basic capabilities an easy task.

One area of contention is the menu browser's use of tree files.

Currently, the entire menu hierarchy is stored in a tree file; this tree file is read in its entirety on startup. This may be fine for relatively small hierarchies, but consider a very large documentation system generating tree files of more than one megabyte of text. It would be very wasteful---and initially very slow---to load the entire tree file on startup.

One solution to this problem requires a simple extension to the menu browser. The program producing the tree file could be modified to only produce the first level of the hierarchy, rather than the entire hierarchy. References to nodes below this top level would signal the menu browser to call a menu expansion hook, which would be a function that would ``expand'' the current tree to include the newly selected node. In this manner, as the menu hierarchy is traversed, only the necessary portions of the tree are expanded, keeping memory use to a minimum.[4] Some obvious extensions to this idea include avoiding tree files in the first place, and simply having a top level menu expansion hook that expands the first level on startup. Also, two, three or more levels could be expanded at a time, rather than just one. Finally, if memory conservation is at a premium, newly expanded menu levels could replace, rather than augment, the current level.

The disadvantage of this method is that it makes the entire system much slower, at least through new areas of the hierarchy.[5] Also, it presents some interesting problems for the support of cross references, which are currently not provided [6] but would be trivial to implement with the present design.[7] Finally, it also places a slightly more complicated load on the programs or elisp routines that must parse the documentation hierarchy, since they would have to expand arbitrary portions of the hierarchy, rather than the entire configuration.