Recently, I started development of an emacs language mode called rubex-mode for supporting Rubex syntax highlighting in emacs. This took me to the ModeTutorial on the emacs wiki, which is a very detailed tutorial for learning how to write new emacs language modes. Before starting the tutorial I had no knowledge of Emacslisp or writing emacs language modes.
In this post I will share some of the important things that I learned about Emacslisp and some things that I think are important about writing language modes for Emacs.
- Learn emacs lisp in 15 minutes
- Programming in Emacs Lisp
- How to know whether to use single quote in elisp.
- Quote in elisp
Emacs lisp basics
If you enable ‘lisp-interaction-mode’ in emacs you can evaluate lisp using the
shortcut. That will insert the result of the evaluation in the buffer.
displays the same result in the minibuffer.
Programs are made of symbolic expressions (pre-fix notation), like
(+ 2 2),
this means ‘2 + 2’.
Expressions are made of atomic expressions or more symbolic expressions. In
(+ 2 (+ 1 1)),
1 and 2 are atoms, (+ 2 (+ 1 1)) and (+ 1 1) are symbolic expressions.
Getting and setting variables
setq stores a value into a variable:
(setq my-name "sameer")
Variables can also be initialized using
defvar. The emacswiki page is here.
defvar is similar to
setq, but the difference is that
defvar will not set the variable
if it already has a value.
Setting global constants
defconst keyword is used for setting global constants. It informs a person reading your code that
symbol has a standard global value, established here, that should not be changed by the user or by other
programs. Note that symbol is not evaluated; the symbol to be defined must appear explicitly in the defconst.
(defconst pi 3.141592653589793 "The value of Pi.")
Above code initializes the variable
pi to a value and sets a docstring.
Functions can be defined using the
defun keyword. For example, to defined a function
hello that accepts
name and inserts the variable with a string on the buffer:
(defun hello (name) (insert "Hello " name))
Fun fact: when evaluating elisp in a buffer, place the cursor at the bottom of the file otherwise emacs will only evaluate code until the cursor and throw unexpected output.
You can use the
progn form for evaluating a set of expressions one by one and returning the value of the last one.
The preceding expressions are only evaluated for their side effects and their values are discarded.
All emacs commands are basically just elisp function calls. So you can call something like this:
(progn (switch-to-buffer-other-window "*scratch*") (hello "you"))
And it will switch the active window to the
*scratch* buffer and print
Hello you in the buffer.
A value can be bound to a local variable using
let. This command can also be used for combining several sexps.
(let ((local-name "you")) (switch-to-buffer-other-window "*test*") (erase-buffer) (hello local-name))
quote is a special form in elisp that returns its single argument, without
evaluating it. This provides a way to include constants and lists, which are not
self-evaluating objects, in a program. This link
talks about it in detail.
Its used so often that a short form of using a single quote is often used instead (
talks in detail about when to and when not to use it.
In general, if you are trying to use the variable itself, use the quoted form,
otherwise directly use the variable name. For example, in the expression
(mapcar 'hello list-of-names),
we use a quoted
hello because don’t actually want to call the function, we just want to pass a reference
to it to the
mapcar function which will then call
hello at its own leisure.
A list of names can be stored like so:
(setq list-of-names '("Sarah" "Chloe" "Mathilde"))
The above expression is quoted because we want to set the whole expression
as a list to
car function for getting the first element of the list and
for getting all elements except the first element.
Lists are composed of cons cells. Each cons cell is a tuple of two lisp objects,
cdr. In the case of a list, the first slot of a cons cell holds
the element of the list and the next part chains to the next element of the list.
The cdr of the last cell of the list is
nil. This helps in detecting the end
of a list.
Dotted pair notation
A dotted pair notation is a general syntax for creating cons cells that represents
the car and cdr explicitly. In this syntax,
(a . b) stands for a cons cell whose
car is the object
a and whose
cdr is the object
b. Dotted pair notation is
more general than list syntax because the
cdr does not have to be a list.
Dotted pairs can be chained together to form a list. For example,
(1 2 3) is written
(1 . (2 . (3 . nil))).
Simple matrix multplication
Writing an emacs major mode
Basic mode setup
There are certain variables that all modes must define. Here’s a list:
wpdl-mode-hook: allows the user to run their own code when your mode is run.
wpdl-mode-map: allows both you and your users to define their own keymaps.
In order to tell emacs that this mode must start when a particular file extension is detected, we add to a list called
auto-mode-alist using the
add-to-list function. For example:
(add-to-list 'auto-mode-alist '("\\.rubex\\'" . rubex-mode))
alist is for historical reasons made of plain cons cells instead of full lists.