Keyboard tips
- Use the Standard US keyboard layout. The US keyboard's layout (unlike the western European keyboard layouts) makes typing the punctuation characters you need in programming languages easy.
- Learn to touch-type.
- Invest in a quality keyboard.
Key Swapping
- Alt key for Meta, not Escape.
- Turn Capslock into Control.
- Swap Capslock and Backspace (Rubout in LM).
- Swap parentheses and brackets (US layout).
- Alt and Altgr are now Control.
- Win keys are now Meta
- Control keys are now Alt
- Menu key is Compose (or Altgr).
- Alt+arrows works like C-M-f, C-M-b, C-M-u, C-M-d, etc. (like PLT DrScheme)
- Using a European PC 105 keyboard, the less-than (
Some xmodmap files that describe the Lisp machine keyboard on the picture above reasonably faithfully can be found here.
The xkeycaps program takes care of this on X, MacOS users can use uControl, Windows users can use XKeymacs.
In just about every programming language I've ever used (C, Java, Perl, bash and LISP), and in normal prose, parenthesises occur far more often than the square bracket characters. So it's important to make typing the parenthesis easy:
(keyboard-translate ?\( ?\[) (keyboard-translate ?\[ ?\() (keyboard-translate ?\) ?\]) (keyboard-translate ?\] ?\))
This assumes that the [ and ] are easy to reach unshifted chars.
The keyboard-translates above can interfere with pasting text using the mouse in emacs. Another way to accomplish the same thing while limiting the effect to Slime is:
(define-key slime-mode-map (kbd "[") 'insert-parentheses)
(define-key slime-mode-map (kbd "]") 'move-past-close-and-reindent)
(define-key slime-mode-map (kbd "(") (lambda () (interactive) (insert "[")))
(define-key slime-mode-map (kbd ")") (lambda () (interactive) (insert "]")))
If using Paredit, this code can be used to swap parentheses and square brackets:
(define-key paredit-mode-map (kbd "[") 'paredit-open-round)
(define-key paredit-mode-map (kbd "]") 'paredit-close-round)
(define-key paredit-mode-map (kbd "M-[") 'paredit-wrap-round)
(define-key paredit-mode-map (kbd "(") 'paredit-open-square)
(define-key paredit-mode-map (kbd ")") 'paredit-close-square)
Structured editing
What is structured editing?
Structured editing is a way of editing source code which attempts, as much as is possible, to keep the source code consistently valid. This means, among other things, that the inserting of an open parenthesis should insert the closing one as well (similarly for ").
Taylor R. Campbell (Riastradh on #lisp) has written a package of lisp editing code called paredit. The rest of this page uses functions defined in that package.
Start with paredit-open-list it inserts both the open and the closing parenthesis and then leaves the cursor between the two (unless we're in a comment or string, in which case it inserts a lone ( character). After filling in the LISP form, use the paredit-close-list command which moves past the closing parenthesis and reindents the line. Here's my setup:
(define-key slime-mode-map [(?\()] 'paredit-open-list) (define-key slime-mode-map [(?\))] 'paredit-close-list) (define-key slime-mode-map [(return)] 'paredit-newline)
Unstructured editing
So how do you insert a simple, standalone "(" or ")" character? I happen to have the "=" character directly below ")" and the "\" character just to the left of that; so here's what I use:
(define-key slime-mode-map [(control ?\=)] (lambda () (interactive) (insert "(")))
(define-key slime-mode-map [(control ?\\)] (lambda () (interactive) (insert ")")))
Choose something that makes sense to use and which requires at most one key press (though it will probably be modified). Even with structured editing you'll still need to insert lone parenthesis every now and then. Note: You can also just as easily do C-q ( and C-q ); personally, I insert lone parenthesises often enough that that's too many keypresses for my tastes.
Splicing, Dicing and Moving Around
When editing LISP code, you shouldn't think of the source code as text, but as program structure (SEXPs). With parenthesis-aware editors, we get the same functionality used in IntelliSense (otherwise a separate IDE component in other languages). The basic lists/program manipulation commands (basic EMACS bindings) are:
- transpose-sexps (C-M-t) - swap the sexp before point with the sexp after point.
- backward-sexp (C-M-b) - move to before the preceding sexp.
- forward-sexp (C-M-f) - move after the following sexp.
- kill-sexp (C-M-k) - kill the following sexp.
- backward-up-list (C-M-u) - move point to the start of the enclosing list.
- up-list (not bound by default) - move forward out of the current enclosing list.
- down-list (C-M-d) - move the just after the open paren of the next list.
- mark-sexp (C-M-@) - Keep the cursor at the start of an s-exp and executing this key strokes highlight the entire S-expression.
When editing LISP code you will use these the forward/backward/transpose-sexp functions far more often the the char versions, I'd suggest swapping them so that, for example, C-M-t (transpose-sexp) is C-t and C-t (transpose-char) is C-M-t:
(define-key slime-mode-map (kbd "C-t") 'transpose-sexps) (define-key slime-mode-map (kbd "C-M-t") 'transpose-chars) (define-key slime-mode-map (kbd "C-b") 'backward-sexp) (define-key slime-mode-map (kbd "C-M-b") 'backward-char) (define-key slime-mode-map (kbd "C-f") 'forward-sexp) (define-key slime-mode-map (kbd "C-M-f") 'forward-char)
Use the standard keybindings for a bit and after you've figured out how they work and how often you use them, chose some keybindings based on your preferences. For example, I have a Dvorak keyboard where the H, T, and N keys are located directly under the right hand, so I've put the forward functions on then N key, the transpose functions on the T key, and the backward functions on the H key.
In addition, paredit provides the following commands:
- paredit-open-list (() - Inserts a balanced parenthesis pair.
- paredit-close-list (M-)) - Moves past one closing parenthesis and reindents.
- paredit-close-list-and-newline ()) - Moves past one closing delimiter, adds a newline, and reindents.
- paredit-splice-sexp (M-s) - Splices the list that the point is on by removing its delimiters.
- paredit-backward-delete (DEL) - Deletes a character backward or moves backward over a delimiter.
- paredit-forward-slurp-sexp (C-)) - Adds the S-expression following the current list into that list by moving the closing delimiter.
- paredit-backward-slurp-sexp (C-() - Adds the S-expression preceding the current list into that list by moving the closing ((sic) opening?) delimiter.
- paredit-forward-barf-sexp (C-}) - Removes the last S-expression in the current list from that list by moving the closing delimiter.
- paredit-backward-barf-sexp (C-{) - Removes the first S-expression in the current list from that list by moving the closing ((sic) opening?) delimiter.
- paredit-wrap-sexp (M-() - Wraps the following S-expression in a list.
Indentation
A simple, consistent way to indent lisp code is using C-M-q at the begining of an s-exp. Alternatively, use C-M-\ to re-indent the selected region.
Learning Emacs commands
KeyWiz is a quiz game that teaches you Emacs key-bindings.
Paredit Cheat Sheet for paredit commands beyond the scope of this document.