|
This is a pre-print extract from the forthcoming O'Reilly book Lisp Outside the Box. Contents are subject to change as the book's production progresses. Feedback is most welcome, either in private by or in public by responding to the blog entry which announced this chapter. Table of Contents The Superior Lisp Interaction Mode for Emacs (or SLIME for short) is a widely used, powerful programming environment for Lisp programs. If you’re using Emacs to edit Common Lisp code then you really should consider working under SLIME. It integrates and standardizes the four basic Common Lisp development tools (listener, editor, inspector and debugger) and augments these with some handy introspective interfaces (such as definition locators and advanced symbol completion). Simple “key chords” control the most common actions: compiling a single definition or a whole file, inspecting values or locating source from backtraces, choosing a restart after an error. SLIME will boost your productivity; by making information more instantly accessible it leaves you free to get on with thinking about your application. SLIME is open source and free to use. It supports ten out of the eleven Common Lisp implementations listed in Chapter 1, Getting Started, the exception being GNU Common Lisp (GCL); it runs under GNU Emacs versions 21-23 and XEmacs version 21; it works on Unix, Mac OS X, and Windows. We’ll be working here with Clozure CL and GNU Emacs running on FreeBSD but could equally have chosen a different combination and very little would have changed. The message of this chapter is that there’s little excuse for debugging complex applications from a raw command line, and none for ignoring Lisp’s introspection facilities altogether. We’ll walk through SLIME’s most useful features and discuss some of the hairier configuration issues. I have to assume familiarity with Emacs; the initial learning curve for this application is quite steep and it’s probably beyond my remit to insist that you should study it just so you can follow this chapter. So if you’re new to Emacs I suggest you read the section called “Background” below and then skim the section called “Basic Operations”. That’ll give you a flavor of the potential of SLIME and hence Common Lisp itself to support application development at a very high level. Even if you never use SLIME, you could choose to lift ideas from the backend files it uses for talking to a range of Lisp implementations. Emacs is a freely available, open source text editor which runs in both terminal windows (Figure 18.1, “An Emacs window showing the SLIME inspector and debugger at work.”) and GUIs on a very wide variety of platforms. There are several ports, the most popular being GNU Emacs. You’ll find a good general-purpose introduction on Wikipedia, much more detail in the O’Reilly book Learning GNU Emacs by Debra Cameron, Bill Rosenblatt and Eric Raymond, and an extensive project website at
ExerciseIf you’ve never used Emacs before, visit http://www.gnu.org/software/emacs/tour/ and wander through the tour. TipIn Emacs documentation and in this chapter, Much of Emacs is written in Lisp. Emacs can be extended by
writing more Lisp. Every character you type (whether the plain
letter “q” or some fancy control sequence) invokes a
Lisp function; in the finest traditions of Lisp such functions can
be defined and redefined on the fly, i.e. without restarting Emacs.
When it starts up, Emacs loads Lisp forms from the
;; Control whether quotes are curly (“”) or straight ("")
(global-set-key [f9] 'toggle-sgml-quotes)
(define-key sgml-mode-map "'" 'sgml-insert-single-quote)
(define-key sgml-mode-map "\"" 'sgml-insert-double-quote)
(defvar sgml-quotes-p nil)
(defun toggle-sgml-quotes ()
(interactive)
(setf sgml-quotes-p (not sgml-quotes-p))
(message (format "Fancy quotes %s" (if sgml-quotes-p "on" "off"))))
(defun sgml-insert-single-quote ()
(interactive)
(insert (if sgml-quotes-p "’" "'")))
(defun sgml-insert-double-quote (p)
(interactive "P")
(insert (if sgml-quotes-p
(if p "”" "“") ; C-u " for close quote
"\"")))
The Lisp in Emacs, Emacs Lisp
provides built-in support for programming the Emacs text editor
with functions such as (require 'cl) CautionThis still doesn’t give you the whole of Common Lisp. In particular CLOS is absent. See http://www.gnu.org/software/emacs/manual/html_mono/cl.html for details. Emacs is much more than an editor. Of particular interest here:
you can run shells in Emacs windows; you might then run an
interactive Lisp session in such a shell. Emacs supports this with
Inferior Lisp mode (the word
“inferior” here is not a value judgement but means that
Lisp is running as a subprogram under the auspices of Emacs). And
then, for example, if you’re editing Lisp code the key
binding Emacs comes bundled with Linux, FreeBSD, and Mac OS X. ExerciseEstimate how many people have access (whether or not they use it) to Emacs Lisp. TipEmacs uses the term point to refer to the text cursor location and I’ll be doing the same here. So “the symbol under point” means “the symbol under the text cursor”. This should be very straightforward. The project home page for SLIME:
includes links for a thorough manual, an hour-long video tutorial, the slime-devel mailing list which should be your first port of call if you need technical help, and for downloads:
Download and unpack the distribution, for example using
(setq inferior-lisp-program "/home/ndl/lisps/ccl/scripts/ccl") (add-to-list 'load-path "/home/ndl/chapter-18/slime-2009-08-26/") (require 'slime-autoloads) (slime-setup '(slime-fancy)) I really did hope to write this book without mentioning
Finally, evaluate the above forms (e.g. M-x slime TipProblems? Check your When SLIME starts, it fires up the inferior Lisp and loads into it a server called Swank with which it then communicates using a socket protocol. Swank comes with a backend file for every supported implementation. ExerciseLocate and take a brief look at your implementation’s
backend file. They’re all in the top level SLIME directory.
Also take a look at SLIME creates three initial buffers, two of which are not much
use other than for troubleshooting. Some SLIME features don’t work with all Lisps. This will
depend on what the underlying implementation supports. Look for
“Warning: These Swank interfaces are unimplemented” in
the In both source files and the listener, SLIME’s completion can expand each component of a
hyphenated symbol: TipSymbol completion assumes and encourages consistent use of lower case. Figure 18.2. Interacting with the listener. The echo area shows the argument list for the form we’re entering and the *Completions* buffer lists all external symbols in the ASDF package starting with the character *. ![]() The space key inserts a space character but has a secondary
action in both source files and the listener: it prints to the echo
area the argument list of the operator which you’re working
on, highlighting the argument which comes next (Figure 18.2,
“Interacting with the listener. The echo area shows the
argument list for the form we’re entering and the
*Completions* buffer lists all external symbols in the ASDF package
starting with the character *.”). If you want to do this
without inserting spaces (for example, in a read-only buffer) then
use You can look up Hyperspec
documentation for the symbol under point with The (global-set-key (kbd "C-c s") 'slime-selector) It offers you a choice of single letter “commands” for specifying which buffer you’re after, among which are:
The upshot of this is that TipIf you accidentally kill the REPL buffer, open a new listener
with
ExercisePick a Common Lisp symbol with a straightforward definition
( TipHow well Note while you’re floating around the source that SLIME
understands reader conditionals: If you’ve used TipThe command Once you’ve found the function you’re looking for,
maybe you’d like to trace it? Use Figure 18.4. Compiler warnings provoked by two deliberate mistakes. The source for all warnings is underlined and the “current” one highlighted, a description of the warning itself is in the echo area. Use M-n (next) and M-p (previous) to cycle through the warnings. ![]() The workhorse for compiling and executing the top-level form at
point is To compile and load the current source file, use If the compiler hits badly broken syntax, such as If the compiler issues any notes or warnings then the offending
forms will be annotated (by underlining them) and the warnings
listed in a SLIME also provides commands for evaluating without explicit
invocation of the compiler. In particular, ExerciseWe’ve seen the Caution
Figure 18.5. Entering the debugger. The condition is reported first, followed by the restarts. A backtrace follows further down. ![]() Any errors signaled by the inferior Lisp are debugged in a popup
SLDB buffer (Figure 18.5,
“Entering the debugger. The condition is reported first,
followed by the restarts. A backtrace follows further
down.”). SLDB supplies a number of commands for
navigating through stack frames and invoking restarts. You
don’t have to remember what all of these are because
Figure 18.6. Frame details in SLDB. M-n shows the variables from the next frame down and—if it can—also opens the source file for that frame and highlights your position in the source. ![]() ExerciseEvaluate something which will signal an error. If you
don’t have anything else to hand then TipTo interrupt Lisp and enter the debugger, type You need to know what’s going on inside your data structures; poking around in the guts of objects which you’ve grabbed from the listener or debugger should become second nature. This is where the inspector, one of the most powerful tools available to Lisp programmers, comes in. This is a tool for displaying a “snapshot“ of some Lisp object, exposing its components and allowing you to reset them or inspect them recursively. We’ve already met the SLDB shortcuts for invoking the
inspector. If you’re in another SLIME buffer use TipInspect the last value printed by the REPL with The inspector’s display varies according to the class of the object you’re inspecting. The convention is to show a human-readable description at the top followed by a list of internal values (methods for a generic function, slots for a general CLOS object, and so on). TipYou can control how this display works; see the section called “Customizing the Inspector” below. Once you’re in the inspector, as for the debugger,
CautionTake care not to accidentally invoke actions which will destroy your data. A one-key action to clear a hash table isn’t always that convenient. To override the supplied behavior, see the section called “Customizing the Inspector” below. SLDB maintains a stack of inspected values: each time you press
Exercise(Figure 18.7,
“Inspecting a simple CLOS object. See the exercise in this
section.”) Define a class and inspect an instance of it;
use Two other useful inspector key bindings are:
We saw earlier a basic configuration technique for SLIME: you register the location of an inferior Lisp, tell Emacs where to find SLIME, and then call: (require 'slime-autoloads) (slime-setup '(slime-fancy)) The
(add-hook 'slime-mode-hook
(lambda ()
(unless (slime-connected-p)
(save-excursion (slime)))))
The argument to You’re not confined to always using the same inferior
Lisp. If you invoke In addition to the configurations above, both SLIME and Swank
can be customized. For SLIME, use the
Emacs facility Swank is customized by setting variable values in your
You can invoke macroexpansion of the form beginning or ending at point with any of:
The macroexpansion appears in a popup buffer (so you can close
it with SLIME manages indentation of macro bodies (for example: in a
macroexpansion buffer, or in the listener) by treating TipDiscover suitable values for this property either from the symbol you care about in an Emacs session in which that symbol hasn’t been overridden yet, or by looking at the properties of other symbols that have similar argument lists. SLIME caches symbols’ indentation properties. It will stay
up-to-date on macro definitions in the current package. When a new
package is created (typically this means you’ve been loading
code) SLIME scans every symbol in the system. These strategies are
usually good enough and in the rare cases when they’re not
you can force an update with The separation of SLIME into an Emacs interface and the Swank backend makes it relatively easy to run the Emacs side and Lisp session on different machines. This practice might come in handy if you ever need to debug a remote server. You’ll need ssh access to the server’s host and you might want to perform the first of the following steps before the server runs aground. TipTerminology: the machine running code which you want to debug is the “server” (in particular it’s going to serve Swank) and is “remote” to you. Your machine is the “client”.
If you want to serve Swank on a port other than 4005 then
specify a value for If you want to share source files between client and server, you
can do this using TRAMP (remote file
editing module for GNU Emacs). Load the The inspector display is controlled by the generic function
TipUse Each method takes an object as its single argument and should return a list specifying how to render the object for inspection. Every element of the list must be one of the following forms:
Here’s a very simple example:
(defclass animal ()
((legs :accessor animal-leg-count :initform 0)))
(defmethod swank-backend:emacs-inspect ((self animal))
(let ((count (animal-leg-count self)))
`("Hello. "
(:value ,count ,(format nil "This animal has ~r leg~:p." count))
(:newline) (:newline)
(:action "Grow another one"
,(lambda () (incf (animal-leg-count self)))))))
A new instance of #<ANIMAL 200CE94F> -------------------- Hello. This animal has zero legs. Grow another one Select the first line of text to inspect the number zero. Click on the action to increment the animal’s legs slot and update the display. Table 18.1. Key bindings introduced in this chapter
|