Speak with an Emacs Lisp

Table of Contents

1 The Basics

1.1 Intro

1.1.1 Why Learn Emacs?

There's been a lot of jibber-jabber on the net lately about Emacs. And maybe you know that one guy who won't stop preaching its gospel. Or maybe you're just sick of being a n00b who edits code in Notepad. Isn't it time you learned what all the fuss is about?

Recently at a Clojure conference I was suprised by the lack of people using Emacs. A casual survey other's computer screens showed barely a third of people using it. Surely, if they knew Emacs, I thought, they'd use it instead. Why wouldn't Lisp programmers want an editor that could be customized to do almost anything in Lisp?

Because it's hard to learn. And even harder to get started learning. Emacs is meant to be customized, which is good because its default settings are horrible. You need to do a lot of customization to get it working nicely, which entails writing Emacs Lisp, which (surprise!) is hard to do if you don't know Emacs Lisp.

And that's the problem with Emacs. There are a lot of good packages that provide "sane" default settings, with the intent of making it easier for beginners to get started with Emacs without having to write any Emacs Lisp. But what do you do when things stop working? How can you debug Emacs Lisp if you don't understand the language?

We're up to our ears in books about nearly every programming language under the sun, and there are several books published in the last few years about other editors such as vim. But Emacs just sits in the corner, getting no love, with just a couple books, published in the 90's, about versions so old they're barely relevant. There are other resources online for learning Emacs, including many good intoductory tutorials, but to really get the most out of Emacs you'll want to learn more than just the basics.

Hence this book. We'll learn Emacs Lisp by first using to fix all those nasty default settings, and then by customizing Emacs to do crazy shit. By the end, you'll know enough that you'll be able to turn it into your perfect editor. If you're reading this book, hopefully you don't need me to sell Emacs to you, but I just did. That's the elevator pitch: if you learn Emacs, you'll be able to make it work however you want and do almost anything.

You should definitely have past programming experience before reading this book. Another Lisp language like Clojure will make things a lot easier for you, but isn't necessary nor assumed.

I've seen too many people give up on Emacs after a few weeks because of one minor quirk or another that they had no idea how to fix. This book is dedicated to those people.

1.1.2 Installing

Before we go any further, you'll need to install Emacs. Hopefully you already know how to install things and don't need me wasting my breath, but make sure you have version 24.5 or newer with full GUI support (unlike VIM, most Emacs users don't run Emacs inside a terminal). Beware that OS X and many Linux distributions come with an ancient version of Emacs installed. Check the output of emacs --version from your command line to make sure you have the latest version.

  1. Mac OS X

    I recommend installing Emacs via Homebrew. Hopefully, you already have Homebrew installed, but if not, check out http://brew.sh/ for instructions on how to install it. After that, run

    brew update                # update package info
    brew install emacs --cocoa # install Emacs with Cocoa GUI
    brew link emacs            # set up symlinks to Homebrew version of Emacs
    brew linkapps              # create Emacs.app in /Applications
    

    Another good option is installing a pre-built binary from http://emacsformacosx.com/.

  2. Windows

    Head over to https://www.gnu.org/software/emacs/#Obtaining and follow the links to find a nearby GNU mirror. Look in the windows/ folder of the mirror's file listing and download the appropriate ZIP file.

  3. Linux

    If you're running Linux, you know how to install packages. Again, just make sure you have an up-to-date version.

1.2 Core Concepts

If you're interested in (better) learning Emacs Lisp, you probably have at least a vague familiarity with Emacs itself. If so, feel free to skim over this chapter or skip it altogether. Otherwise, we'll quickly go over some fundamental Emacs concepts.

1.2.1 Frames & Windows

Let's jump right into it. Fire up Emacs and we'll get started. You should see a screen like this:

emacs_with_initial_splashscreen.png

Figure 1: Emacs with Welcome Splashscreen

It's important to remember Emacs started its long evolution in the seventies, before GUIs became wide-spread. Emacs predates many of the standard terms used to describe computer interfaces today. And so Emacs uses some of these terms in a different, sometime counterintuitive way.

What we'd think of today as an application window is called a frame in Emacs. A window, on the other hand, is a subdivision of a frame. The picture above is of a single frame with a single normal window, displaying a slashscreen with a neat 90's-era Emacs logo, and a minibuffer window, which is the single line of text at the bottom of the frame, used for displaying messages or prompting for input. A frame can only have a single minibuffer window1, but it can have many regular windows. The minibuffer window is a special case, and you can safely ignore it for much of our discussion of windows going forward.

The "current" window is said to be selected, as is the current frame; switiching to a different window or frame is known as selecting it.

1.2.2 Buffers & Visting Files

Here's a (customized) frame with a window with a Dired2 buffer, and another with a buffer that's visiting an Emacs Lisp file.

emacs_with_2_windows.png

Visiting a file is Emacs-speak for opening it. A buffer contains text to be edited, and other context you can access through various variables or functions. That text might be the contents of the file it's visiting, although not all buffers are neccessarily visiting files: their content can be generated programatically. Each window displays a single buffer at a time; a buffer can be displayed in any number of windows – one, several, or even none.

One buffer is always said to be current. Typing (usually) inserts text in the current buffer; most editing commands will affect it. The current buffer is often the buffer currently displayed by the selected window, but not always; Emacs Lisp code can switch to a differenty buffer (usually temporarily), in order to make changes to it.

1.2.3 Modes & Keymaps

Every buffer has a single major mode that fills a specific purpose, such as editing code in a certain language or EDiting DIRectories. A major mode can defines everything from syntax highlighting and indentation rules to special commands specific to that major-mode.

Keymaps bind events such as keystrokes or mouse actions to specific commands. Global keybindings, available throughout Emacs, are defined in the global-map. Major modes usually define a keymap of their own; this keymap will only be active when the current buffer has that major mode. Keybindings in major mode keymaps are used in preference to ones in the global keymap in case of a conflict; conventionally, major (and minor) mode keybindings start with the prefix C-c ("Ctrl-C") to avoid clashes.

Emacs automatically knows which major mode to use for when visiting a new file thanks to patterns and functions defined in a variable named auto-mode-alist, which we'll look at a little later.

1.2.4 Minor Modes

In addition to a single major mode, a buffer can have one or more minor modes. Minor modes add additional functionality independently of major modes, such as linum-mode, which shows line numbers in the left margin, and auto-complete or company, which provide auto-completion. Many minor modes work across a variety of major modes; others augment a specific one, such as elisp-slime-nav-mode, which adds handy navigation commands to emacs-lisp-mode.

Like major modes, minor modes can define their own keymaps; bindings in these may override those in the current major mode keymap.

1.2.5 Key Sequences

Throughout the Emacs world, you'll see key sequences, or keys for short, which are simple sequences of keystrokes written like this: C-l. This example means "press control and l at the same time". C simply means "Control", and dashes are used to group together keys pressed simultaneously. You'd pronounce this as "Control-l".

Sequences of several keystrokes are separated by spaces. Thus, C-x C-f is simply shorthand for "press Control and x at the same time, then press Control and f at the same time". You'd read this example aloud as "Control-X Control-F". C-c c means "press Control and c at the same time, then press c by itself".

M is short for "Meta", which probably isn't a button on your keyboard, unless you have something like this Space Cadet Keyboard:

space_cadet_keyboard.jpg

Many things in Emacs are they way they are because it was originally written on computers that looked very different from modern ones, as you'll see throughout this book. Keyboards like this are similar to what users of Emacs would probably be using "back in the day". But since modern keyboards don't have a Meta button, the Alt key on your keyboard (or Option on a Mac)3 is used in its place. So M-x, pronounced "meta-X", is typed by holding down Alt/Option and pressing X.

Keystrokes can use multiple modifiers, such as C-M-x, which means hold Control and Meta (Alt) and press x; you'd read it as "Control-Meta-X". Shift can be specified with S, so M-S-v means "hold Shift and Meta and press v", but would more commonly be written as M-V. Conventially, multiple modifiers are written in alphabetical order, so you'd write C-M-x istead of M-C-x, although they both mean the same thing.

Besides Meta, you might have noticed some of the other wacky keys on the Space Cadet Keyboard, such as Hyper and Super. Emacs understands the Windows Key on a PC or Command on a Mac as Super4, which is written with s. So s-u means "Super-U", which means "press Windows/Command and U at the same time".

Emacs also understands the modifiers Hyper, written as H, and Alt, which is different from Meta and written as A. On a hardware level, the modifier keys on the left-hand side of your keyboard send codes that are distinct from those on the right-hand side; that is, Left Control and Right Control are two distinct keys. It just so happens that they're usually treated as though they are the same, but you do things like tell Emacs to treat Right Control as Hyper if you are so inclined5.

Certain keys are referred to by name, such as left for the left arrow key. When writing a named key in a key sequence, you need to wrap it in angle brackets, e.g. <M-left>.

  1. TODO - Get a better keyboard image from http://xahlee.info/kbd/lisp_keyboards.html

1.2.6 Commands & Getting Help

When you enter a key sequence like C-x C-f, Emacs runs the corresponding command. A command is nothing more than an Emacs Lisp function that contains the (interactive) form, which we'll investigate a little later. In this case, C-x C-f is bound to the function find-file. You can also run commands by typing M-x and entering the name of the command and pressing return; so you could type M-x find-file instead.

If you ever wonder what a key binding does (or what command it's mapped to), you can type C-h k <key sequence> (e.g., C-h k C-x C-f), which opens the documentation for the command in question6. Alternatively, C-h f <function name> (e.g. C-h f find-file) will let you look up the documentation of a function by its name. Notice how these bindings both start with the prefix C-h; the same is true for bindings to other help commands7. In this case, the h in C-h is short for "help"; you'll have an easy time remembering Emacs keybindings if you remember them this way (C-h k is help keys", C-h f is "help function").

You can see a list of all commands bound to a key sequence starting with some prefix by typing <prefix> C-h. So C-h C-h will give you a list of all the commands that can be invoked with a key sequence that starts with C-h.

You'll be learning many such keybindings in your quest for Emacs greatness. This is good, however; learn them well enough and you'll be able to edit code faster than you ever thought possible. Personally, I find it extremely helpful to write key bindings I'm trying to memorize on sticky notes and stick them to the edge of my screen until I've memorized them. Cheatsheets are helpful too; at one point or another, I've taped a few to my desk. You can also try writing them on yourself with a Sharpie, and uploading selfies of your new tatoos to Instagram with the hashtag #EmacsLyfe.

While we're on the subject, another extremely useful keybinding is C-h v (describe-variable), which lets you look up the documentation of a variable by name.

1.2.7 The Init File – ~/.emacs.d/init.el

In 2015, your Emacs customizations live in the init file, located at ~/.emacs.d/init.el. In the past, they lived in ~/.emacs, but you'll want to put your init file in a directory in case you decide to break it out into smaller files once it gets big and hairy.

1.2.8 Opening init.el

Let's get started writing some Emacs Lisp! You can open a file using the find-file command discussed above (in Emacs, opening a file is usually called "visiting" a file). We'll use it to open our init file, ~/.emacs.d/init.el, so we can tell Emacs not to show us that annoying splash screen. So type C-x C-f (or M-x find-file), and you'll see a prompt at the bottom of the screen that says "Find file:". The bottom part of the screen is what's known as the minibuffer. We'll discuss it in more detail later, but for now just know that commands can, and often do, prompt you for input here, and messages are frequently displayed there.

Go ahead and type the following code:

(setq inhibit-splash-screen t)

Save the file by typing C-x C-s, then close Emacs by typing C-x C-c. Again, notice how these commands all start with the prefix C-x. Many important global Emacs commands start with the prefix C-x, so just remember s for save and c for close.

1.2.9 Packages

Before we go any futher, you'll want to get Emacs configured to install packages. Add the following to your init file:

(require 'package)   ; TODO - is this neccesary ?
(package-initialize)

(nconc package-archives '(("melpa" . "http://melpa.milkbox.net/packages/")
                          ("marmalade" . "http://marmalade-repo.org/packages/")))

Now you'll be able to install third-party packages through the Package Menu (M-x package-list-packages) or via M-x package-install RET [package-name].

2 Speak with an Emacs Lisp

2.1 Emacs Lisp Types

If you've picked up a book on Emacs Lisp, you probably already know languages in the Lisp family look a little different than ones from the Fortan/C tradition. So I'm going to try to harp on these differences as little as possible. Just know that the syntax is a little different. But then again, Objective-C's syntax is different too, and that didn't stop people from writing iPhone apps, did it?

If you'd like to follow along with the examples, I'd recommend using ielm (M-x ielm), the Emacs Lisp REPL, to interactively evaluate Emacs Lisp expressions. Alternatively, you can visit an Emacs Lisp file, enter and expression, and type C-x C-e (eval-last-sexp) to evaluate the symbolic expression that precedes the cursor, and display the results in the minibuffer.

2.1.1 Hello, World! (Everything is an Expression)

Let's start with a traditional example:

(message "Hello, World!")

Evaluating that code will display the message Hello, World! in the minibuffer, and add it to the end of the *Messages* buffer. Lisp stands for LISt Processing; all code in Lisp is written in lists, denoted by parentheses. Lists are composed of atoms (symbols, strings, numbers, and the like) and of other lists. The list in the example above is composed of two atoms: the symbol message, and the string Hello, World!.

Formally, atoms and lists are collectively known as symbolic-expressions, or s-expressions or sexps for short. Every sexp produces a result when evaluated; atoms like strings or numbers evaluate to themselves, but variables evaluate to their value. Even if...else constructs return a value; contrast that with more conventional languages, where there is a separate concept of a statement that does not return a value.

When a list is evaluated, the first item is treated as a function, and all other items are evaluated and then passed to that function as arguments. Written in a more conventional language, the example above would look something like:

message("Hello, World!");

This syntax can take some getting used to, but it makes Lisp extremely flexible and powerful, as you'll see later when we discuss macros. It also has some advantages. In other languages, you might write:

1 + 2 + 3

But in Emacs Lisp, the function + can accept a variable number of arguments:

(+ 1 2 3)

As do functions like >, which returns t (true) if each arg is greater than the next:

(> 3 2 1)

Unlike many other languages, + and > aren't special built-in operators. They're regular functions, just like any other, and you can replace them if you're so inclined.

As aforementioned, you can nest lists:

(* (+ 1 2) 4)

Since the arguments of a function are evaluated first, this becomes:

(* 3 4)

which evaluates to 12. You can prevent a list from being evaluated by using the special form quote:

(quote (1 2 3))

Evaluating the form above will return the list (1 2 3). Because quoting lists and symbols is quite commonplace in Lisp code, as a bit of syntactic sugar you can instead simply put a single quote in front of the sexp in question:

'(1 2 3)

Lisp has just a tiny handful of special forms like quote; the rest of the language can be defined by simply building upon these special forms.

2.1.2 t and nil

nil is used to represent falsity and nothingness (null and false in other languages). t is used to represent true, but everything that is non-nil is considered true. The empty list is the same as nil, for reasons we'll discuss later in this chapter.

2.1.3 Comments

Comments in Lisp start with a ; and extend to the end of the line. In Emacs Lisp convention, comments that share a line with Lisp source code start with a single semicolon; comments that are on their own line start with two semicolons; comments serving as headers denoting large chunks of code start with 3.

;;; Big Chunk Of Code Starts Here
'() ; the empty list (nil)

;; TODO - Check logic here
(when (> x 100)
  ;; if x > 100 ...
  (message "OK!"))

Unlike Common Lisp or Scheme, Emacs Lisp does not syntax for multiple-line comments.

2.1.4 Symbols

Symbols are uniquely-named global objects, used for referring to variables and functions, stored in an internal table. When the reader (i.e., interpreter) encounters a symbol, it looks for an existing object with the corresponding name in an internal table and returns it if found; otherwise a new symbol is created, added to the table, and then returned. This process is known as interning a symbol.

These symbol objects have several "cells", such as its current value as a variable. Evaluating a symbol directly will return this value; you can quote it to prevent this from happening:

major-mode  ; -> emacs-lisp-mode
'major-mode ; -> major-mode

Emacs Lisp has no namespaces. Like other such languages, it is customary to prefix the name of every symbol in a package/library with the name of that package and a hypen (package-symbol). Thus, symbols from dired.el start with dired-, such as dired-recursive-copies. You'll also occasionally see prefixes like package/symbol or package:symbol. Note that symbols in Emacs Lisp can contain many characters that would be invalid in other languages: they can be anything except whitespace and these: ( ) " , ' ` ; # | \ _ [ ]. A variable that is should be treated as private is usually prefixed with pacakge-name--.

You can get the string name of a symbol using the function symbol-name:

(symbol-name 'emacs-lisp-mode) ; -> "emacs-lisp-mode"

2.1.5 Variables

You can set a variable using set:

(set 'require-final-newline t) ; add a final newline to files when saving

(Technically, what you're doing here is setting the symbol require-final-newline's current value as a variable to t.) Note how you have to quote require-final-newline to prevent it from being evaluated. Because this pattern is so common, the variation setq (SET Quoted) exists:

(setq require-final-newline t) ; add a final newline to files when saving

You can also set multiple variables at once with setq:

(setq echo-keystrokes 0.1        ; show keystrokes in progress in minibuffer sooner
      select-enable-clipboard t) ; cutting and pasting uses the system clipboard
  1. TODO defvar
  2. TODO defcustom
  3. TODO defconst

2.1.6 Functions

You can define a function with defun, whose syntax looks like:

(defun function-name args-list
  body-forms...)

A function consists of a name, a list of arguments, and any number of forms that make up the function's body. When called, the result of function is the result of its last form – no return statements here.

;; Define a new function
(defun square (x)
  (* x x))

;; Now call it
(square 12) ; -> 144

In JavaScript, this might look like:

function square(x) {
    return x * x;
}
square(12); // -> 144

In addition to variable cells, symbols have a function cell. So what you're really doing when you're calling defun is setting the function definition of the symbol square.8

Functions are treated just like any other object in Lisp: they can be passed as arguments, created on the fly, and returned from functions.

2.1.7 Emacs Lisp is a Lisp-2

Since a symbol has both a variable cell and a function cell, it's what's known as a Lisp-2 (as is Common Lisp). The value that you get when you evaluate it depends on the context: evaluate it at the beginning of a list, and its function definition is used; otherwise, its value as a variable is returned. Thus, you can do something like this:

;; Set the variable value of x
(setq x 100)

;; Set the function definition of x
(defun x (y)
  (+ y 1))

;; Evaluating x as an atom gives us its variable value
x     ; -> 100

;; When x is at the beginning of a list, it is used as a function
(x x) ; -> 101

The term "Lisp-2" simply refers to the fact that Emacs Lisp has 2 separate "namespaces" for functions and variables9, as opposed to a single combined one, such as in a Lisp-1 such as Scheme or Clojure:

;; Define x as the value 100
(def x 100)

;; Define x as a function (overwriting its previous value)
(defn x [y]
  (+ y 1))

x ; -> #<fn ...>

(x x) ; Error! Cannot cast function to a number

There are pros and cons to each approach. In Lisp-1 languages, you'll often see weird function parameter names like varr and klass to avoid overshadowing functions like var and class, respectively. However, in some ways it is "cleaner" – for example, you can call a function passed as a parameter directly:

(defn call-some-fn [f]
  (f))

In Lisp-2 languages, however, you have to use funcall to call a function passed as a parameter:

(defun call-some-fun (f)
  (funcall f))

We'll examine funcall more a bit later. Emacs Lisp takes advantage of its separate namespaces in many places. For example, minor modes usually define a variable that tells you whether it is currently active, and a function that can be used to turn it on or off:

;; Variable whitespace-mode tells you whether the minor mode is active
whitespace-mode ; -> nil

;; toggle it
(whitespace-mode)

;; Check the variable again
whitespace-mode ; -> t

2.1.8 Buffer-Local Variables

make-local-variable
make-variable-buffer-local
setq-default
setq-local
kill-local-variable
kill-all-local-variables

2.1.9 Dynamic & Lexical Binding

  1. let

2.1.10 Cons Cells

(x . y)

2.1.11 Chars & Strings

2.1.12 Keywords

2.1.13 Association Lists

2.1.14 Property Lists

2.1.15 Vectors + Hash Maps ?

2.1.16 Registers

2.2 Controlling Flow

2.2.1 progn

2.2.2 if

Like many other languages, Emacs Lisp provides an if...else construct for controlling program execution. Unlike other languages, it is an expression and returns a value. In fact, it is somewhat similar to the ternary if operator found in the C family of languages:

int error_code = explosion_count() > 0 ? 1 : 0;

In Emacs Lisp, an if statement takes the form

(if condtion then-form else-form)

So the example above would look like the following in Emacs Lisp:

(setq error-code (if (> explosion-count 0) 1
                   0))

2.2.3 when, unless, cond

2.2.4 Predicate Functions

2.2.5 mapcar

2.2.6 mapc

2.2.7 mapconcat

2.2.8 maphash

2.2.9 dolist

2.2.10 Errors

  1. error
  2. warn
  3. unwind-protect
  4. condition-case
  5. ignore-errors

2.3 Functions

2.3.1 #' (function) vs ' (quote)

  1. Allows byte compiler to check if you have used function names that are actually defined
  2. Makes Intention Clearer
  3. Documentation for function:

    Like `quote', but preferred for objects which are functions. In byte compilation, `function' causes its argument to be compiled. `quote' cannot do that.

  4. As in Common Lisp, lambda is a macro that expands to #'(lambda …)
  5. Was different on old versions of Emacs. Needed for cl-flet and cl-labels
  6. Funcall Behavior & cl-flet

2.3.2 Lambdas

2.3.3 &rest args

2.3.4 Interactive

2.3.5 funcall

2.3.6 fboundp

2.3.7 symbol-function

2.3.8 apply

2.3.9 apply-partially

2.3.10 recursion

  1. No Tail-Call Optimization

2.3.11 defsubst – inline functions

2.3.12 fset / defalias

2.3.13 indirect-function

2.4 Macros

Ask any Lisper what makes Lisp special and macros are sure to be mentioned. I'm sure you've heard the hype before: Lisp macros are magical, they make it more powerful than any other language, they will clean your house and make you dinner, etc. etc. So I'll save my breath and skip the macro hype. If you haven't drank the macro Kool-Aid just yet I'd highly recommend you read Paul Graham's Beating the Averages (http://www.paulgraham.com/avg.html), which explains why macros are so special better than I could ever hope to do.

Before we jump into discussing macros themselves, you'll need to understand how backquoting works.

2.4.1 Backquoting

The backquote, also known as backtick or syntax quote, makes it easy to construct a list where some elements are evaluated and others aren't. Let's say you want to define a function that takes one argument and will return a list with the elements a, b, and that argument.

(defun a-b-arg (x)
  (list 'a 'b x))

(a-b-arg 'c) ; -> (a b c)

This is a bit of a pain, since you have to quote every form that you don't want to be evaluated. You can't quote the entire list, because then x would never get evaluated:

(defun a-b-arg (x)
  '(a b x))

(a-b-arg 'c) ; -> (a b x)

That's not what we wanted! Luckily, backquoting exists to ease our pain:

(defun a-b-arg (x)
  `(a b ,x))

(a-b-arg 'c) ; -> (a b c)

Using backquote is just using regular quote, but any forms that are preceded with a comma, or unquote, are evaluated and the result is subsituted in its place. You can also use ,@ (unquote-splicing) to splice arguments into a list:

(defun a-b-args (&rest args)
  `(a b ,@args))

(a-b-args 'c)    ; -> (a b c)
(a-b-args 'c 'd) ; -> (a b c d)

When ,@ precedes a form, it is evaluated, and the elements of the resulting list are spliced into the list in its place. You can nest multiple levels of backquoting and unquoting as well:

(defun a-b-doubled-args (&rest args)
  `(a b ,@(mapcar (lambda (x)
                    `(,x ,x))
                  args)))

(a-b-doubled-args 'c 'd) ; -> (a b (c c) (d d))

The mapcar form is evaluated and generates the list ((c c) (d d)), which is then spliced into the final result. Backquoting will become your best friend when writing macros, as we'll see shortly.

2.4.2 Macros

So, what is a macro? It's code that writes code. A macro is very much like a function that recieves its arguments before they're evaluated, and returns a new sexp to be evaluated in its place. This process is known as macro expansion. Let's look at a real world example. Here's how unless could be implemented:

(defmacro my-unless (condition &rest body)
  `(when (not ,condition)
     ,@body))

;; Whenever you type
(my-unless (= 1 2)
  (message "new-math-mode is not enabled."))

;; It is expanded and replaced with:
(when (not (= 1 2))
  (message "new-math-mode is not enabled."))

Just like the functions we defined in the previous section, my-unless uses backquoting to return a new list. The key difference here is that the reader then replaces the my-unless form with the result before anything is ever evaluated.

Macros can return forms that contain macros, which are then themselves expanded.

(defmacro my-when (condition &rest body)
  `(my-unless (not ,condition)
     ,@body))

(my-when (= 1 2)
  (message "new-math-mode is enabled."))

;; The first time this is expanded, it becomes:
(my-unless (not (= 1 2))
  (message "new-math-mode is enabled."))

;; After being expanded again, it becomes:
(when (not (not (= 1 2)))
  (message "new-math-mode is enabled."))

When writing macros, you'll find it very helpful to see such expansions, one step at a time. You can use the function macroexpand-1 to expand a macro:

(macroexpand-1 '(my-when (= 1 2) do-something))
;; -> (my-unless (not (= 1 2)) do-something)

Note you must quote the macro form when passing it to macroexpand-1. Similarly, macroexpand will expand a macro, but instead of doing it one step at a time, it will completely expand the form, which is rarely as useful. More useful still is pp-macroexpand-expression, which is similar to macroexpand-1 but pretty-prints the results in a new buffer.

You can use the command pp-macroexpand-last-sexp, which calls pp-macroexpand-expression on the sexp before point. You can call it again on resulting form in the new buffer, allowing you to step through the expansion of a macro. This command is so handy I'd recommend binding it; I like C-c RET because it's used for the same purpose in other Lisp modes (cider, for Clojure development, is one example).

Also worth a look is the macrostep package. macrostep provides a minor mode, macrostep-mode, that when enabled lets you interactively expand and collapse macros one step at a time in your Emacs Lisp sources themselves.

Let's look at some ways macros are commonly used in the real world.

2.4.3 "def" Macros

You'll often see macros that make it easier to define something, such as defun or even defmacro itself. Conventionally such macros have names that start with def. Let's say you wanted to create a new version of defvar that would add every var created with it to a secret list that you could use for nefarious purposes. We'll call it def-tracked-var.

(defvar tracked-vars '()
  "Variables created with `def-tracked-var.")

(defmacro def-tracked-var (symbol &rest args)
  `(progn (add-to-list 'tracked-vars ',symbol)
          (defvar ,symbol ,@args)))

(def-tracked-var b 100
  "Number of friends to recommend this book to")

;; this expands to:
(progn
  (add-to-list 'tracked-vars 'b)
  (defvar b 100 "Number of friends to recommend this book to"))

;; Which is then evaluated.
b            ; -> 100
tracked-vars ; -> '(b)

Note our macro returns a progn, since macros can only return a single form. Notice too how we use both a quote and and unquote with symbol. Recall that 'arg is just shorthand for (quote arg), so ',arg just becomes (quote ,arg); this allows us to pass a 'b to add-to-list instead of b, which is what we want in this case.

defvar takes 3 args, the last of which is optional. But since def-tracked-var is only concerned with the first we can just gather the rest of the arguments to def-tracked-var with &rest and unquote-splice them into the defvar form we create.

2.4.4 Abstracting Away Boilerplate & Common Patterns

It's obnoxious to write similar-looking boilerplate code over and over (unless you are a fan of Java). Worse yet, it wastes space, distracts readers from the important parts of your code, and can lead to bugs if you write said boilerplate wrong. Wouldn't it be nice if we could just tell computers how to write this code for us? They can! So long as you're writing Lisp.

When byte compiling an Emacs Lisp file, the byte compiler will complain when it sees functions it doesn't know to be defined. You can use declare-function to tell it that a function exists in a certain file:

(declare-function paredit-backward-delete "paredit")

But what if you want you want to tell it two functions exist in paredit.el? You'd have to use two calls to declare-function:

(declare-function paredit-backward-delete "paredit")
(declare-function paredit-doublequote "paredit")

Why couldn't we just use mapc?

(mapc (lambda (f)
        (declare-function f "paredit"))
      '(paredit-backward-delete
        paredit-doublequote))

declare-function is itself a macro, and since f is passed to declare-function before it's evaluated, we're effectively just telling the byte compiler that a function named f exists in paredit.el, twice. Which is not at all what we want. Instead, we could use backquoting to create declare-function forms and call eval on them:

(mapc (lambda (f)
        (eval `(declare-function-2 ,f "paredit")))
      '(paredit-backward-delete
        paredit-doublequote))

This would work, in theory, but eval forms are evaluated at runtime and not by the byte compiler. So we'll still see warnings. And what if we wanted to declare functions in multiple files? Let's write a macro instead:

;; Switch the position of the file argument to the front
;; so we can accept a variable number of functions.
(defmacro declare-functions (file &rest functions)
  (declare (indent 1))
  `(progn ,@(mapcar (lambda (f)
                      `(declare-function ,f ,file))
                    functions)))

(declare-functions "paredit"
  paredit-backward-delete
  paredit-doublequote
  paredit-newline)

;; Expands to:
(progn
  (declare-function paredit-backward-delete "paredit")
  (declare-function paredit-doublequote "paredit")
  (declare-function paredit-newline "paredit"))

Much better! Notice how we added (declare (indent 1)) to the Emacs how to indent our macro. You could instead define the macro recursively, if you were so inclined:

(defmacro declare-functions (file fn &rest more)
  (declare (indent 1))
  `(progn (declare-function ,fn ,file)
          ,(when more
             `(declare-functions ,file ,@more))))

;; The previous example...
(declare-functions "paredit"
  paredit-backward-delete
  paredit-doublequote
  paredit-newline)

;; Expands to:
(progn
  (declare-function paredit-backward-delete "paredit")
  (declare-functions "paredit" paredit-doublequote paredit-newline))

;; Which then expands to:
(progn
  (declare-function paredit-backward-delete "paredit")
  (progn
    (declare-function paredit-doublequote "paredit")
    (declare-functions "paredit" paredit-newline)))

;; And finally:
(progn
  (declare-function paredit-backward-delete "paredit")
  (progn
    (declare-function paredit-doublequote "paredit")
    (progn
      (declare-function paredit-newline "paredit")
      nil)))

Here, we take the first arg after file and create a declare-function form. Then, if &rest more is non-nil (i.e., non-empty), we create a recursive declare-functions form with the remaining arguments. Each iteration of the macroexpansion generates a single declare-function form. There's no real benefit to defining declare-functions recursively, but there are cases where it makes sense to define a macro this way.

2.4.5 Wrapper Macros

(defmacro cam/suppress-messages (&rest body)
  (declare (indent 0))
  `(cl-letf (((symbol-function 'message) (lambda (&rest _))))
     ,@body))

2.4.6 with- macros

2.4.7 Controlling Execution Flow

  1. when-let
  2. threading macros

2.4.8 Macro Techinques / Gotchas

  1. implicit progn
  2. Double Evaluation
  3. Gensyms

3 Intermediate

3.1 Defining Code to Be Ran On a Later Occasion

Emacs is flexible and customizable. Perhaps you want to convert all tabs to spaces in files before they're saved to disk. Maybe you want to tell a command to re-indent the current line whenever it's ran. Or maybe you want to run code after a certain package is loaded. We'll be looking at how to do all of these things in this chapter.

3.1.1 Hooks

A hook is simply a list of functions10 that are ran at some specific occasion. Hooks exist for a wide variety of occasions. before-save-hook is ran whenever a user saves a buffer, before it's actually written to disk; here you might want to add functions to reindent your code or sort your imports. after-save-hook is ran after the file is written; perhaps this is a good place to restart some external process? Every major mode is supposed to run a mode hook (which is just the name of the major mode with -hook appended) as the end of its initialization; many minor modes run modes hooks as well. emacs-lisp-mode-hook gets ran right as emacs-lisp-mode finishes initializing. Maybe you want to add a hook function to enable a minor mode?

To add a function to a hook, you use the function add-hook:

(add-hook 'emacs-lisp-mode-hook #'paredit-mode)

Whenever you visit an Emacs Lisp file, emacs-lisp-mode is activated, and the functions in emacs-lisp-mode-hook are ran, including #'paredit-mode. Recall that minor mode functions toggle minor modes in the current buffer when called without an arg; since the minor mode was off to begin with, it will now be enabled.

The best part about hooks is that they're automatically created if needed when you call add-hook. This means you don't need to call (require 'clojure-mode) before adding a function to clojure-mode-hook. You can add custom hooks for hundreds of major modes in your init.el without sacrificing your Emacs startup speed.

Instead of adding a named function to a hood, you can add a lambda:

(add-hook 'before-save-hook (lambda ()
                              ;; Untabify the current buffer
                              (untabify (point-min) (point-max))))

Generally, however, it's probably worth the trouble of upgrading the lambda in question to a named function, since you'll be able to modify the hook function without touching the hook itself, which is handy if you accidently make a mistake in your hook function. Either way, you can remove a hook function by calling remove-hook; this works for both function symbols and lambdas. Alternaltively, you can simply setq a hook to nil and re-add the desired hook functions.

add-hook accepts two optional arguments: append and local. By default, hooks function are added to the beginning of a hook, meaning it will run before any previously added hooks. By passing a non-nil value for append, the hook function will be added to the end instead. By default, it also adds hook functions to the global value of a hook. This isn't an issue when adding functions to a major mode hook, which only affect certain buffers. But the example above that untabifies the current buffer will run when any buffer is saved. There are cases where this probably isn't what you want – consider a Makefile, where tabs are neccesary. If you save one after adding this hook, your tabs will be no more.

Passing a non-nil value for local makes the hook buffer-local in the current buffer and modifies that value instead of the global one. It also adds t to the buffer-local value, which tells run-hooks to run the functions in the global value as well as those in the buffer-local one. The example above can be better rewritten as:

(defun my-untabify-buffer ()
  (untabify (point-min) (point-max)))

(defun my-emacs-lisp-mode-setup ()
  (add-hook 'before-save-hook #'my-untabify-buffer nil :local))

(add-hook 'emacs-lisp-mode-hook #'my-emacs-lisp-mode-setup)

Now, we're adding a buffer-local hook to untabify the current buffer whenever we enter emacs-lisp-mode. Whenever you save an Emacs Lisp file, #'my-untabify-buffer is called; your Makefiles are unaffected.

append and local just check for any non-nil value, so you can pass it anything you want. I find it more readable to use a keyword like :append than simply using t; it makes it clear what the argument you're passing means.

Most hooks are normal hooks, which means its functions are called with no arguments, and there return values aren't used in any way. By convention, normal hooks are any hook whose name ends in -hook. Abnormal hooks, on the other hand, are hooks whose functions are passed arguments, whose return values are used, or both. By convention, abnormal-hooks have names ending in -functions. There are also abnormal hooks whose value is a single function (as opposed to a list of functions); these have names that end in -function.

You can run hooks with the function run-hooks, which accepts a variable number of arguments:

(run-hooks 'before-exploding-hook 'before-crashing-and-burning-hook)

run-hooks simply calls the functions in the hook one-by-one, as with add-hook, this symbol doesn't actually have to be defined as a variable anywhere.

There are several variations on run-hooks, such as run-hook-with-args, run-hook-with-args-until-failure, run-hook-with-args-until-success, and run-hook-wrapped, which can be used to run abnormal hooks.

A major mode is supposed to finish initialization by calling change-major-mode-after-body-hook, its mode hook, and after-change-major-mode-hook. The function run-mode-hooks is provided to run these hooks.11

The following is a partial list of some of the standard hooks:

Hook Name Description
active-mark-hook Called when the mark becomes active.
after-change-functions Called after each text change.
after-change-major-mode-hook Called immediately after a major mode hook.
after-init-hook Ran after Emacs initialization has
  completely finished.
after-insert-file-functions Called after insert-file-contents.
after-make-frame-functions Ran after a frame is created.
after-save-hook Ran after a buffer is saved to its file.
auto-save-hook Ran just before auto-saving.
before-change-functions Called before each text change.
before-hack-local-variables-hook Ran before setting file-local variables,
  after checking for unsafe/risky ones.
  Only called if there are file-local
  variables to set.
before-init-hook Ran before loading init files.
before-make-frame-hook Ran before a frame is created.
before-save-hook Ran before a buffer is saved to its file.
buffer-access-fontify-functions List of functions called by buffer-substring
  to fontify if neccessary.
buffer-list-update-hook Ran when the buffer list changes.
buffer-quit-function Function to call to quit the current buffer,
  or nil if none.
change-major-mode-after-body-hook Called immediately before a major mode hook.
change-major-mode-hook Ran before changing the major mode.
command-line-functions List of functions to process unrecognized
  command-line arguments.
deactive-mark-hook Called when the mark becomes inactive.
delete-frame-functions Ran before deleting a frame.
delete-terminal-functions Ran when a terminal is deleted.
echo-area-clear-hook Ran when clearing the echo area.
emacs-startup-hook Ran after loading init files and handling
  the command line.
find-file-hook Called after a buffer is loaded from a file.
find-file-not-found-functions Functions to be called for find-file on a
  non-existent file.
first-change-hook Called when changing an unmodified buffer.
focus-in-hook Ran when a frame gains input focus.
focus-out-hook Ran when a frame loses input focus.
frame-auto-hide-function Function called to automatically hide
  frames.
hack-local-variables-hook Ran after processing a file's local
  variables
kill-buffer-hook Ran when a buffer is killed.
kill-buffer-query-functions Functions to call before killing a buffer.
  If any of them returns nil, the buffer will
  not be killed.
kill-emacs-hook Ran when kill-emacs is called.
kill-emacs-query-functions Functions to call before killing Emacs. If
  any of these functions retuns nil, killing
  Emacs is cancelled.
menu-bar-update-hook Ran to update menu definitions before
  redisplaying the menu bar.
minibuffer-exit-hook Ran just after exit from the minibuffer.
minibuffer-setup-hook Ran just after entry to the minibuffer.
pop-up-frame-function Function used by display-buffer for
  creating a new frame.
post-command-hook Ran after each command is executed.
post-gc-hook Ran after garbage collection finishes.
post-self-insert-hook Ran at the end of self-insert-command,
  after inserting the character.
pre-command-hook Ran before each command is executed.
split-window-preferred-function Function called by display-buffer to split
  a window.
suspend-hook Ran before suspending Emacs.
suspend-resume-hook Ran after Emacs is unsuspended.
temp-buffer-setup-hook Ran at the start of
  with-output-to-temp-buffer; the temporary
  buffer is current when the hook runs.
temp-buffer-show-hook Ran by with-output-to-temp-buffer after
  displaying the buffer.
window-configuration-change-hook Called when the window configuration
  changes.
window-scroll-functions Functions to call before redisplaying a
  buffer when scrolling.
window-setup-hook Similar to emacs-startup-hook, but runs after
  frame parameters have been set up in response
  to any settings in the init file.
window-size-change-functions Functions called before redisplay when a
  window's size changes.
window-text-change-functions Functions to call in redisplay when text in
  the window might change.
write-contents-functions Called before writing out a buffer to a file.
  If one of them returns non-nil, the file is
  considered already written, and the rest of
  the functions are skipped, as are the ones
  in write-file-functions.
write-file-functions Called before writing out a buffer to a file.
  If one of them returns non-nil, the rest are
  skipped.
write-region-annotate-functions Called at the start of write-region.
write-region-post-annotation-function Called after write-region completes.

3.1.2 Advice

3.1.3 eval-after-load

3.2 Moving Around

3.2.1 Point

3.2.2 Mark

3.2.3 Positions

3.2.4 Markers

3.3 Working With Buffers, Windows, and Frames

3.4 Operating on Strings

3.5 Packages

3.5.1 Autoloads

3.5.2 Require & Provide

4 Advanced

4.1 Syntax Tables

4.2 Font Locking

4.3 Custom Variables

4.4 Byte Compilation ?

4.5 Keymaps

5 Libraries

5.1 cl-lib

5.2 subr-x

5.3 dash

5.4 s

6 Putting it All Together

6.1 Debugging with Edebug

6.2 Writing a Minor Mode

6.3 Writing a Major Mode

6.3.1 define-generic-mode

6.4 Packaging

7 Possibilities

7.1 Keyboard Macros

7.2 identity, ignore

7.3 Primitive Functions ?

Footnotes:

1

It's possible to create a frame without a minibuffer window, but it must use the minibuffer of some other frame. You can do this passing the frame parameter minibuffer when creating it; pass an existing minibuffer window, or nil for it to use the minibuffer of default-minibuffer-frame.

2

The Emacs DIRectory EDitor.

3

If you're using Emacs in terminal (-nw) mode, you might have to tell your terminal to use Alt/Option as Meta (this is the case on OS X). But I'd strongly recommend using Emacs in GUI mode. Terminals are limited. Try typing C-i and TAB. They're the same thing!

4

Unless you're using Emacs in terminal (-nw) mode, in which case you're SOL.

5

You can tell Emacs to interpret keycodes for the modifier keys on either side of your keyboard differently by setting corresponding variables. On a Mac, for example, (setq ns-right-command-modifier 'hyper) tells Emacs to treat the right command key as hyper instead of super. Other similar variables are prefixed with ns-. On Windows, similar variables such as w32-rwindow-modifier exist. Alternatively, you can also use C-x @ <modifier letter> <key sequence> to simulate modfier keys like Hyper. C-x @ h g will be understood as h-g, but that's a lot of typing.

6

This is also a good way to see if a key sequence isn't bound to any command, as it will give you an error if it isn't.

7

You can use the <f1> prefix instead of C-h for invoking help commands, too.

8

Actually, defun is a just a macro that rewrites the sexp as a defalias form that sets the function definition of a symbol to an anonymous function. Internally, defalias usually calls fset, which actually does the function cell-setting.

9

Lisps with more than one namespace are also referred to as Lisp-Ns, since Common Lisp actually has at least 7 namespaces, according to Peter Norvig in Paradigms of AI Programming.

10

A hook can also be a single function, but this usage is obsolete. Calling add-hook on such a hook will automatically upgrade it to a list.

11

The rules are a little different for derived major modes, which we'll get into a little bit later.

Author: Cam Saul

Created: 2015-06-04 Thu 19:47

Emacs 25.0.50.1 (Org mode 8.2.10)

Validate