The Emacs text editor uses lisp as an extension language. This article will attempt to explain enough lisp to do basic emacs customization, to someone who knows imperative programming languages.
Lisp consists of balanced pairs of parantheses, filled with tokens, separated by space, eg. like this:
(somefun1 1 2 3 "four") (somefun2 5 6)
The flow of a lisp program is to start from the top, and evaluate the balanced parantheses and their contents. When doing this, lisp expects the first item in the list to either be a function (actually the name of a function (or actually a symbol bound to a function (but now it is time to stop digressing and nest up the parantheses and continue))), or what’s called “a special form”.
For now, let’s assume that the first items are all functions. Then the example above, would be to just invoke “somefun1” with three integer arguments and one string argument, then invoke “somefun2” with two integer arguments.
Ie. basically, the same as this C fragment, except with the parantheses surrounding the name of the function, and no semicolon to terminate each statement:
somefun(1, 2, 3, "four"); somefun(5, 6);
But a more interesting, or typical, lisp example, would be something like this:
(somefun1 (+ 0 1) (+ 1 1) (+ 1 1 1) (concat "f" "o" "u" "r")) (somefun2 (- 11 6) (- 11 5))
What happens when lisp starts evaluating the first line, is that it will evaluate each of the balanced parantheses, before it eventually serves them up as arguments to “somefun1”.
Then lisp will move on to the next line and do the same thing there, and continue with this, until it reaches the end of input.
Evaluating “special forms”
Evaluating a special form differs from evaluating a function in the way the arguments are evaluated.
Examples of special forms, are the flow control constructs of lisp, eg. the “if” special form:
(if (= 2 2) (message "If test was true!") (message "If test was false!"))
When lisp encouters an “if” special clause, it will start by evaluating the first argument.
If the result of the first arguent is other than nil, the second argument will be evaluated. If the there are more arguments to “if”, they will not be evaluated.
If the result of the first argument is nil, the third, and following arguments to “if” will be evaluated (this is the “else” part of the if clause). In this case, the second argument to if will not be evaluated.
Trying out lisp
In emacs, go to the scratch buffer. This can be done with `C-x b *sc TAB RET’.
Type the following text into the buffer:
(message "Hello minibuffer!")
Place the cursor at the end of the line, and press `C-j’. Two things will happen:
- The minibuffer will show the text “Hello minibuffer!” (without the quotes)
- The line below the line you typed in will get the text “Hello minibuffer!” (this time with the quotes)
The `C-j’ command will evaluate the lisp expression that ends on the same line as the cursor, and the evaluation result will be printed on the next line.
The evaluation result is useful when debugging an expression, such as the test argument to an “if” special form.
If you don’t wish to move the cursor to the end of the clause being tested, you can instead press `C-M-x’, which will evaluate the outermost clause, under the cursor.
Using `C-M-x’ won’t output the evaluation result to the scratch buffer
In the .emacs file you can set variables that affect how emacs operates. On unix-ish systems, the .emacs file resides in the home directory. On windows systems the default is to look for the file in the “%USERPROFILE%AppDataRoaming” directory (unless the HOME environment variable, in which case emacs looks for it in “%HOME%”).
One of my oldest settings is one that stops emacs from saving “~” backup files:
(setq make-backup-files nil)
In today’s emacs one can set a simple settings like this interactively, using the customize mechanism.
The most important thing to be able to do, is to set various configuration variables. Today this can be done interactively for many variable using the “customize” mechanism.
But it’s still useful to be able to know how to set variables in lisp, eg. for setting variables differently depending of the type of file loaded, the version of emacs, or the OS one is running on.
To set variables, use the special form “setq”. Type the following into the scratch buffer, and evaluate it:
(setq a-variable-used-as-an-argument t)
Now a-variable-used-as-an-argument is a variable, and you can use it in lisp code. The value is t.
Functions are defined with the “defun” special form. An example, is:
(defun somefun1 (firstarg secondarg) "This is a function to do something. If firstarg is non-nil it will output that firstarg was true. If firstarg is nil it will output that firstarg was false. The secondarg argument isn't used for anyting at all" (if firstarg (message "Firstarg was true!") (message "Firstarg was false!")))
First try `C-h f somefun1 RET’. Emacs will say “[No Match]” when RET is pressed.
Then move to the scratch buffer and paste in the code of the example, and use `C-j’ or `C-M-x’ to evaluate the defun clause.
Then try `C-h f somefun1 RET’ again. This time the emacs window will split in two and the lower half will show:
somefun1 is a Lisp function. (somefun1 firstarg secondarg) This is a function to do something. If firstarg is non-nil it will output that firstarg was true. If firstarg is nil it will output that firstarg was false. The secondarg argument isn't used for anyting at all [back]
To try using the function, paste the following into the scratch buffer, and evaluate it:
This will cause the lisp debugger to pop up, saying that the function has two methods, but is called with none.
Add some arguments to the function call and evaluate it again:
(somefun1 nil "Required but unused")
The minibuffer will show “Firstarg was false!”. Now try putting different values as the first argument. All values, other than nil, will result in “Firstarg was true!” being written to the minibuffer.
Many variables used by language modes are “buffer local”. This is so that eg. c-mode can use different indentation settings on two separate source files, to accomodate the different indentation/formatting used on them.
This means that if you set the variable when starting up emacs, the buffer version of the variable may not get the setting.
To make it possible to customize this, and other things, many emacs format specific modes provides “hooks”.
A hook is a list of functions, and emacs will run all functions in that list when doing a particular operation. Typically there are hooks for loading and saving files.
In the same way as the two preceeding articles, this article describes the subset of lisp and emacs lisp, that I use on a regular basis. Lisp by itself could probably be a lifetime study. I have for instance skipped mentioning macros, which are another important construct in lisp. Macros allow programmers to create constructs that behaves similar to special forms. Macros can e.g. be used to create new control structures (the macro “when” is such a control structure. It is nicer syntactically than the special form “if”).
Suggested reading is the Emacs Lisp Reference Manual and An Introduction to Programming in Emacs Lisp. In addition to reading them on the net, you can read them in the builtin manual reader of emacs (`C-h i m elisp RET’ and `C-h i m emacs lisp TAB RET’).