Resistance is Futile - LispWorks Editor Customizations
Wednesday, August 31, 2005
I normally use SLIME with Emacs when I'm writing Lisp code (even when I'm using a commercial CL like ACL or LispWorks) as I feel it offers a superior editing environment. However, if you're using one of the commercial CL's, you may be tempted by their own editors due to the tighter integration there will be between the IDE editor and the other tools (profiler, debugger, stepper, system browser, etc) provided by the CL vendor. There are several different approaches that can be taken if you like using Emacs but also want to utilize your vendor's tools as much as possible:
- Separate Emacs Approach: Use Emacs when editing and the IDE tools only when necessary: This is the approach that I've tended to favour in the past. I've gotten to the stage where I really dislike using alternative editors when working with Lisp code. When I do happen to be using a commercial Lisp, I tend to only make use of the vendor's tools when I really need them and spend most of my time in Emacs/SLIME.
- Integrated-Emacs Approach: Offer Emacs as an alternative editor: This is the approach that Franz has adopted with ACL. They give you the option of using either their native editor or Emacs with ELI (their Emacs Lisp major mode for working with CL code). If you're using Franz's CL and only Franz's CL, this is a great option. However, ELI only works with Franz's CL (although at one stage some people attempted to port it to other CL's, those efforts were largely dropped in favour of SLIME once SLIME got "critical mass"). So, if you ever work with other CL's, it means you need to use a different Emacs major mode when working with the alternative CL's - a bit of an irritant.
- Borg Approach: Enhance the native editor by making it more Emacs-like: This is the approach that LispWorks have adopted with their editor. They not only provide an Emacs look and feel to their editor, they also provide a very extensive set of Emacs key bindings as well as the ability to create custom editor commands. In addition (with the commercial versions of their product), source code for the editor is provided so that it too can be extended. So, theoretically, this should allow you to assimilate whatever you currently do in Emacs/SLIME in the LispWorks editor [which is why I call it the "Borg Approach" ;-)]. However, in practice, LispWorks editor customizations tend to be not very common as there aren't a lot of examples that people can draw on for sample code (which is one of the reasons why Emacs Lisp customizations became so popular).
- Coexistance Approach: Combine usage of both an "enhanced" native editor (with the IDE's tools) and Emacs/SLIME: This is an attempt to combine the best of both worlds. Unfortunately, in order for this to be effective, elements of approach #3 have to be incorporated as well; otherwise, the native editor is never really utilized, thus leading to this becoming a "de facto" #1 approach. Therefore, for this approach to be successful, functionality and key bindings should be pretty consistent across both the native editor and Emacs/SLIME.
The lw-add-ons package basically adds a lot of the special functionality in SLIME to the LispWorks editor. Some of the things it adds are (Note: the list below is culled from Edi's documentation but I've condensed it and used the default key bindings as examples - you can specify alternative bindings if you choose):
- Symbol completion: Symbol completion is set up to work more or less like
SLIME's
slime-complete-symbol*function, i.e. you can type, e.g.,m-v-band press TAB and it'll be expanded tomultiple-value-bind. - Information about the arguments of a function: When you press the space key within an s-expression, it inserts a space and shows the argument list of the nearest enclosing operator in the echo area. It will (optionally) also show the documentation string of the operator.
- Transient mark mode: The editor tries to emulate GNU Emacs' transient mark mode
(normally bound to
C-SPCand/orC-@). This results in the marked region always being highlighted. - Search and replace: The editor commands to find and replace strings are modified in
such a way that they only operate on the marked region if there is
one. Also, the effects of a "
Replace..." command can be undone with a single "Undo" command. The editor command "Continue Tags Search" and all commands (like, say, "Edit Callers") that make it applicable (see the LispWorks Editor User Guide) push the current position of point onto a definitions stack before they move to a new position. You can walk back through this "history" using the new editor command "Pop Definitions Stack". - Online documentation: The editor command "
Meta Documentation" (bound toF5in the sample init file) tries to find HTML documentation for the symbol at point and immediately shows it using the default web browser. This applies to the HyperSpec, the LispWorks reference manuals, the MOP, and some other useful stuff, e.g. format strings like~*, reader macros like#x, and loop clauses likeloop:until. Finally, HTML documentation for libraries like CL-PPCRE that have Hyperdoc support will also be found. - ASDF integration: ASDF system definitions can (optionally) be translated to Common Defsystem definitions whenever you load or compile an ASDF system.
- Listener shortcuts: Similar to SLIME's
slime-handle-repl-shortcutyou can press,(comma) in the listener and then choose from a number of shortcuts to perform administrative tasks like loading a system via ASDF or changing the current directory. - SLIME Integration: There is a convenience function for starting up communication between LispWorks and SLIME. This is useful if you regularly use Emacs/SLIME as well as the LispWorks editor.
- Miscellaneous: There are a number of additional functions that make life easier for the developer. These are covered in the documenation.

Since I always start up Emacs/SLIME when I use LispWorks, I've added
(lw-add-ons:start-swank-server) to the end of my
.lispworks file as well. This starts up communication with
Emacs/SLIME (or anything else that communicates using SWANK's
protocol). Since I use the Personal version of
LispWorks (which doesn't support initialization files) on Mac OS X, I use the
following Applescript script to launch LispWorks, load the
.lispworks file and then load Emacs and connect to LispWorks via SLIME:tell application "LispWorks Personal" activate tell application "System Events" tell process "LispWorks Personal" repeat until get frontmost end repeat keystroke return tell window "LispWorks Personal Edition" click button "Close" end tell tell window "Listener 1" if exists sheet 1 then click button "Close" of sheet 1 end if keystroke "(when (probe-file \"~/.lispworks\") (load \"~/.lispworks\"))" keystroke return end tell end tell end tell end tellI documented this technique previously. If you're using Win32 rather than Mac OS X, you can do the same sort of thing using a similar approach. Of course, if you're using either the Professional or Enterprise versions of LispWorks, you don't have to resort to these work-arounds as LispWorks will automatically load the .lispworks file on startup.
-- some people might need to uncomment/modify the following line -- do shell script "sleep 2"
tell application "Aquamacs Emacs" activate tell application "System Events" tell process "Emacs" tell window 1 key code 53 keystroke "x" keystroke "slime-connect" keystroke return keystroke return keystroke return end tell end tell end tell end tell
So, if you're a LispWorks user and you like SLIME too, you should really have a look at Edi's lw-add-ons package. It will definitely make coexistance a lot easier for you. In addition, regardless of whether or not you use SLIME, you will almost definitely learn a thing or two about customizing the LispWorks editor by having a look at Edi's code. And, you will probably also be impressed with the functionality that has been incorporated into LispWorks from SLIME. SLIME is like the Borg - assimilation is just a matter of time and resistance is futile. ;-)

