If you enjoyed this site, please consider donating $3. Any amount is appreciated. Thanks!

Tips For Editing Lisp Code With Emacs

Xah Lee, 2007-12, 2009-11-05

This page gives you some tips about editing emacs lisp code in emacs. Most tips will also apply to editing other lisp language codes or code with many nested matching pairs.

Convenient Highlighting Setup

Turn on the following modes: Syntax Highlighting, Active Region Highlighting. You can turn them on with these code in your “.emacs”:

; syntax color code. (on by default in emacs 22)
(font-lock-mode 1)

; highlight text selection (active region) (on by default in emacs 23)
(transient-mark-mode 1)

; make typing overwrite text selection
(setq delete-selection-mode 1) ; this turns on transient-mark-mode automatically

For modes, by convention, argument of 1 is to turn on, 0 is off, and “nil” (or no arg) toggles the current state.

To see your emacs version, type “Alt+x version”.

Show Paren Mode

You also want to turn on Paren Match Highlighting.

; turn on highlight matching parens when cursor is on one
(show-paren-mode 1)

show-paren-mode has 2 styles of highlighting parens.

emacs show-paren-mode 1

Highlighting just the parens.

emacs show-paren-mode 2

Highlighting the whole expression

By default, emacs highlight just the parens. But you can change that with the following code:

(setq show-paren-style 'parenthesis) ; highlight just parens
(setq show-paren-style 'expression) ; highlight entire expression

Also, you can change the default background color for highlighting the paren. You can do so by typing “Alt+x customize-face Enter show-paren-match Enter”. Then, move your cursor to the “Attributes” section, “Background” item, in the value section type “azure2” replacing the default “turquoise”. Then, click the button “Save for Future Sessions” at the top. This will save the lisp code in your emacs init file. For example, the following shows in my emacs init file:

;...
'(show-paren-match ((((class color) (background light)) (:background "azure2"))))
;...

To see a list of available colors and their names, type “Alt+x list-colors-display”.

Evaluating Lisp Expressions

To evaluate a single lisp expression, move your cursor to the right of the last closing parenthesis, and type “Alt+x eval-last-sexp” (Ctrl+x Ctrl+e). Alternatively, there's “eval-region” and “eval-buffer”. These last 2 commands do not have a shortcut by default. You can assign them a shortcut (see How to Define Keyboard Shortcuts in Emacs), or you can give them a alias. For example, i have the following aliases defined:

(defalias 'eb 'eval-buffer)
(defalias 'er 'eval-region)
(defalias 'ee 'eval-expression)
(defalias 'elm 'emacs-lisp-mode)

You can also evaluate a elisp file without opening it, by “Alt+x load-file”.

Also, emacs has a interactive emacs lisp shell: “Alt+x ielm”.

Function Documentation Lookup

Function and Variable lookup

To find the inline documentation of a function, type “Ctrl+h f” (describe-function), then type the function name. If the word the cursor is on is a valid elisp function, emacs will use that by default.

Once the function's inline doc string page comes up, you can jump to the function's location in source code by clicking on underlined file name (or move your cursor there and press Enter).

To find the documentation of a variable, type “Ctrl+h v” (describe-variable).

Finding Commands and Functions

To search command names using a regex, type “Ctrl+h a” (apropos-command). Note that this will only search commands, not functions. (A “command” is a function with the “(interactive ...)” clause.) To search both function and command name spaces, give the command a empty argument, like this: “Ctrl+u Ctrl+h a”.

For example, you want to find the function that opens a file but forgot the function's name. You might start looking for it by “Ctrl+h a Enter” then type “file”. This will return all functions with “file” in their name.

To search all symbols space (commands, functions, variables), type “Alt+x apropos”.

Note: all these commands are under the menu “Help‣Describe” or “Help‣Search Documentation”.

Searching Elisp Manual

Usually a function's inline documentation is sufficient for knowing how to use the function, but sometimes you want to read about a function in the elisp manual, which often gives more detail and context.

To search for a function in the elisp manual, use “elisp-index-search”. For emacs manual, use “emacs-index-search”. Both of these commands are under the menu “Help”.

If you use elisp-index-search often, you can assign it a alias.

(defalias 'eis 'elisp-index-search)

Navigating Nested Code

Lisp code with its nested parenthesis syntax represents a tree structure. Emacs has several commands that are very helpful in moving around nested syntax, analogous to navigating a tree. Here is a table showing their shortcuts, names, and purpose. (For historical reasons, lisp code units are sometimes called “sexp”, short for Symbolic EXPression.)

Shortcut Command name Purpose
Ctrl+Alt+ backward-sexp Move to previous sibling
(move to the (beginning of) previous sexp unit)
Ctrl+Alt+ forward-sexp Move to next sibling
(move to the (end of) next sexp unit)
Ctrl+Alt+ backward-up-list Move to parent
(move to the (beginning of) outer paren pair)
Ctrl+Alt+ down-list Move to first child
(move into the (beginning of) first inner paren pair)

Here is a lisp code layed out in a way to show its tree structure. You should try the above commands on it. It is very helpful to understand how sexp corresponds to a tree, and how the commands move the cursor exactly.

( defun
  fold
  "Applies (f x ele) recursively to the list li ..."
  (f x li)
  ( let
    (
      (li2 li)
      (ele)
      (x2 x)
    )
    (while
      (setq ele (pop li2))
      (setq x2 (funcall f x2 ele))
    )
    x2
  )
)

Place your cursor at the beginning of the left bracket. Now, try to move your cursor, by using only the tree-walking commands, to the “pop”, then move it to “let”, then “funcall”.

Moving To Previous/Next Sibling That Has Children

The commands “backward-sexp” and “forward-sexp” moves to the previous or next sibling of the sexp the current cursor is on. For example, if you have “(a (b) c d (e f))” and your cursor is on end paren of “(b)”, then, “forward-sexp” will move it to “c”, and do it again will move it to “d”, then end paren of “(e f)”. Occationally, you want to move to the next sibling that has a branch. For example, if you are at the end of “(b)” and you want to move it to next paren pair the “(e f)”, you can then use “backward-list” and “forward-list”.

Selecting A Sexp Unit

You can use the command “mark-sexp” (Ctrl+Alt+Space) to select a complete sexp. However, your cursor should be at the beginning of the unit. To select a complete sexp, type “Ctrl+Alt+” then “Ctrl+Alt+Space”.

Typing Conveniences

Rebind Sexp Navigation Commands

The default hotkeys for tree-walking commands need you to hold down both Meta and Control. This is not very convenient. You can rebind them with just Meta.

(global-set-key (kbd "M-<up>") 'backward-up-list)
(global-set-key (kbd "M-<down>") 'down-list)
(global-set-key (kbd "M-<left>") 'backward-sexp)
(global-set-key (kbd "M-<right>") 'forward-sexp)

The above binding will make “Meta+‹arrow›” for walking the sexp tree.

Typing Parenthesis By Pairs

On a PC keyboard, the matching pairs “(){}[]” are typed by the weak 4th and 5th fingers. It is convenient to move them under the home row, and also to type them always in pairs. Here's the code:

(global-set-key (kbd "H-s") (lambda () (interactive) (insert "[]") (backward-char 1)))
(global-set-key (kbd "H-d") (lambda () (interactive) (insert "()") (backward-char 1)))
(global-set-key (kbd "H-f") (lambda () (interactive) (insert "{}") (backward-char 1)))

The “H” in the above code means the Hyper key. You can make your PC's Menu key as Hyper, or your Mac's Option key as Hyper. Here's the code:

(cond
 ((string-equal system-type "windows-nt") ; Windows
  (setq 
   w32-pass-apps-to-system nil 
   w32-apps-modifier 'hyper ; set Menu key as Hyper
   )
  )
 ((string-equal system-type "darwin") ; Mac
  (setq mac-option-modifier 'hyper) ; set Option key as Hyper
  )
 )

Arrows Keys Under Homerow

Emacs default cursor movement keys (C-p, C-n, C-b, C-f) are inconvenient to press. (See Why Emacs's Keyboard Shortcuts Are Painful) You can rebind the cursor movement keys under the home row with Alt key held down. Here's the code:

(global-set-key (kbd "M-j") 'backward-char) ; was indent-new-comment-line
(global-set-key (kbd "M-l") 'forward-char)  ; was downcase-word
(global-set-key (kbd "M-i") 'previous-line) ; was tab-to-tab-stop
(global-set-key (kbd "M-k") 'next-line) ; was kill-sentence

(global-set-key (kbd "M-SPC") 'set-mark-command) ; was just-one-space

For a complete ergonomic shortcut set, see: A Ergonomic Keyboard Shortcut Layout.


Related essays:

2007-12
© 2007 by Xah Lee.