Following up on my transcript/review of the UCW “Hello World” screencast, here is my review of Marco Barringer’s SLIME movie. (Description, 150MB .mov, Torrent, watch online). This screencast was more difficult to annotate because:
- It was almost 3x as long (55 min vs. 20)
- It covered more topics (Linux, Emacs, Lisp, SLIME)
I did find it much more interesting though because it showed off a lot of the cool features in those topics, whereas the UCW screencast was mostly just instructional. Also, I don’t know if I’ll ever use UCW for an app, but I’m already using the LELS stack and plan on using it for a long time to come.
Looking back at my UCW reference, I think the format worked for that screencast because it was mostly just straight Lisp code. In the SLIME movie, the Lisp code is the least useful part – it’s just the vehicle for showing off the tools. So there’s a mix of Linux commands (unfortunately omitted because WordPress or Apache or somebody thinks they’re a security problem), Emacs key chords, Emacs Lisp code, and Common Lisp code. I’m leaving out most of the Common Lisp code for the morse code translator to focus on what’s more relevant. Also, I added links to documentation for the features shown. Hopefully this will make it easier to watch the movie and get straight to work on your own projects!
NOTE: In places where a file path is shown, I replaced directories specific to Marco’s user account with “[user]“. You can replace this with your own user-specific path.
- Setting up SLIME, Emacs
- Working in SLIME
- Using the SLIME debugger (sldb)
- Emacs tools for writing Lisp code
- More debugger demonstration
0:15 Architecture: SLIME is two parts. An Emacs mode to handle commands, the debugger, all IDE modes, etc, and Swank, a server program that runs in the Lisp environment. Emacs connects with Swank over a typical IP/port protocol, so it can connect to a local or remote Lisp instance. This demo will show connection to a remote Lisp instance (SBCL, in this demo).
NOTE: Robert Goldman points out that this setup is a little dated, and the current setup is simpler. See the links in this comment.
0:25 Recommendation to always work with the latest build of SLIME from CVS. NOTE: This movie was made several years ago – is this still a valid recommendation or is SLIME stable enough to just use the released version without any worries?
EDIT: vanekl from c.l.l says you also need to add this to your .emacs file:
(slime-setup '(slime-fancy slime-asdf))
1:03 Setting up SBCL to be able to load Swank
1:37 Edit (or create) the SBCL initialization file. (The directory he used was /home/[user]/.sbclrc ) Add the following code:
(require :asdf)(push "/home/[user]/systems/" asdf:*central-registry*)
2:53 Create a /home/[user]/systems/ folder and create a link to /home/[user]/slime/swank.asd in that folder
3:08 In the SBCL prompt, load Swank by typing
(asdf:oos 'asdf:load-op :swank) ;oos = operate on system
3:23 Use a secure shell to create a communication link for Slime and the remote Swank process
3:56 Swank will attempt to use second stream for output. This makes things faster and helps avoid odd hangups. It is off for the demo to avoid having an extra port open. To disable it, enter the following in the SBCL prompt:
(setf swank:*use-dedicated-output-stream* nil)
4:37 To start the Swank server, enter this at the SBCL prompt:
EDIT: this command was deprecated in 2006. The new command is:(swank:create-server)
4:48 Configure your local emacs by creating a slime.el file. This should go in the directory below your .emacs file. For Marco, it was:
4:59 Selected contents of Marco’s slime.el file, with comments related to each setting. (Marco’s full slime.el file and his Highly Opinionated Guide to Editing Lisp Code with Emacs including more about his key bindings)
;need to run same version of slime on both machines(add-to-list 'load-path "/Users/[user]/lisp/slime/") ; local directory, where does emacs find slime(require 'slime);tell emacs to enter slime mode when editing a lisp file(add-hook 'lisp-mode-hook (lambda () (slime-mode t))) (add-hook 'inferior-lisp-mode-hook (lambda () (inferior-slime-mode t))) (setq inferior-lisp-program "/Users/[user]/bin/[openmcl/sbcl/?]" ;what to run if slime is local lisp-indent-function 'common-lisp-indent-function ;as opposed to elisp indentation slime-compile-symbol-function 'slime-fuzzy-complete-symbol ;other options - see documentation common-lisp-hyperspec-root "file:///Users/[user]/lisp/HyperSpec/" ; slime-startup-animation nil) ;translates from emacs buffer to filename on remote machine (setf slime-translate-to-lisp-filename-function (lambda (file-name)(subseq file-name (length "/ssh:[userid]:"))) slime-translate-from-lisp-filename-function (lambda (file-name) (concat "/[userid]:" file-name)))
7:10 In Emacs, start SLIME and connect to remote Lisp by entering the following key chord:
Enter the IP address and port number and you will then be connected to remote REPL
EDIT: To connect to a local lisp instance, use:
8:18 SLIME REPL Presentations
*, **, *** objects returned by previous evaluations
9:25 REPL shortcuts – pressing ‘,’ in the REPL lets you enter commands in the minibuffer. Enter the command ‘help’ to see all available shortcut commands.
10:45 Key chords to find out information about a symbol: (see also Documentation)
C-h k = describe command (general Emacs key chord)
C-c C-d d = Describe symbol
C-c C-d h = Hyperspec lookup
12:25 Package declarations.
(defpackage :morse ; create a new package(:use :common-lisp)) ; include supporting packages(in-package :morse) ; this file belongs in the package just created
C-M-x = slime-eval-defun (slime-eval-toplevel)
C-x C-e = slime-eval-last-expression (evaluates form immediately preceding cursor)
13:45 The SLIME Selector lets you jump to a number of places with a single key. By default it isn’t bound to any key. Enter this in the slime.el file to bind it to F12 (change binding key as you wish):
(define-key global-map (kbd "<f12>") 'slime-selector)
Some SLIME Selector Locations:
? – A help buffer listing all
slime-selectors‘s available buffers.
r – The REPL buffer for the current SLIME connection.
d – The most recently activated SLDB buffer for the current connection.
l – The most recently visited
s – The
*slime-scratch*buffer. See slime-scratch.
15:15 Pressing ‘ ‘ (space) after a typing a function shows the parameter list in the minibuffer.
16:25 Marco does a cool demonstration of Emacs keyboard macros. I have no idea how he did it and I’m not ready to dive into Emacs documentation just yet. Enjoy the link!
EDIT: Reader jeep says:
With standard keybindings, the macro at 16:25 could be:
(#\ C-f M-SPC ‘ C-e ‘) C-n C-a
Start the keyboard macro with C-x (
Then insert the characters (#\
Go forward one character
Get rid of all but one space (M-SPC)
Insert the character ‘
Go to the end of the line
Insert the characters ‘)
Go to the next line and then back to the beginning of the line.
Then close the macro with C-x )
Then C-x e to execute it and e to repeat.
17:05 Demonstration of Emacs sexp navigation. See Marco’s slime.el file for how to bind these functions to keys.
19:35 SLIME Completion in REPL. Press tab in the REPL and a temporary buffer will show information about all possible matches. There are three different kinds of completion. In the screencast, Marco is using fuzzy completion, which can be accessed in two ways:
- Key Chord C-c M-i
- Adding this to your slime.el file:
(setq slime-complete-symbol-function 'slime-fuzzy-complete-symbol)
22:20 Welcome to the SLIME debugger buffer (sldb)
22:27 Backtrace and frames. The documentation is more thorough. I’ll list which commands he uses at which time so you can find a demonstration for them.
23:00 Use ‘t’ to toggle details when on a backtrace frame
24:10 In debugger/backtrace frame
v = sldb-show-source
a = sldb-abort; invoke the abort restart
M-n = next command in REPL history
M-p = previous command in REPL history
26:00 Optional declarations – these setting are used to ensure all debugging information is shown for the demo
; make sure all debugging is shown for demo(declaim (optimize (speed 0) (safety 3) (debug 3)))
27:00 Emacs tools for writing Lisp code – I’m not sure if any of these have default bindings or if you have to define them in the slime.el file. I wrote down what he said in the video, and you can refer to his slime.el file for reference on how to setup your own.
27:15 Auto-closing parentheses
27:58 Sexp navigation
C-n = forward sexp (non-standard binding)
C-h = backward sexp (non-standard binding)
28:40 Transpose sexps
C-t = transpose-sexps ; swaps sexp on cursor line with the next one below it
29:10 kill sexp
C-k = kill-sexp ; deletes form immediately after point
29:45 M-[num] ( = wrap [num] close parentheses after next sexp
33:35 Recompile file, demonstration of the compiler notes buffer. The form where error is present is underlined (warning = orange, error = red). When there are multiple warnings/errors, you get a tree buffer.
M-n = next note
M-p = previous note
v = view source
35:00 When you’re on a warning and you hit enter, it takes you to the place in the file where the error is
35:45 Debugging methods
C-c C-v h = hyperspec documentation
M-. = jump to source code definition
C-c RET = Macroexpand 1
37:42 Using asdf-install to download and configure an external package. At the REPL, type
(require :asdf-install)(asdf-install:install :split-sequence)
You will get this error “No key found for key…” – unless you have the public key of the library creator. See documentation for more details. Asdf-install will download, unpack, compile, and load source for the package you select.
39:02 Inspecting a package
46:18 Summary of topics covered:
- slime debugger
- inspecting frames
- ways to send code from emacs to lisp
- ways to inspect running image for more info
47:20 Inspecting objects that aren’t printable – current value of that variable in the call stack. This is useful when there’s an error and you don’t know what’s wrong – you can look at actual values
i [when on a frame] = evaluate expression in the stack context of that frame
50:25 Cross reference facility – for instance,you add new parameter to a function and you want to update every call to it
C-c < = slime-list-callers
C-c > = slime-list-callees
53:25 Final thoughts
M-x slime-disconnect = close connection between emacs and SWANK/Lisp
(follow the discussion about this on comp.lang.lisp)