Process modes for gnu emacs

---
I have some new process modes for interacting with T and Scheme (and
shell, TeX, and Lisp) processes in gnu emacs. A description of these modes is
appended to this msg. The package itself is too large to be shipped out with
this msg -- the compressed shar file is 50kb. If you would like to try the
modes out, you may retrieve the file by anonymous ftp from zurich.ai.mit.edu
(18.26.0.176):
- log in with user id "anonymous"
- Set the transfer type to image or binary (command "binary" or somesuch).
- get pub/cmu/cmuproc.shar.Z
- leave ftp, uncompress & de-shar the file.
MIT CScheme users may prefer to remain with xscheme.el mode. See the
discussion about this is the notes below.
-Olin
------ Notes follow ------
I have written new gnu-emacs packages that provide shell, inferior lisp,
inferior scheme, and inferior T modes. These packages have the following
advantages over the standard released gnu packages:
- Input history is kept in all modes, traversed with M-p and M-n, just
like on LispM's and various fancy shells.
- Filename completion and query is available in all modes.
- Keybindings are cross-compatible among all modes.
- Keybindings are compatible with Zwei and Hemlock.
- Directory tracking is more robust in shell mode, and is *only* active in
shell mode. (Try entering "cd /" to an inferior lisp in the old package:
Lisp barfs, but the inferior lisp mode goes ahead and changes the
buffer's directory.)
- Non-echoed text entry (for entering passwords) is available in all modes.
- Shell and inferior Lisp modes are backwards compatible with the standard
gnu modes.
- One source for the inferior Lisp mode works in both emacs releases 18.4x and
18.5x. This has been the cause of confusing bugs for users who unwittingly
tried to use an 18.4x version inferior Lisp mode in an 18.5x version emacs,
and vice-versa.
- A full set of eval/compile-region/defun commands for the inferior Lisp,
Scheme, and T modes.
- New modes are easily created for new types of processes.
===============================================================================
THE BAD NEWS:
It would be nice if the shell & inferior lisp package, cmushell.el, was
completely plug-compatible with the old package in shell.el -- if you could
just name the new version shell.el, and have it transparently replace the old
one. But you can't. Several other packages (tex-mode, background, dbx, gdb,
kermit, monkey, prolog, telnet) are also clients of shell mode. These packages
assume detailed knowledge of shell mode internals in ways that are
incompatible with the new mode (mostly because of the new mode's greater
functionality). So, unless we are willing to port all of these packages, we
can't have the new shell package be a complete replacement for shell.el --
that is, we can't name the file shell.el, and its main entry point (shell),
because dbx.el will break when it loads it in and tries to use it.
There are two ways to fix this. One: rewrite these other modes to use the
new package. This is a win, but can't be assumed. The other, backwards
compatible route, is to make this package non-conflict with shell.el, so
both files can be loaded in at the same time. This is what I have
done. So the mode names and major functions have different names, e.g:
shell.el cmushell.el
-------- ----------
M-x shell M-x cmushell -- Fire up a shell
M-x run-lisp M-x cmulisp -- Fire up a lisp
shell-mode-map cmushell-mode-map -- Keybindings for [cmu]shell mode
All the names have been carefully chosen so that shell.el and cmushell.el
won't tromp on each other -- that way dbx.el and friends can happily load
in shell.el without breaking the cmushell.el package, and vice versa.
With the exception of M-x cmushell and M-x cmulisp, however, most of the name
changes are invisible to the user. Further, most of the customising
variables that are common in functionality have the same name:
inferior-lisp-program, explicit-shell-file-name, et al.
Hook variables are different, so you can customise shell-mode and
cmushell-mode differently, for instance.
By the way, it is rather easy to port the shell.el-dependent packages to use
the new stuff. There are fairly complete comments in the relevant source
files showing how to do this. Note that this backwards-compatibility hassle
*only* affects shell and inferior lisp mode; the other process-in-a-buffer
modes (Scheme, T, etc.) do not have this problem.
===============================================================================
GENERALIA:
The implementation strategy was to factor common process functionality
into a general command interpreter mode -- comint mode -- and then to
build all the specific modes on top. This provides uniform, integrated
functionality and interface across all the derived modes. Comint mode
provides the input history, filename completion and query,
non-echoed text entry, input editing, and process signalling
(e.g., ^z, ^c, ...) commands. *Any* mode built on comint mode gets
all this stuff automatically. Additionally, comint mode has general
hooks for customising it to specific command interpreters, such as
Lisp, Scheme, csh, ML, etc..
This release includes the following files:
- comint.el comint mode
- cmushell.el cmushell and cmulisp modes, built on comint mode.
- cmuscheme.el inferior Scheme mode, built on comint mode.
- tea.el inferior T mode, built on comint mode.
- tea2.el Variant of tea.el
- cmutex.el tex-mode.el with rewritten process interaction code.
Some bugs also fixed.
These packages have been in daily use by a user community of about 10-20
at CMU since August; most bugs have been shaken out. cmutex.el is less
tested. Please notify me of bugs.
The files are *extensively* commented; this should serve as sufficient
documentation. Each file includes suggestions for your .emacs file
in comments at the top. On-line documentation (C-h C-m, C-h C-f, C-h C-v)
is available for modes, commands, and variables.
This source is available on an FSF-style basis: use it any way you like
as long as you don't charge money for it or change the basis of its
availability; I assume no liability for its use.
===============================================================================
INPUT HISTORY:
There are actually two different ways to retrieve old commands for
resubmission to a process. The standard way is to use the input history
mechanism. An internal list is kept in each process buffer of the last n
inputs (default: 30). The commands M-p and M-n move through this list. This
is similar in functionality to the input history mechanisms provided by the
LispM, Hemlock, and various fancy shells (tcsh, cmucsh, ksh,...). There is
also a command, bound to C-c r, which searches backwards through the input
history looking for a substring match.
RMS doesn't like this mechanism. He has suggested an input history mechanism
that operates by searching backwards (and forwards) through the buffer for
occurrences of the prompt. The user can then resubmit the input by hitting
return.
I do not like this mechanism. If the prompt changes dynamically, you can miss
a command. False positives are also annoying. The screen jumps around a lot as
you scroll through your history. If you run a subprogram that has a null
prompt (like dc), prompt search will miss all its inputs. Etc.
However, you may try either of these mechanisms, and go with the style you
prefer. The RMS-style prompt-search stuff is available on M-N and M-P
(meta-shift-n and meta-shift-P); C-c R is bound to a command that searches for
specific commands (analogous to C-c r). If you use this stuff, you will
probably want to sharpen up the regular expression used to match the prompt in
each mode to match your particular prompt -- the default, general regexp used
in shell mode generates too many annoying false positives. (It's local
variable comint-prompt-regexp -- you should set it in a hook).
===============================================================================
MIT CSCHEME, XSCHEME.EL AND CMUSCHEME.EL:
MIT Cscheme, when invoked with the -emacs flag, has a special user interface
that communicates process state back to the superior emacs by outputting
special control sequences. The gnumacs package, xscheme.el, has lots and lots
of special purpose code to read these control sequences, and so is very
tightly integrated with the cscheme process. The cscheme interrupt handler and
debugger read single character commands in cbreak mode; when this happens,
xscheme.el switches to special keymaps that bind the single letter command
keys to emacs functions that directly send the character to the scheme
process. Cmuscheme mode does *not* provide this functionality. If you are a
cscheme user, you may prefer to use the xscheme.el/cscheme -emacs interaction.
Here's a summary of the pros and cons, as I see them.
xscheme: Tightly integrated with inferior cscheme process! A few commands not
in cmuscheme. But. Integration is a bit of a hack. Input history
only keeps the immediately prior input. Bizarre keybindings.
cmuscheme: Not tightly integrated with inferior cscheme process.
But. Carefully integrated functionality with the entire suite of
comint-derived CMU process modes. Keybindings reminiscent of Zwei
and Hemlock. Good input history. A few commands not in xscheme.
It's a tradeoff. Pay your money; take your choice. If you use a Scheme
that isn't Cscheme, of course, there isn't a choice. Xscheme.el is *very*
Cscheme-specific; you must use cmuscheme.el.
It would definitely be possible to stick the winning bits of cmuscheme.el into
xscheme.el, or vice-versa. The friendly folks at Cscheme Central may be moved
to do the former (I haven't discussed it with them). Interested parties are
invited to do the latter. I am not a Cscheme user, so I won't be doing it
myself.
-Olin