Utah Symbolic Computation Group June 1982
Operating Note No. 69
A Guide to EMODE
A Guide to EMODE
A Guide to EMODE
by
William F. Galway and Martin L. Griss
Department of Computer Science
University of Utah
Salt Lake City, Utah 84112
Last Revision: 31 January 1983
ABSTRACT
ABSTRACT
ABSTRACT
EMODE is a LISP-based EMACS-like editor that runs on the PSL
system. This document is meant to serve as a guide to using
EMODE--but will only be roughly up to date, since the system is
in a state of transition.
Work supported in part by the National Science Foundation under
Grant No. MCS80-07034.
Guide to EMODE 1
1. Introduction and Acknowledgments
1. Introduction and Acknowledgments
1. Introduction and Acknowledgments
This paper describes the EMODE editor being developed for
PSL [Griss 81]. EMODE is an interactive, EMACS like [Stallman
81a], screen editor. EMODE provides multiple windows, can
simultaneously support different "modes" of editing in different
buffers, and supports a variety of CRT terminals such as the
Teleray 1061 and the DEC VT-100.
Several people have made contributions to EMODE. EMODE
itself is based on an earlier editor EMID [Armantrout 81],
written by Robert Armantrout and Martin Griss for LISP 1.6. Tony
Carter has used EMODE to develop several large packages for VLSI
circuitry design [Carter 81, Carter 82]. Optimizations for the
Vax version, and many useful comments, have been provided by Russ
Fish. Several features have been added by Alan Snyder and Cris
Perdue at Hewlett Packard Research Labs. Cris implemented the
current version of "mode lists", while Alan has implemented a
huge number of commands and improved the efficiency of several
operations.
2. Running EMODE
2. Running EMODE
2. Running EMODE
EMODE is available as a "loadable" file. It can be invoked
as follows:
@PSL:RLISP
[1] load emode;
[2] emode();
Of course, you may choose to invoke RLISP (or PSL)
differently, and to perform other operations before loading and
running EMODE. From this point on the term "PSL" will be used to
refer to this family of systems, independently of whether they
use Lisp or RLISP syntax.
The terminal that EMODE uses by default is determined by its
LOADing the file DEFAULT-TERMINAL. At the University of Utah
this is the TELERAY driver. At other sites, some other driver
may be chosen as the default. To use a different terminal you
must LOAD in a different "driver file" after loading EMODE. For
example, to run EMODE on the Hewlett Packard 2648A terminal, you
could type:
@PSL:RLISP
[1] load emode, hp2648a;
[2] emode();
Guide to EMODE 2
The following drivers are currently available:
AAA For the Ann Arbor Ambassador.
DM1520 For the Datamedia 1520.
HP2648A For the Hewlett Packard 2648A and similar Hewlett
Packard terminals.
TELERAY For the Teleray 1061.
VT52 For the DEC VT52.
VT100 For the DEC VT100.
See section 9 for information on creating new terminal drivers.
EMODE is quite similar to EMACS [Stallman 81b, Stallman
81a], although it doesn't have nearly as many commands. A
detailed list of commands is given in appendix I. This
information can also be obtained by typing "HELP EMODE;" to
RLISP, or (equivalently) by reading the file PH:EMODE.HLP.
The notation used here to describe character codes is
basically the same as that used for EMACS. For example: C-Z
means "control-Z", the character code produced by typing Z while
holding down the control key. The ascii code for a control
character is the same as the 5 low order bits of the original
character--the code for Z is 132 octal, while the code for C-Z is
32 octal. M-Z means "meta-Z", the character produced by typing Z
while holding down the meta key. To support those terminals
without a meta key, the same result can normally be achieved by
typing two characters--first the ESCAPE character, then the Z
character. The ascii code for a meta character is the same as
the original character with the parity bit set--the code for M-Z
is 332 octal. (Some terminals use the ESCAPE character for other
purposes, in which case the "META prefix" will be some other
character.) Rather than using the EMACS convention, we write
"control-meta" characters (such as C-M-Z) as "meta-control"
characters (M-C-Z), since the latter notation better reflects the
internal code (232 octal for M-C-Z). The C-Z character is used
as a "meta-control" prefix, so one way to type M-C-Z is to type
C-Z C-Z. (Another way to type it is to hold down the meta and
control keys and type "Z".)
When EMODE is started up as described above, it will
immediately enter "two window mode". To enter "one window mode",
you can type "C-X 1" (as in EMACS). Commands can be typed into a
buffer shown in the top window. The result of evaluating a
command is printed into the OUT_WINDOW buffer (shown in the
bottom window). To evaluate the expression starting on the
current line, type M-E. M-E will (normally) automatically enter
two window mode if anything is "printed" to the OUT_WINDOW
buffer. If you don't want to see things being printed to the
Guide to EMODE 3
output window, you can set the variable !*OUTWINDOW to NIL. (Or
use the RLISP command "OFF OUTWINDOW;".) This prevents EMODE
from automatically going into two window mode when something is
printed to OUT_WINDOW. You must still use the "C-X 1" command to
enter one window mode initially.
Figure 2-1 shows EMODE in two window mode. In this mode the
top window includes everything above (and including) the first
line of dashes. This is followed by a single line window,
showing the current prompt from PSL. Beneath this is the "output
window", the window which usually shows the OUT_WINDOW buffer.
This is followed by another single line window, which EMODE uses
to prompt the user for values (not the same as PSL's prompt).
% Commands can be typed in the top window.
% When they're executed the value is printed into
% the OUT_WINDOW buffer.
x := '(now is the time);
y := cddr x;
----MAIN-----------------------------------------85%---
[7]
-------------------------------------------------------
NIL
(NOW IS THE TIME)
(THE TIME)
----OUT_WINDOW-----------------------------------75%---
File for photo: s:twowindow.photo
Figure 2-1:
Figure 2-1:
Figure 2-1: Two window mode
Figure 2-2 shows EMODE in one window mode. The "top window"
takes up most of the screen, followed by EMODE's prompt line, and
then by PSL's prompt line.
The BREAK handler has been modified by EMODE to "pop up" a
"break window menu". This is illustrated in figure 2-3. The
commands in the menu can be executed with the M-E command, and
you can also edit the BREAK buffer just like any other buffer.
If you wish to move to another window, use the C-X N command.
Guide to EMODE 4
% Commands can be typed in the top window.
% When they're executed the value is printed into
% the OUT_WINDOW buffer.
x := '(now is the time);
y := cddr x;
----MAIN-----------------------------------------85%---
File for photo: s:onewindow.photo
[7]
Figure 2-2:
Figure 2-2:
Figure 2-2: One window mode
This may cause the break window to disappear as it is covered by
some other window, but C-X P will find it and pop it to the "top"
of the screen again.
EMODE is not very robust in its handling of errors. Here's
a summary of known problems and suggestions on how to deal with
them:
Garbage collection messages "blow up":
Printing messages into EMODE buffers involves
CONSing, so the system blows up if it tries to
print a message from inside the garbage
collector. EMODE sets GC OFF at load time.
Always run EMODE with GC OFF.
Terminal doesn't echo:
This can be caused by abnormal exits from EMODE.
If PSL is still running, you can call the routine
"EchoOn" to turn echoing back on. (It's the
routine "EchoOff" that turns echoing off, and
starts "raw output" mode.)
Otherwise, as may happen on the Vax running Unix,
you will have to give shell commands to turn
Guide to EMODE 5
cdr 2; +------------------------------+
|A ;% To abort |
|Q ;% To quit |
|T ;% To traceback |
|I ;% Trace interpreted stuff |
|R ;% Retry |
|C ;% Continue, |
| % using last value |
----MAIN-----------|? ;% For more help |-
4 lisp break> +----BREAK---------------11%---+
----------------------------------------------------
NIL
***** An attempt was made to do CDR on `2', which is
not a pair {99}
Break loop
----OUT_WINDOW-----------------------------------75%---
File for photo: s:breakwindow.photo
Figure 2-3:
Figure 2-3:
Figure 2-3: A break window (doctored from the original)
echoing back on. This is best done by defining
the following alias in your ".login" file.
alias rst 'reset; stty -litout intr ^C'
(That's a "control-C", not "uparrow C".) The
"rst" command must be typed as "<LF>rst<LF>"
because carriage-return processing is turned off.
"Garbled" printout:
This is probably caused by EMODE's not running in
"raw output" mode--a problem which can be caused
by some other errors. A cure is to type C-Z C-Z
to leave EMODE, and then to call EMODE again.
This should reset the terminal mode to "raw mode"
(by calling EchoOff). (The C-Z C-Z must be
followed by a linefeed on the Vax, to force the
C-Z C-Z to be read.)
Stuck in an error:
This is often caused by trying to evaluate an
expression that lacks a closing parenthesis (or
some other terminator)--producing a message
something like:
Guide to EMODE 6
***** Unexpected EOF while reading ...
If it's obvious that an additional parenthesis
will cure the problem, you can use C-X N to
select the input window and insert it. Then
position the cursor to the left of the
parenthesis and use C-X N to select the break
window and "Quit".
Otherwise you should use the "Abort" option of
the break handler. Currently this resets the
terminal mode (at least on the DEC-20), so you'll
have to restart EMODE as described above. The
BREAK window will still be present on the screen
after restarting, even though you are no longer
in the break loop. You can use the C-X 2 or
C-X 1 command to get rid of the break window, and
then use the C-X B command to select some buffer
other than the break buffer.
3. A Guide to the Sources and Rebuilding
3. A Guide to the Sources and Rebuilding
3. A Guide to the Sources and Rebuilding
The "primary" sources for EMODE reside on UTAH-20:
PES: Is defined locally as <GALWAY.EMODE.V2>. This
directory is for the "version 2" of EMODE--being
maintained now. The corresponding "logical name"
on the VAX is "$pes".
PE: Is defined as <PSL.EMODE>. Holds sources and
documentation which may be generally useful to
the public. It includes sources for the various
terminal drivers available for EMODE. (Further
described in section 9.) The corresponding
logical name on the VAX is "$pe".
The file PES:BUILD-EMODE.CTL is the command file for
building EMODE on the DEC-20. Use SUBMIT or DO to run the
command file, which builds EMODE in two parts on the local
directory: EMODE-B-1.B and EMODE-B-2.B. PES:BUILD-EMODE.CSH (or
$pes/build-emode.csh) is the build file for the VAX. It also
builds the binary files on the "local directory". On both
machines the ".B" files for the terminal drivers and for RAWIO.B
are built separately.
The PES:EMODE.TAGS file can be used with the TAGS facility
provided by EMACS on the DEC-20. (Highly recommended!)
Guide to EMODE 7
4. Terminology: Buffers, Views/Windows, and Virtual Screens
4. Terminology: Buffers, Views/Windows, and Virtual Screens
4. Terminology: Buffers, Views/Windows, and Virtual Screens
"Buffers", "views", and "virtual screens" are the three
major data structures in EMODE. Virtual screens correspond
_______
fairly closely to what are often called windows in other systems.
They are rectangular regions on the screen, possibly overlapping,
that characters can be written to. A virtual screen provides a
sort of pseudo-hardware. The operations that can be performed on
a virtual screen are modeled after what can be done with a real
terminal. The use of a virtual screen provides these advantages:
- Operations on a virtual screen are machine independent.
(To some extent, this will be less true if we try to
support "fancier" graphics.)
- The "bandwidth problem" of maintaining the screen image
is isolated to the virtual screen package--other
programs don't have to worry about the problem.
- Several virtual screens can be shown on one physical
screen.
Virtual screens are implemented as "Structs" using the
"DefStruct" facility provided by the loadable file "NSTRUCT".
Buffers hold the data to be edited, possibly something other
than text, depending on the buffer's "data mode". Views are data
structures used to display buffers on the screen, they may be
______
made of several virtual screens. The term "window" is often used
instead of "view", when you see the one term it should be
possible to substitute the other.
Buffers and views are implemented as "environments". An
environment is an association list of (NAME . VALUE) pairs.
(These association lists are sometimes referred to as
"descriptors".) The usual method for working with an environment
is "restoring" (or "selecting") the environment by calling the
procedure "RestoreEnv". This sets each variable name in the list
to its associated value. The procedure "SaveEnv" does the
inverse operation of updating the values of each variable name in
the association list. (This is done "destructively", using
RPLACD.) The names in an environment are sometimes called
"per-environment" variables. Names in "buffer environments" are
called "per-buffer variables", and similarly for "per-view
variables".
Buffers and views are just environments that follow certain
conventions. These conventions are that they always include
certain (name . value) pairs--i.e. that they always include
certain "per-buffer" or "per-view" variables. For example, the
required per-buffer variables include:
Guide to EMODE 8
buffers_file The name (a string) of a file associated with the
buffer, or NIL if no file is associated with the
buffer.
buffers_view_creator
A routine that creates a "view" (or "window")
looking into the buffer.
In addition to the required per-buffer variables, text buffers
include variables containing things like the text being edited in
the buffer and the location of "point" in the buffer.
The required per-view variables include:
windows_refresher
(Which should actually be called the
"views_refresher") defines a routine to be the
refresh algorithm for whatever data structure
this view looks into.
WindowsBufferName
Is the name (an ID) of the buffer that the view
looks into.
Views into text buffers include additional information such as a
virtual screen to display the text in, and "cache" information to
make refreshing faster.
The choice of whether variables should be per-buffer or
per-view is sometimes unclear. For example, it would seem to
make better sense to have "point" be part of a view, rather than
a buffer. This would allow the user to have two windows looking
into different parts of the same buffer. However, it would also
require the selection of a window for the many functions that
insert strings into the buffer, delete strings from the buffer,
etc., since these routines all work around the current "point".
____
Somehow it seems unnatural to require the selection of a view for
______
these buffer operations. The current decision is to make point a
per-buffer variable.
Further details on buffers and views for different modes are
given in section 6.
A list of all the buffers in EMODE is stored in the variable
"BufferNames" as a list of (name . environment) pairs . These
pairs are created with the routine "CreateBuffer".
Guide to EMODE 9
A list of "active" views in EMODE is stored in the variable
"WindowList". This is simply a list of "environments"
(association lists as described above). Unlike buffers, views
are not referred to by name. Instead, specific views can be
referred to by storing their environment in a variable (such as
"BreakWindow").
5. Modes and Key bindings in EMODE
5. Modes and Key bindings in EMODE
5. Modes and Key bindings in EMODE
There are two aspects to "modes" in EMODE. One is the
choice of the data structure to be edited within a buffer. Until
recently there has only been one kind of structure: "text". As
discussed in section 6 EMODE now provides tools for editing
other, user defined, structures.
The other aspect of "modes", discussed in this section, is
the binding of "handler" routines to terminal keys (or sequences
of keys for multi-key commands). A simple version of this would
associate a table of handlers (indexed by character code) with
each buffer (or view). The method actually used is more
complicated due to a desire to divide keyboard bindings into
groups that can be combined in different ways. For example, we
might have a text mode and an Rlisp mode, and an optional Word
Abbreviation Mode that could be combined with either of them to
cause automatic expansion of abbreviations as they are typed.
_______
Implementing optional keyboard bindings that can removed as
_____
well as added is difficult. Consider the situation with an
optional "Abbreviation Mode" and an optional "Auto Fill Mode".
Turning on either mode redefines the space character to act
differently. In each case, the new definition for space would be
something like "do some fancy stuff for this submode, and then do
whatever space used to do". Imagine the difficulties involved in
turning on "Abbreviation Mode" and then "Auto Fill Mode" and then
turning off "Abbreviation Mode".
EMODE's solution to the problem is based on the method
______ ______
suggested in [Finseth 80]. A single, global "dispatch vector" is
used, but is rebuilt when switching between buffers. The mode
for each buffer is stored as a list of expressions to be
evaluated. Evaluating each expression enters the bindings for an
associated group of keys into the vector. Incremental modes can
be added or deleted by adding or deleting expressions from the
list. Although changing modes is fairly time consuming (more
than a few microseconds), we assume that this is rare enough that
the overhead is acceptable. NOTE that simply changing an entry
in the dispatch vector will not work--since any switching between
Guide to EMODE 10
buffers will cause the entry to be permanently lost.
The dispatch "vector" is actually implemented as a
combination of a true PSL vector "MainDispatch", indexed by
character code, and an association list "PrefixAssociationLists"
used to implement two character commands. Currently the only two
character commands start with the "prefix character" C-X,
although the mechanism is more general. Prefix characters are
"declared" by calling the routine "define_prefix_character"
(refer to code for details). Bindings for prefix-character
commands are stored in PrefixAssociationLists as an association
list of association lists. The top level of the list is
"indexed" by the prefix character, the next level contains
(character . handler) pairs indexed by the character following
the prefix character.
The list of expressions for building the dispatch vector is
called the "mode list", and is stored in the per-buffer variable
"ModeEstablishExpressions". See the following section for more
on how ModeEstablishExpressions is used in the declaration of a
mode. The procedure "EstablishCurrentMode" evaluates these
expressions in reverse order (the last expression in the list is
evaluated first) to establish the keyboard dispatch vector used
for editing the current buffer. Reverse order is used so that
____ _____
the last expression added to the front of the list will be
evaluated last. EstablishCurrentMode must be called after
changing the mode list for the current buffer and when switching
___ _______ ____ ___ ________
to a different buffer for editing from the keyboard. The routine
SelectBuffer switches to a buffer without "establishing" the
buffer's mode. This saves the cost of setting up the dispatch
vector when it isn't needed (which is the case for most "internal
operations" on buffers).
___
The expressions in ModeEstablishExpressions can execute any
code desired. This generality is rarely needed, the usual action
is to call the routine SetKeys with a list of
(character . handler) pairs. For example, the mode list for text
mode is defined by this Lisp code:
(setf FundamentalTextMode
'((SetKeys TextDispatchList)
(SetKeys BasicDispatchList)
(NormalSelfInserts)))
The RLISP mode is built "on top of" FundamentalTextMode as
follows:
Guide to EMODE 11
(setf RlispMode
(cons
'(SetKeys RlispDispatchList)
FundamentalTextMode))
This section taken from the code that builds
BasicDispatchList shows what a "key list" for the SetKeys routine
should look like:
(setf BasicDispatchList
(list
(cons (char ESC) 'EscapeAsMeta)
(cons (char (cntrl U)) '$Iterate)
(cons (char (cntrl Z)) 'DoControlMeta)
% "C-X O" switches to "next window" (or "other
% window" if in "two window mode").
(cons (CharSequence (cntrl X) O) 'next_window)
(cons (CharSequence (cntrl X) (cntrl F)) 'find_file)
.
.
.
Note that the pairs in a key list can specify character sequences
like "(cntrl X) O" as well as single characters.
At runtime, after they're created, key lists can be most
easily modified by calling the routine AddToKeyList. For example
(AddToKeyList
'RlispDispatchList
(char (meta (cntrl Z)))
'DeleteComment)
could be executed to add a new, "delete comment" handler to RLISP
mode.
The routine SetTextKey is equivalent to adding to the key
list TextDispatchList (see code). For example
(SetTextKey (char (meta !$)) 'CheckSpelling)
could be executed to add a new "spelling checker" command to text
mode (and other modes such as RLISP mode that incorporate text
mode). SetTextKey seems to correspond most closely to EMACS's
"Set Key" command.
Guide to EMODE 12
The routine "SetLispKey" is also defined for adding bindings
to "Lisp mode". (There is no "SetRlispKey" routine in EMODE,
although it would be easy to define for yourself if desired.)
6. Creating New Modes
6. Creating New Modes
6. Creating New Modes
To define a new mode you must provide a "buffer creator"
routine that returns a "buffer environment" with the required
per-buffer variables along with any other state information
needed for the type of data being edited. You need to "declare"
the mode by calling the routine "declare_data_mode". It's also
possible to associate the mode with a file extension by calling
the routine "declare_file_mode".
For example, the current EMODE declares the modes, "text"
and "rlisp", as follows:
(declare_data_mode "text" 'create_text_buffer)
(declare_data_mode "rlisp" 'create_rlisp_buffer)
(declare_file_mode "txt" 'create_text_buffer)
(declare_file_mode "red" 'create_rlisp_buffer)
The second argument to both routines is the "buffer creator"
routine for that mode. The first argument to declare_data_mode
is a "name" for the mode. The first argument to
declare_file_mode is a file extension associated with that mode.
The conventions for "buffer environments" are that they
always include certain (name . value) pairs--i.e. that they
always include certain "per-buffer" variables. These variables
are:
ModeEstablishExpressions
A list of expressions to evaluate for
establishing the keyboard bindings for the
buffer's mode.
buffers_file The name (a string) of a file associated with the
buffer, or NIL if no file is associated with the
buffer.
buffers_file_reader
A routine to APPLY to one argument--a PSL
io-channel. The routine should read the channel
into the current buffer.
buffers_file_writer
Guide to EMODE 13
A routine to APPLY to an io-channel. The routine
writes the current buffer out to that channel.
buffers_view_creator
A routine to create a "view" (or "window")
looking into the buffer. This is described in
more detail below.
For example, the buffer creator for "text mode" is:
(de create_text_buffer ()
(cons
(cons 'ModeEstablishExpressions FundamentalTextMode)
(create_raw_text_buffer)))
Most of the work is done by create_raw_text_buffer, which does
everything but determine the keyboard bindings for the buffer.
Here's the code with comments removed:
(de create_raw_text_buffer ()
(list
(cons 'buffers_view_creator 'create_text_view)
(cons
'buffers_file_reader
'read_channel_into_text_buffer)
(cons
'buffers_file_writer
'write_text_buffer_to_channel)
(cons 'buffers_file NIL)
(cons 'CurrentBufferText (MkVect 0))
(cons 'CurrentBufferSize 1)
(cons 'CurrentLine NIL)
(cons 'CurrentLineIndex 0)
(cons 'point 0)
(cons 'MarkLineIndex 0)
(cons 'MarkPoint 0)
))
Other modes based on text can be similarly defined by consing an
appropriate binding for ModeEstablishExpressions to the
environment returned by create_raw_text_buffer.
Of course we need some way of "viewing" buffers once they've
been created. The per-buffer variable "buffers_view_creator" is
responsible for creating a view into a buffer. The "view
creator" is typically invoked by the routine
"select_or_create_buffer".
Guide to EMODE 14
The required per-view variables are:
windows_refresher
Which should actually be called the
"views_refresher", is a routine to APPLY to no
arguments. This routine is the refresh algorithm
for whatever data structure this view looks into.
WindowsBufferName
Is the name (an ID) of the buffer that the view
looks into.
views_cleanup_routine
A routine that's called when a view is being
deleted from the screen. Different views may
require different kinds of cleaning up at this
point. For example, they should "deselect" any
"virtual screens" that make up the view.
The view creator for text structures is "create_text_view".
This routine typically modifies and returns the current view
(which is almost certainly also looking into text in the current
system) so that the current view looks into the new text buffer.
Most of the real work of creating text views is done by the
routine "FramedWindowDescriptor", which is typically invoked by
the routines "OneWindow" and "TwoRFACEWindows". (So, although
select_or_create_buffer is one way of creating views into a
buffer, there's quite a bit of freedom in using other methods for
creating views.)
7. Manipulating Text Buffers
7. Manipulating Text Buffers
7. Manipulating Text Buffers
The text in "text buffers" is stored as a vector of strings
in the per-buffer variable "CurrentBufferText"--with the
exception of a "current line" (stored in the per-buffer variable
"CurrentLine"), which is a linked list of character codes. The
CurrentLine is the line indexed by "CurrentLineIndex". Refer to
the routine create_text_buffer for details of the contents of a
text buffer.
It's an easy mistake to modify CurrentLine but to forget to
update the CurrentBufferText when moving to a new line. For this
reason, and because the representation used for text may change
in the future, you should use the utilities provided (mostly) in
PES:EMODE1.RED to manipulate text. The procedure "GetLine(x)"
can be used to get line x as the current line. The procedure
"PutLine()" is used to store the current line back into
CurrentBufferText. The procedure "SelectLine(x)" first "puts
away" the current line, and then "gets" line x.
Guide to EMODE 15
It would seem natural to move forward a line in the text by
doing something like
SelectLine(CurrentLineIndex + 1);
but you should resist the temptation. For one thing, SelectLine
makes little attempt to check that you stay within the limits of
the buffer. Furthermore, future representations of text may not
use integers to index lines. For example, some future version
may use a doubly linked list of "line structures" instead of a
vector of strings.
So, you should use the routines "NextIndex" and
"PreviousIndex" to calculate new "indices" into text, and you
should also check to make sure that CurrentLineIndex is within
the bounds of the buffer. You can probably just use the routines
"!$ForwardLine" and "!$BackwardLine", (or "!$ForwardCharacter"
and "!$BackwardCharacter"). You should also read some of the
code in EMODE1.RED before attempting your own modifications.
(Much of the code is rather ugly, but it does seem to work!)
8. Evaluating Expressions in EMODE Buffers
8. Evaluating Expressions in EMODE Buffers
8. Evaluating Expressions in EMODE Buffers
The "M-E" command for evaluating an expression in a buffer
(of the appropriate mode) depends on I/O channels that read from
and write to EMODE buffers. This is implemented in a fairly
straightforward manner, using the general I/O hooks provided by
PSL. (See the Input/Output chapter of the PSL Manual for further
details.) The code for EMODE buffer I/O resides in the file
RFACE.RED.
The tricky part of implementing M-E is making it fit with
the READ/EVAL/PRINT loop that Lisp and other front ends use. The
most obvious scheme would be to have EMODE invoke one
"READ/EVAL/PRINT" for each M-E typed. However, this doesn't work
well when a break loop, or a user's program, unexpectedly prompts
for input.
Instead, the top level read functions in PSL call the "hook"
function, MakeInputAvailable(), which allows the user to edit a
buffer before the reader actually takes characters from the
current standard input channel. Examples of top level read
functions are READ (for Lisp), and XREAD (for RLISP). If you
define your own read function, for example--to use with the
general TopLoop mechanism, it should also call MakeInputAvailable
before trying to actually read anything.
Guide to EMODE 16
When EMODE dispatches on M-E, it RETURNS to the routine that
called it (e.g. READ), which then reads from the selected channel
(which gets characters from an EMODE buffer). After evaluating
the expression, the program then PRINTs to an output channel
which inserts into another EMODE buffer. EMODE is then called
again by the read routine (indirectly, via MakeInputAvailable).
_______ __ ___ ______
The fact that EMODE returns to the reader means that
different buffers cannot use different readers. This can be a
bit confusing when editing several buffers with different kinds
of code. Simply switching to a buffer with Lisp code does not
cause the system to return to READ instead of XREAD.
Implementing this would require some sort of coroutine or process
mechanism--neither of which are currently provided in PSL.
(However, it may be possible to provide an acceptable
approximation by having M-E normally invoke a READ/EVAL/PRINT
operation, while preserving the MakeInputAvailable hook for
exceptional situations.)
9. Customizing EMODE for New Terminals
9. Customizing EMODE for New Terminals
9. Customizing EMODE for New Terminals
The files PE:AAA.SL, PE:DM1520.SL, PE:HP2648A.SL,
PE:TELERAY.SL, PE:VT52.SL, and PE:VT100.SL define the different
terminal drivers currently available. Terminal drivers define
some values and functions used to emit the appropriate character
strings to position the cursor, erase the screen and clear to end
of line. To define a new terminal, use one of the files as a
guide. A listing of TELERAY.SL follows:
%
% TELERAY.SL - EMODE support for Teleray terminals
%
% Author: William F. Galway
% Symbolic Computation Group
% Computer Science Dept.
% University of Utah
% Date: 27 June 1982
% Copyright (c) 1982 University of Utah
%
% Screen starts at (0,0), and other corner is offset by (79,23)
% (total dimensions are 80 wide by 24 down).
(setf ScreenBase (Coords 0 0))
(setf ScreenDelta (Coords 79 23))
% Parity mask is used to clear "parity bit" for those terminals
% that don't have a meta key. It should be 8#177 in that case.
% Should be 8#377 for terminals with a meta key.
Guide to EMODE 17
(setf parity_mask 8#377)
(DE EraseScreen ()
(progn
(PBOUT (Char ESC))
(PBOUT (Char (lower J)))))
(DE Ding ()
(PBOUT (Char Bell)))
% Clear to end of line from current position (inclusive).
(DE TerminalClearEol ()
(progn
(PBOUT (Char ESC))
(PBOUT (Char K))))
% Move physical cursor to Column,Row
(DE SetTerminalCursor (ColLoc RowLoc)
(progn
(PBOUT (char ESC))
(PBOUT (char Y))
(PBOUT (plus (char BLANK) RowLoc))
(PBOUT (plus (char BLANK) ColLoc))))
Guide to EMODE 18
10. Bibliography
10. Bibliography
10. Bibliography
[Armantrout 81]
Armantrout, R.; Benson, E.; Galway, W.; and Griss,
M. L.
____ _ _____ ______ ______ ______ _______ __
EMID: A Multi-Window Screen Editor Written in
________ ____
Standard LISP.
Utah Symbolic Computation Group Opnote No. 54,
University of Utah, Department of Computer
Science, January, 1981.
[Carter 81] Carter, T.; Galway, W.; Goates, G.; Griss, M. L.;
and Haslam, R.
_____ _ ____ _____ _____ ____ ____ ______ ___ ___
SLATE: A Lisp Based EMACS Like Text Editor for SLA
______
Design.
Utah Symbolic Computation Group Opnote 55,
University of Utah, Department of Computer
Science, January, 1981.
[Carter 82] T. M. Carter.
ASSASSIN: An Assembly, Specification and Analysis
System for Speed-Independent Control-Unit
Design in Integrated Circuits Using PPL.
Master's thesis, Department of Computer Science,
University of Utah, June, 1982.
[Finseth 80] Finseth, C. A.
______ ___ ________ __ ____ _______
Theory and Practice of Text Editors.
MIT/LCS/TM-165, Massachusetts Institute of
Technology, Laboratory for Computer Science,
May, 1980.
[Griss 81] Griss, M. L. and Morrison, B.
___ ________ ________ ____ _____ ______
The Portable Standard LISP Users Manual.
Utah Symbolic Computation Group Technical
Report TR-10, University of Utah, March, 1981.
[Stallman 81a] Stallman, R. M.
EMACS The Extensible, Customizable Self-
Documenting Display Editor.
___________ __ ___ ___ _______ _______
In Proceedings of the ACM SIGPLAN Notices
_________ __ ____ ____________
Symposium on Text Manipulation, pages 147-156.
ACM, New York, New York, June, 1981.
[Stallman 81b] Stallman, R. M.
_____ ______ ___ ______ _____
EMACS Manual for TWENEX Users.
AI Memo 555, Massachusetts Institute of
Technology, Artificial Intelligence Laboratory,
May, 1981.
Guide to EMODE 19
APPENDIX A: Default Keyboard Bindings for EMODE
APPENDIX A: Default Keyboard Bindings for EMODE
APPENDIX A: Default Keyboard Bindings for EMODE
The following commands are notable either for their
difference from EMACS, or for their importance to getting started
with EMODE:
- To leave EMODE type C-X C-Z to "QUIT" to the EXEC, or
C-Z C-Z to return to "normal" PSL input/output.
- While in EMODE, the "M-?" (meta- question mark)
character asks for a command character and prints the
name of the routine attached to that character.
- The function "PrintAllDispatch()" will print out the
current dispatch table. You must call EMODE first, to
set this table up.
- M-C-Y inserts into the current buffer the text printed
as a result of the last M-E.
- M-X prompts for a one line string and then executes it
as a Lisp expression. Of course, similar results can
be achieved by using M-E in a buffer.
A (fairly) complete table of keyboard bindings follows:
C-@ Runs the function SETMARK.
C-A Runs the function !$BEGINNINGOFLINE.
C-B Runs the function !$BACKWARDCHARACTER.
C-D Runs the function !$DELETEFORWARDCHARACTER.
C-E Runs the function !$ENDOFLINE.
C-F Runs the function !$FORWARDCHARACTER.
Tab In Lisp mode, runs the function LISP-TAB-COMMAND.
Indents as appropriate for Lisp.
Linefeed In text mode, runs the function !$CRLF and acts
like a carriage return.
In Lisp mode, runs the function LISP-LINEFEED-
COMMAND. Inserts a newline and indents as
appropriate for Lisp.
C-K Runs the function KILL_LINE.
C-L Runs the function FULLREFRESH.
Return Runs the function $CRLF (inserts a carriage
return).
C-N Runs the function !$FORWARDLINE.
C-O Runs the function OPENLINE.
C-P Runs the function !$BACKWARDLINE.
C-Q Runs the function INSERTNEXTCHARACTER. Acts like
a "quote" for the next character typed.
C-R Backward search for string, type a carriage
return to terminate the search string. Default
(for a null string) is the last string previously
Guide to EMODE 20
searched for.
C-S Forward search for string.
C-T Transpose the last two characters typed (if the
last character typed was self inserting).
Otherwise, transpose the characters to the left
and right of point, or the two characters to the
left of point if at the end of a line.
C-U Repeat a command. Similar to EMACS's C-U.
C-V Runs the function SCROLL-WINDOW-UP-PAGE-COMMAND.
C-W Runs the function KILL_REGION.
C-X As in EMACS, control-X is a prefix for "fancier"
commands.
C-Y Runs the function INSERT_KILL_BUFFER. Yanks back
killed text.
C-Z Runs the function DOCONTROLMETA. As in EMACS,
acts like "Control-Meta" (or "Meta-Control").
ESCAPE Runs the function ESCAPEASMETA. As in EMACS,
ESCAPE acts like the "Meta" key.
) Inserts a "matching" right parenthesis. Bounces
back to the corresponding left parenthesis, or
beeps if no matching parenthesis is found.
RUBOUT Runs the function !$DELETEBACKWARDCHARACTER.
M-C-@ Runs the function MARK-SEXP-COMMAND. Sets mark
at the end of the s-expression following point.
M-C-A In Lisp mode, runs the function BEGINNING-OF-
DEFUN-COMMAND. Moves backward to the beginning
of the current or previous) DEFUN. A DEFUN is
heuristically defined to be a line whose first
character is a left parenthesis.
M-C-B Runs the function BACKWARD_SEXPR.
M-C-D Runs the function DOWN-LIST. Moves "deeper" into
the next contained list.
M-C-E In Lisp mode, runs the function END-OF-DEFUN-
COMMAND. Moves forward to the beginning of the
next line following the end of a DEFUN.
M-C-F Runs the function FORWARD_SEXPR.
M-Backspace In Lisp mode, runs the function MARK-DEFUN-
COMMAND.
M-Tab In Lisp mode, runs the function LISP-TAB-COMMAND.
M-C-K Runs the function KILL_FORWARD_SEXPR.
M-Return Runs the function BACK-TO-INDENTATION-COMMAND.
Similar to C-A, but skips past any leading
blanks.
M-C-N Runs the function MOVE-PAST-NEXT-LIST. Moves to
_______
the right of the current or next list.
M-C-O Runs the function FORWARD-UP-LIST. Moves to the
_______
right of the current list.
M-C-P Runs the function MOVE-PAST-PREVIOUS-LIST. Moves
to the beginning of the current or previous list.
M-C-Q Runs the function LISP-INDENT-SEXPR. "Lisp
indents" each line in the next s-expr.
M-C-U Runs the function BACKWARD-UP-LIST. Does the
Guide to EMODE 21
"opposite" of FORWARD-UP-LIST.
M-C-Y In Lisp and Rlisp mode runs the function
INSERT_LAST_EXPRESSION. Inserts the last body of
text typed as the result of a M-E.
M-C-Z Runs the function OLDFACE. Leaves EMODE, goes
back to "regular" PSL input/output.
M-Escape In Lisp mode, runs the function BEGINNING-OF-
DEFUN-COMMAND. (See M-C-A.)
M-C-] In Lisp mode, runs the function END-OF-DEFUN-
COMMAND. (See M-C-E.)
M-C-RUBOUT Runs the function KILL_BACKWARD_SEXPR.
M-% Runs the function QUERY-REPLACE-COMMAND. Similar
to EMACS's query replace.
M-( Runs the function INSERT-PARENS. Inserts a
matching pair of parenthesis, leaving point
between them.
M-) Runs the function MOVE-OVER-PAREN. Moves over a
")" updating indentation (as appropriate for
Lisp).
M-/ Runs the function !$HELPDISPATCH, see the
description of M-? below.
M-; In Lisp and Rlisp mode runs the function
INSERTCOMMENT.
M-< Runs the function !$BEGINNINGOFBUFFER. Move to
beginning of buffer.
M-> Runs the function !$ENDOFBUFFER. Move to end of
buffer.
M-? Runs the function !$HELPDISPATCH. Asks for a
character and prints the name of the routine
attached to that character.
M-@ Runs the function MARK-WORD-COMMAND.
M-B Runs the function BACKWARD_WORD. Backs up over a
word.
M-D Runs the function KILL_FORWARD_WORD.
M-E In Lisp and RLISP modes evaluates the expression
starting at the beginning of the current line.
M-F Runs the function FORWARD_WORD. Moves forward
over a word.
M-M Runs the function BACK-TO-INDENTATION-COMMAND.
(See M-Return for more description.)
M-V Runs the function SCROLL-WINDOW-DOWN-PAGE-
COMMAND. Moves up a window.
M-W Runs the function COPY_REGION. Like C-W only it
doesn't kill the region.
M-X Runs the function EXECUTE_COMMAND. Prompts for a
string and then converts it to Lisp expression
and evaluates it.
M-Y Runs the function UNKILL_PREVIOUS. Used to cycle
through the kill buffer. Deletes the last yanked
back text and then proceeds to yank back the
previous piece of text in the kill buffer.
M-\ Runs the function DELETE-HORIZONTAL-SPACE-
Guide to EMODE 22
COMMAND. Deletes all blanks (and tabs) around
point.
M-^ Runs the function DELETE-INDENTATION-COMMAND.
Deletes CRLF and indentation at front of line,
leaves one space in place of them.
M-RUBOUT Runs the function KILL_BACKWARD_WORD.
C-X C-B Runs the function PRINTBUFFERNAMES. Prints a
list of all the buffers present.
C-X C-F Runs the function FIND_FILE. Asks for a filename
and then selects the buffer that that file
resides in, or creates a new buffer and reads the
file into it.
C-X C-O Runs the function DELETE-BLANK-LINES-COMMAND.
Deletes blank lines around point (leaving one
left).
C-X C-P Runs the function WRITESCREENPHOTO. Write a
"photograph" of the screen to a file.
C-X C-R Runs the function CNTRLXREAD. Read a file into
the buffer.
C-X C-S Runs the function SAVE_FILE. Writes the buffer
to the file associated with that buffer, asks for
an associated file if none defined.
C-X C-W Runs the function CNTRLXWRITE. Write the buffer
out to a file.
C-X C-X Runs the function EXCHANGEPOINTANDMARK
C-X C-Z As in EMACS, exits to the EXEC.
C-X 1 Goes into one window mode.
C-X 2 Goes into two window mode.
C-X B Runs the function CHOOSEBUFFER. EMODE asks for a
buffer name, and then selects (or creates) that
buffer for editing.
C-X H Runs the function MARK-WHOLE-BUFFER-COMMAND.
C-X N Runs the function NEXT_WINDOW. Selects the
"next" window in the list of active windows.
Note that some active windows may be covered by
other screens, so they will be invisible until
C-X N reaches them and "pops" them to the "top"
of the screen.
C-X O An alternate way to invoke NEXT_WINDOW.
C-X P Runs the function PREVIOUS_WINDOW. Selects the
"previous" window in the list of active windows.
Guide to EMODE 23
APPENDIX B: Some Important Fluid Variables
APPENDIX B: Some Important Fluid Variables
APPENDIX B: Some Important Fluid Variables
Here is an incomplete list of the fluid ("global") variables
in EMODE.
*outwindow A flag for PSL's ON/OFF mechanism. When T, means
that the "output" (or OUT_WINDOW) window should
be "popped up" when output occurs.
*EMODE T when EMODE is running. (Not quite the same as
"runflag" described below. For example, runflag
will be set NIL to cause EMODE to leave a
"recursive edit", but *EMODE stays T.)
*RAWIO T when "raw I/O" is in effect.
BasicDispatchList
The "key list" for "basic" operations.
BreakWindow The view for the "popup" break window.
BufferNames An association list of the
(name . buffer-environment) pairs for all the
buffers.
CurrentBufferName
The name of the currently selected buffer.
CurrentBufferSize
A per-buffer variable for text buffers, gives
number of lines actually within buffer.
CurrentBufferText
A per-buffer variable for text buffers. A vector
of lines making up the buffer.
CurrentLine A per-buffer variable for text buffers. The
contents (text) of current line--as a linked list
of character codes. (Takes precedence over
whatever is contained in the text vector.)
CurrentLineIndex
A per-buffer variable for text buffers. Index of
the "current line" within buffer.
CurrentVirtualScreen
Per-view variable for text windows (views), holds
the virtual screen used by the view.
CurrentWindowDelta
Per-view variable for text windows, gives window
dimensions as (delta x . delta y).
CurrentWindowDescriptor
The currently selected window environment.
declared_data_modes
List of (mode-name . buffer-creator) pairs for
all the declared modes.
declared_file_extensions
List of (file-extension . buffer-creator) pairs
for all modes with declared file extensions.
Guide to EMODE 24
EmodeBufferChannel
Channel used for EMODE I/O. Perhaps this should
be expanded to allow different channels for
different purposes (break loops, error messages,
etc.) (Or, perhaps the whole model needs more
thought! )
FirstCall NIL means re-entering EMODE, T means first time.
FundamentalTextMode
Mode list (list of expressions) for establishing
"fundamental" text mode.
kill_buffer_ring
Vector of vectors of strings--holds recently
deleted text.
kill_opers list of (names of) handler routines that kill
text. NEEDS MORE DOCUMENTATION!
kill_ring_index Pointer to the most recent "kill buffer".
last_buffername Name (a string) of the last buffer visited.
last_operation The "last" routine dispatched to (before the
"current operation").
last_search_string
The last string searched for by a search
command--used as default for next search command.
last_yank_point Vector of [buffer lineindex point], giving
location where last "yank" occured.
LispDispatchList
The "key list" for Lisp mode.
LispMode The mode list for Lisp mode.
MainDispatch Dispatch table (vector), an entry for each key.
minor_window_list
List of windows to be ignored by the
"next_window" routine.
ModeEstablishExpressions
List of expressions to be evaluated. Each
expression is expected to modify (add to?) the
dispatch table.
OldErrOut The error output channel in effect before EMODE
was started.
OldStdIn The standard input channel in effect before EMODE
was started.
OldStdOut The standard output channel in effect before
EMODE was started.
point A per-buffer variable for text buffers. Number
of chars to the left of point within CurrentLine.
PrefixAssociationLists
Additional dispatch information for prefixed
characters.
PrefixCharacterList
A list of the declared prefix characters.
Guide to EMODE 25
pushed_back_characters
A list of characters pushed back for EMODE's
command reader. This may be used when a command
isn't recognized by one dispatcher, so it can
push the characters back and pass control to
another dispatcher.
reading_from_output
Kludge flag, T when input buffer is OUT_WINDOW
buffer (for M-E).
RlispDispatchList
The "key list" for RLISP mode.
RlispMode The mode list for RLISP mode.
runflag EMODE continues its READ/DISPATCH/REDISPLAY until
this flag is NIL.
SelfInsertCharacter
Character being dispatched upon. (Usually the
last character typed.)
ShiftDisplayColumn
Amount to shift things to the left by before
(re)displaying lines in a text view.
TextDispatchList
The "key list" for fundamental text mode.
Two_window_midpoint
Gives location (roughly) of dividing line for two
window mode.
WindowList List of active windows (views).
WindowsBufferName
Required per-view variable giving the name of the
buffer being viewed.
Windows_Refresher
Required per-view variable giving the refresh
algorithm to be APPLYed for this view.
Window_Image Per-view variable for text views, holding
information for speeding up refresh.
Guide to EMODE i
Table of Contents
Table of Contents
Table of Contents
1. Introduction and Acknowledgments 1
2. Running EMODE 1
3. A Guide to the Sources and Rebuilding 6
4. Terminology: Buffers, Views/Windows, and Virtual Screens 7
5. Modes and Key bindings in EMODE 9
6. Creating New Modes 12
7. Manipulating Text Buffers 14
8. Evaluating Expressions in EMODE Buffers 15
9. Customizing EMODE for New Terminals 16
10. Bibliography 18
APPENDIX A: Default Keyboard Bindings for EMODE 19
APPENDIX B: Some Important Fluid Variables 23
Guide to EMODE ii
List of Figures
List of Figures
List of Figures
Figure 2-1:
Figure 2-1:
Figure 2-1: Two window mode 3
Figure 2-2:
Figure 2-2:
Figure 2-2: One window mode 4
Figure 2-3:
Figure 2-3:
Figure 2-3: A break window (doctored from the original) 5