8. USER INTERFACES

A single elvis binary can be compiled to support multiple user interfaces. For example, under UNIX elvis can be compiled to have a graphical user interface when run under X-windows, a termcap interface for use on most text terminals, an "open" interface for use on any terminal, and a "quit" interface for running scripts.

The exact list of available user interfaces will vary from one system to another. You can make elvis output a list of available interfaces by running "elvis -g?". This will also show you which interface elvis will use by default.

Elvis chooses the default user interface at run time by testing each user interface in turn, starting with the most desirable, and working its way down the list until it finds one that appears to be supported in the current environment. For example, if you're using elvis on a text terminal under UNIX, then elvis will bypass the "x11" interface because X-windows doesn't work on text terminals, and then elvis will find that the "termcap" interface would work, so that'll be the default.

If you don't want to use the default user interface, you can specify which interface to use via the -g gui command-line flag.

8.1 X11 Interface

The x11 interface is used under X-Windows on UNIX systems. It provides a scrollbar and mouse support, and allows you to select which fonts to use. Fonts are specified via command-line flags; there is no way to change fonts after elvis has created the first window.

The x11 interface doesn't read an app-defaults file. Instead, defaults fonts and colors are controlled via options which are usually set in the elvis.ini or elvis.rc file.

8.1.1 X11 Command-line Flags

To specify a normal font, use -font fontname or -fn fontname. Proportional fonts are not supported. If you don't specify a normal font, then elvis will use a font named "fixed" by default.

To specify a bold font, use -fb fontname. The specified font should have the same size character cell as the normal font, but elvis does not verify this. If you don't specify a bold font, then elvis will fake it by smearing the normal font rightward one pixel.

To specify an italic font, use -fi fontname. The specified font should have the same size character cell as the normal font, but elvis does not verify this. If you don't specify an italic font, then elvis will fake it by sliding the top half of the normal font rightward one pixel.

If you want to use Courier fonts, there is a shortcut: -courier size will use the normal, bold, and italic versions of the courier font in the requested size.

Elvis has a built-in icon, which is generally a good thing. Some window managers won't allow you to assign a new icon to a program that has a built-in one, so elvis has a -noicon flag which disables the built-in icon.

Elvis also supports the -geometry WxH+X+Y flag for specifying the size and/or position of the first window. Unfortunately, using this option is a little awkward, because unless you precede it with a "-gx11" flag, elvis will interpret "-geometry" as a request to use a GUI named "eometry".

The -client option causes elvis to look for an already-running elvis process on the same X server, and if there is one, send the new arguments to it. This causes the old elvis process to create new windows for file arguments. The new elvis process then exits, leaving the old one to do the real work.

8.1.2 X11 Mouse

I've tried to reach a balance between the mouse behavior of xterm(1) and what makes sense for an editor. To do this right, elvis has to distinguish between clicking and dragging.

Dragging the mouse always selects text. Dragging with button 1 pressed (usually the left button) selects characters, dragging with button 2 (the middle button) selects a rectangular area, and dragging with button 3 (usually the right button) selects whole lines. These operations correspond to elvis' v, ^V, and V commands, respectively. When you release the button at the end of the drag, the selected text is immediately copied into an X11 cut buffer, so you can paste it into another application such as xterm. The text remains selected, so you can apply an operator command to it.

Clicking button 1 cancels any pending selection, and moves the cursor to the clicked-on character. Clicking button 3 moves the cursor without canceling the pending selection; you can use this to extend a pending selection.

Clicking button 2 "pastes" text from the X11 cut butter. If you're entering an ex command line, the text will be pasted into the command line as though you had typed it. If you're in visual command mode or input mode, the text will be pasted into your edit buffer. When pasting, it doesn't matter where you click in the window; elvis always inserts the text at the position of the text cursor.

Double-clicking button 1 simulates a ^] keystroke, causing elvis to perform tag lookup on the clicked-on word. If elvis happens to be displaying an HTML document, then tag lookup pursues hypertext links so you can double-click on any underlined text to view the topic that describes that text. Double-clicking button 3 simulates a ^T keystroke, taking you back to where you did the last tag lookup.

8.2 Termcap Interface

The termcap interface is the one you'll use most often on non-graphic terminals. It looks and acts a heck of a lot like the traditional vi. The biggest addition is the support for multiple windows. (For more information on how to use multiple windows, start elvis and give the command :help ^W.)

If your terminal supports ANSI color escape sequences, then you can use the :color command to assign different colors to the six basic fonts: normal, bold, italic, underlined, emphasized, and fixed. You must assign a normal color first, e.g., ":color normal yellow".

There are three additional options when using the termcap interface: term, ttyrows,and ttycolumns. The term option contains the name of the termcap entry being used; it should correspond to the type of terminal you're using. The ttyrows and ttycolumns options give the size of the screen.

Under Win32, there is also a codepage option for detecting or changing the current code page. Win32's termcap interface also supports the mouse, using basically the same rules as the x11 interface. The only differences are that it doesn't cut & paste via the clipboard, and pressing both buttons of a two-button mouse will simulate pressing the missing middle button.

8.2.1 Termcap, Terminfo, and tinytcap

Termcap is a database of terminal characteristics, and a library of C functions for accessing that database. It was created at Berkeley to allow the original vi editor to be terminal-independent. Elvis' termcap user interface was written to use this.

AT&T created the terminfo database and library, adding a few minor features. Most modern UNIX systems use terminfo instead of termcap. Fortunately, terminfo's library contains functions which emulate the termcap functions, so the termcap interface can be compiled to work with the terminfo library.

The tinytcap.c file contains a simple reimplementation of the termcap library, for those systems (such as MS-DOS) which don't have either a real termcap, or terminfo. Tinytcap's database is hard-coded into it; to add or modify a terminal description, you need to edit tinytcap.c and recompile elvis.

8.2.2 Common termcap values

This section describes most the termcap values used by elvis. The values which deal with cursor keys and graphic characters will be described in the following sections.

Termcap field names are two characters long. Some names supply Boolean values, and others supply numeric or string values. A Boolean value is made true by giving the name; the absence of its name in a terminal's entry indicates a false value for that field, for that terminal. For numeric fields, the name is followed by a '#' character and then decimal digits specifying the value. For string fields, the name is followed by a '=' character and then a string. Fields are delimited by ':' characters.

.-------.----------------------------------------------------.
|TERMCAP|                                                    |
| FIELD |                   DESCRIPTION                      |
|-------|----------------------------------------------------|
| :AL=: | Insert a given number of lines before current line |
| :al=: | Insert one line before the current line            |
| :am:  | Automargin - cursor wraps at end-of-line           |
| :bc=: | Move the cursor back one character                 |
| :cI=: | Set cursor shape to "insert" shape                 |
| :cQ=: | Set cursor shape to "quit" shape                   |
| :cR=: | Set cursor shape to "replace" shape                |
| :cV=: | Set cursor shape to "vi command" shape             |
| :cX=: | Set cursor shape to "ex command" shape             |
| :ce=: | Clear from cursor to end-of-line                   |
| :cm=: | Move cursor to a given row/column                  |
| :co#: | Width of screen, in columns                        |
| :DC=: | Delete a given number of character at the cursor   |
| :dc=: | Delete one character at the cursor position        |
| :DL=: | Delete a given number of lines at the cursor       |
| :dl=: | Delete one line at the cursor position             |
| :IC=: | Insert a given number of characters at the cursor  |
| :ic=: | Insert one character at the cursor position        |
| :ke=: | Disable the cursor keypad                          |
| :ks=: | Enable the cursor keypad                           |
| :li#: | Height of screen, in lines                         |
| :md=: | Start bold text                                    |
| :me=: | End bold or half-bright text                       |
| :mh=: | Start half-bright text (used for showing italics)  |
| :pt:  | Terminal supports physical tabs                    |
| :se=: | End standout text                                  |
| :sg#: | Width of gap required by the :so=:se=: strings     |
| :so=: | Start standout text                                |
| :sr=: | Reverse scroll one line (limited form of :ic=:)    |
| :te=: | String that elvis sends upon exiting               |
| :ti=: | String that elvis sends when starting              |
| :us=: | End underlined text                                |
| :ug#: | Width of gap required by the :us:ue:md:me: strings |
| :up=: | move cursor up one line                            |
| :us=: | Start underlined text                              |
| :vb=: | Visible alternative to the bell                    |
| :ve=: | Set cursor shape to "quit" shape                   |
| :vs=: | Set cursor shape to "vi command" shape             |
| :xn:  | Brain-damaged newline; ignore the :am: flag        |
^-------^----------------------------------------------------^

8.2.3 Cursor Keys and Function Keys

Cursor keys and function keys generally send escape sequences when struck. Elvis needs to know what those escape sequences are, so it can recognize the keystroke and act accordingly.

The names of the fields for the arrows are pretty well standardized in termcap, but the other cursor keys are still rather unsettled. Different UNIX variants use different names for the same key. Elvis supports all common names for each key.

Function keys are even more challenging. Originally termcap only had strings which described the first 4 function keys. This was easy to extend to 9 keys, but starting with the 10th function key things get strange because termcap field names must be two characters long. Also, there was no way to describe shift-function keys, control-function keys, or alt-function keys, so I invented by own fields for them.

The following table lists all of the key field names, and the keys they refer to. For keys which may be described via more than one field name, the preferred field name is listed first. It also lists the key's label, as reported by :map and what (if anything) that key is normally mapped to.

.-----------.---------------.-----------------------------------.
| KEY LABEL | TERMCAP NAMES |            DESCRIPTION            |
|-----------|---------------|-----------------------------------|
|  <Up>     | :ku=:         | Up arrow, mapped to "k"           |
|  <Down>   | :kd=:         | Down arrow, mapped to "j"         |
|  <Left>   | :kl=:         | Left arrow, mapped to "h"         |
|  <Right>  | :kr=:         | Right arrow, mapped to "r"        |
|  <PgUp>   | :kP=:PU=:K2=: | Previous Page, mapped to "^B"     |
|  <PgDn>   | :kN=:PD=:K5=: | Next Page, mapped to "^F"         |
|  <Home>   | :kh=:HM=:K1=: | Home, mapped to "^"               |
|  <End>    | :kH=:EN=:K4=: | End, mapped to "$"                |
|  <Insert> | :kI=:         | Insert key, mapped to "i"         |
|  <Delete> | :kD=:         | Delete key, mapped to "x"         |
|  #1       | :k1=:         | F1 key                            |
|  #2       | :k2=:         | F2 key                            |
|  #3       | :k3=:         | F3 key                            |
|  #4       | :k4=:         | F4 key                            |
|  #5       | :k5=:         | F5 key                            |
|  #6       | :k6=:         | F6 key                            |
|  #7       | :k7=:         | F7 key                            |
|  #8       | :k8=:         | F8 key                            |
|  #9       | :k9=:         | F9 key                            |
|  #10      | :k0=:ka=:k;=: | F10 key                           |
|  #1s      | :s1=:         | Shift-F1 key                      |
|  #2s      | :s2=:         | Shift-F2 key                      |
|  #3s      | :s3=:         | Shift-F3 key                      |
|  #4s      | :s4=:         | Shift-F4 key                      |
|  #5s      | :s5=:         | Shift-F5 key                      |
|  #6s      | :s6=:         | Shift-F6 key                      |
|  #7s      | :s7=:         | Shift-F7 key                      |
|  #8s      | :s8=:         | Shift-F8 key                      |
|  #9s      | :s9=:         | Shift-F9 key                      |
|  #10s     | :s0=:         | Shift-F10 key                     |
|  #1c      | :c1=:         | Control-F1 key                    |
|  #2c      | :c2=:         | Control-F2 key                    |
|  #3c      | :c3=:         | Control-F3 key                    |
|  #4c      | :c4=:         | Control-F4 key                    |
|  #5c      | :c5=:         | Control-F5 key                    |
|  #6c      | :c6=:         | Control-F6 key                    |
|  #7c      | :c7=:         | Control-F7 key                    |
|  #8c      | :c8=:         | Control-F8 key                    |
|  #9c      | :c9=:         | Control-F9 key                    |
|  #10c     | :c0=:         | Control-F10 key                   |
|  #1a      | :a1=:         | Alt-F1 key                        |
|  #2a      | :a2=:         | Alt-F2 key                        |
|  #3a      | :a3=:         | Alt-F3 key                        |
|  #4a      | :a4=:         | Alt-F4 key                        |
|  #5a      | :a5=:         | Alt-F5 key                        |
|  #6a      | :a6=:         | Alt-F6 key                        |
|  #7a      | :a7=:         | Alt-F7 key                        |
|  #8a      | :a8=:         | Alt-F8 key                        |
|  #9a      | :a9=:         | Alt-F9 key                        |
|  #10a     | :a0=:         | Alt-F10 key                       |
^-----------^---------------^-----------------------------------^

8.2.4 Graphic characters

Elvis uses graphic characters for HTML mode's <pre graphic> and <hr> tags.

Originally termcap didn't support a way to access the terminal's graphic characters. A standard of sorts was eventually developed under the XENIX variant of UNIX. Later, the terminfo library adopted a different way to access the graphic characters, and this was worked back into the termcap standard, displacing the XENIX standard. The terminfo method is preferred, these days. Elvis supports both.

                      Terminfo Strings
.-------.---------------------------------------------------.
|TERMCAP|                                                   |
| FIELD |                  DESCRIPTION                      |
|-------|---------------------------------------------------|
| :as=: |Start graphic text                                 |
| :ae=: |End graphic text                                   |
| :ac=: |Maps VT100 graphic chars to this terminal's chars  |
^-------^---------------------------------------------------^
The terminfo method uses the :as=:ae=: strings for turning the graphical character attribute on and off. While in graphic mode, the value of the :ac=: string is interpreted as a list of character pairs; the first character is a VT-100 graphic character, and the following character is this terminal's corresponding graphic character. The following table lists the (text versions of) VT-100 graphic characters, and descriptions of them. It also includes IBM PC characters.
   .--------.--------.--------------------------------------.
   | VT-100 | IBM PC |             DESCRIPTION              |
   |--------|--------|--------------------------------------|
   |   'q'  | '\304' | horizontal line                      |
   |   'x'  | '\263' | vertical line                        |
   |   'm'  | '\300' | lower left corner (third quadrant)   |
   |   'v'  | '\301' | horizontal line with up-tick         |
   |   'j'  | '\331' | lower right corner (fourth quadrant) |
   |   't'  | '\303' | vertical line with right-tick        |
   |   'n'  | '\305' | four-way intersection, like '+' sign |
   |   'u'  | '\264' | vertical line with left-tick         |
   |   'l'  | '\332' | upper left corner (second quadrant)  |
   |   'w'  | '\302' | horizontal line with down-tick       |
   |   'k'  | '\277' | upper right corner (first quadrant)  |
   ^--------^--------^--------------------------------------^
So, for example, an entry describing the IBM PC would contain the following: :ac=q\304x\263m\300v\301j\331t\303n\305u\264l\332w\302k\277:
                    XENIX Termcap Strings
.-------.---------------------------------------------------.
|TERMCAP|                                                   |
| FIELD |                  DESCRIPTION                      |
|-------|---------------------------------------------------|
| :GS=: |Start graphic text                                 |
| :GE=: |End graphic text                                   |
| :GH=: |Horizontal bar                                     |
| :GV=: |Vertical bar                                       |
| :G3=: |Lower-left corner (i.e., third quadrant)           |
| :GU=: |Horizontal bar with up-tick                        |
| :G4=: |Lower-right corner (i.e., fourth quadrant)         |
| :GR=: |Vertical bar with right-tick                       |
| :GC=: |Center crosspiece (i.e., a big '+' sign)           |
| :GL=: |Vertical bar with a left-tick                      |
| :G2=: |Upper-left corner (i.e., second quadrant)          |
| :GD=: |Horizontal bar with a down-tick                    |
| :G1=: |Upper-right corner (i.e., first quadrant)          |
^-------^---------------------------------------------------^
In Xenix, a separate string is used for each line-drawing graphic character. There are also optional :GS=:GE=: strings for starting and ending graphic mode. If the :GS=:GE=: strings aren't specified, then termcap is expected to set the MSB of each character in the graphic character strings.

8.3 Open Interface

The open interface was created for use on terminals which lack some necessary capability (such as the :cm=: cursor movement command), or terminals of an unknown type. The open interface is ugly; if you have a choice, you should always use the termcap interface instead.

The open interface works on all text terminals because the only control codes it uses are backspace, carriage return, and line feed.

It only allows you to edit one line at a time. When you move to a new line (e.g., by using the j or k commands), the screen scrolls up and the new line is displayed at the bottom of the screen. This is true even when you're moving the cursor back towards the beginning of the edit buffer; the lines of the buffer will appear on the screen in reverse order! The open interface can be very confusing.

However, practically all of the normal visual commands are available. The only ones missing are those that specifically affect a whole window.

8.3 Quit Interface

The quit interface is intended to be used for executing scripts of ex commands. It performs all of the usual initialization, and then quits. It is normally used in conjunction with the -c command flag.

For example, you can have elvis load a file, print it, and then exit via the following command line...

elvis -g quit -c lp <var>somefile</var> Because the usual initialization guesses a file's display mode automatically, this one command can be used to format and print HTML documents, man pages, C code, and possibly hex dumps of binary files.