• This repository has been archived on 25/Jul/2022
  • Stars
    star
    1,397
  • Rank 33,640 (Top 0.7 %)
  • Language
  • Created about 10 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A quick guide to Emacs Lisp programming

Emacs Lisp Guide

Table of Contents

Audience

Programmers who are too busy to read through long tutorials and manuals, but who want to extend their editor. You don't need to learn everything from the ground up, just enough knowledge to be self-sufficient. You've been using Emacs for a while and now it's time you started making some handy extensions for yourself.

There are a bunch of existing guides, but they don't strike the right balance of useful and helpful. Some just list functions, others try to explain Emacs Lisp from the ground up as a language. You don't need to know everything right away. See the Alternative sources section for a list of these.

Programming in Emacs Lisp

I'm not going to explain the Emacs Lisp language itself in any detail. Programming in Emacs Lisp (look at the Wikipedia page for the academic details) is similar to programming in Python, Scheme, Common Lisp, JavaScript, Ruby, and languages like that. Its syntax is funny but otherwise it's an imperative language with similar data structures.

One important difference compared to usual languages to be aware of is that it has dynamic scope by default. See Dynamic Binding in the manual for the details. Almost all Emacs Lisp code you come across today will be using this. Lexical Binding has recently been added to Emacs, it will take a while for this to permeate.

Like all Lisps, Emacs Lisp has macros which you can read about in the manual at your leisure.

After reading this guide

The best, most comprehensive resource on Emacs Lisp is the manual. I will reference this manual throughout this guide. I will not repeat what's already there. You can reference this manually in a random access fashion when you need to solve a problem.

I reference the manual throughout the guide by HTML link, but you can read it inside your Emacs itself. Run: C-h i m Elisp RET

Trivial basics

These are the basics to syntax that you can lookup in any guide or just by looking at some Emacs Lisp code. I am assuming you're a programmer who can pick things up like this just by looking at code. I include these because I use them later:

(* 2 3)
(concat "a" "b")
(defun func (arg1 arg2)
  "Always document your functions."
   <function body>)
(defvar var-name <the value>
  "Always document your variables.")
(let ((x 1)
      (y 2))
  ...)

In Lisp the normal LET doesn't let you refer to previous variables, so you need to use LET* for that. This is likely to trip people up, so I include it here.

(let* ((x 1)
       (y x))
  ...)

To do many things at once in one expression, use PROGN:

(progn do-this
       do-that)

See manual for details.

The way to set variables is not obvious:

(setq var-name value)

Equality and comparison operators:

  • (eq major-mode 'a)
  • (= 0 1)
  • (> 0 1)
  • (string= "a" "b")
  • (string> "a" "b")

Emacs Lisp has a bunch of equality operators. See the manual for gory details.

Data structures available: lists, vectors, rings, hashtables. Look them up in the manual.

Evaluation

  • Use M-: to evaluate any Emacs Lisp expression and print the result. I personally use this constantly.
  • Use C-x C-e to evaluate the previous s-expression in the buffer. I personally never use this. See next binding.
  • Use C-M-x to evaluate the current top-level s-expression. I use this to re-apply defvar and defun declarations.
  • There is a REPL available by M-x ielm. I tend to use M-: rather than the REPL but you might like it.
  • Use M-x eval-buffer to evaluate the whole buffer of Emacs Lisp code.

Discoverability

A very important thing as an Emacs Lisp programmer is being able to get the information you want in a few keystrokes. Here's a list of ways to find what you need when you're writing Elisp code.

Finding functions of keybindings

Find the function called by a keybinding: C-h k

This will show something like:

C-p runs the command previous-line, which is an interactive compiled
Lisp function in `simple.el'.

It is bound to C-p.

(previous-line &optional ARG TRY-VSCROLL)

You can click the link simple.el to go directly to the definition of that function. Very handy indeed.

Getting documentation

Functions and variables are distinguished in Emacs Lisp, so there are two commands to do lookups:

  • Run C-h f to show documentation for a function. This also works for macros.
  • Run C-h v to show documentation for a variable.

You'll see something like:

mapcar is a built-in function in `C source code'.

(mapcar FUNCTION SEQUENCE)

Apply FUNCTION to each element of SEQUENCE, and make a list of the results.
The result is a list just as long as SEQUENCE.
SEQUENCE may be a list, a vector, a bool-vector, or a string.

Find all bindings in the current buffer

Run C-h b to show a massive list of keybindings and the command they run. You'll see something like, e.g. in markdown-mode:

C-c C-x d       markdown-move-down
C-c C-x l       markdown-promote
C-c C-x m       markdown-insert-list-item

Searching for documentation topics

Use the commands called apropos.

  • M-x apropos
  • M-x apropos-command
  • M-x apropos-library
  • M-x apropos-documentation

Jumping to definition

Install this package: elisp-slime-nav

Now you can use M-. to jump to the identifer at point and M-, to jump back.

Describe functions

The range of M-x describe- functions are useful:

  • M-x describe-mode (aka C-h m)
  • M-x describe-face

Other ones have been mentioned above as keybindings.

Basic concepts

Buffers

All Emacs Lisp code when run has a current buffer. Operations that claim to work on "the buffer" work on this current buffer. Some handy functions, which you can run C-h f on to get more info:

  • (current-buffer) - get the current buffer.
  • (with-current-buffer buffer-or-name ...) - temporarily use the given buffer.
  • (set-buffer buffer-or-name) - set the current buffer without switching to it.
  • (switch-to-buffer name) - switch to the buffer visually.

See Buffers in the manual for detailed info.

Buffer-local variables

Buffers have local variables, for example:

  • major-mode

You can use this variable to see what mode you're in, if you need it.

If you want to set your own buffer-local variable, use this:

(defvar your-variable-name nil "Your documentation here.")

Then later on in your code that will run in a given buffer, use:

(set (make-local-variable 'your-variable-name) <the-value>)

This is very handy in many scenarios when writing functionality. Note that buffer local variables are reset when you revert the buffer or change modes.

See manual for details.

Project-wide buffer-local variables

A handy way to set a buffer local variable for every file that's within a directory structure is to use a .dir-locals.el file.

((nil . ((indent-tabs-mode . t)
         (fill-column . 80)))
 (c-mode . ((c-file-style . "BSD")
            (subdirs . nil)))
 ("src/imported"
  . ((nil . ((change-log-default-name
              . "ChangeLog.local"))))))

The point

All Emacs Lisp code has a current point in the current buffer. It's a number. It refers to where the cursor is. See the manual entry for point, but here's the basics:

  • (point) - current point
  • (point-max) - maximum point of the buffer
  • (point-min) - minimum point of the buffer (why is this not just 0? Because of narrowing).

The region

Sometimes the region can be active, and you can use it in your Emacs Lisp code to manipulate text specially. See the manual for details. Rundown:

  • (region-beginning) - beginning of the region (a point)
  • (region-end) - end of the region (a point)
  • (use-region-p) - whether to try to use region-beginning/region-end for manipulation. Handy for use in commands.
  • (region-active-p) - also handy to know whether the region is active.

Here's an command that uses some region functions:

(defun print-upper-region ()
  "Demo to print the uppercased version of the active region."
  (interactive)
  (when (region-active-p)
    (message "%S" (let ((string (buffer-substring (region-beginning)
                                                  (region-end))))
                    (with-temp-buffer
                      (insert string)
                      (upcase-region (point-min)
                                     (point-max))
                      (buffer-substring-no-properties (point-min)
                                                      (point-max)))))))

To run it, C-M-x it, select some text and run M-x print-upper-region.

Text properties

When you manipulate text in Elisp, it can have properties applied to it, and those properties can be queried. Full details are here but see the "Manipulating the buffer" section in this guide for examples.

Debugging

Run M-: (setq debug-on-error t) RET and any errors will open up the debugger.

I'll write more about using the debugger stepper and breakpoints later.

Editing

Paredit

Install and enable paredit. Nobody sane writes Lisp without paredit (or its shiny cousin, smartparens; or its evil twin, lispy). You will never have unbalanced parentheses, brackets, braces, or strings. Learn to accept this and you will enjoy this mode.

As discussed in the discoverability section, use C-h f paredit-mode RET to see the documentation for this mode.

Learn the following helpful keybindings:

Navigating

  • C-M-u - Go up a node.
  • ) - Go to the end of the node or the end of the parent node when repeated.
  • C-M-f - Go to the end of the node.
  • C-M-b - Go to the start of the node.

Killing

C-k - Kill everything from here to the end of the line, including any following lines that are included in the scope of the nodes being killed. It will also kill inside strings but stop at the end of the string.

Raising

M-r - Replace the parent node by the current node.

(|foo) -> foo
(foo |bar mu) -> bar
(foo (bar |mu zot) bob) -> (foo mu bob)

Wrapping

  • C-M-( to wrap the following node in parens.
  • Alternatively, C-M-SPC to select the whole node, or just use your normal region selection and run ( or [ or { to wrap that selection.

Splitting

  • M-s to split the current node. This works on parenthesized expressions or strings.
  • M-J to join two nodes. Works same as above in reverse.

Manipulating the buffer

These are the most common:

  • (insert "foo" "bar") - to insert text at point.
  • (delete-region start end) - to delete the region of text.
  • (insert-buffer-substring-no-properties buffer start end) - insert text from another buffer.
  • (insert-file-contents <filename>) - insert from a file.

Any other command that inserts things can be called from Emacs Lisp, too.

Text properties

To add properties to text in the buffer, use:

(put-text-property start end 'my-property-name <value>)

To completely reset the properties of text to just this, use:

(set-text-properties start end 'my-property-name <value>)

To retrieve properties back from the text, use:

(get-text-property <point> 'my-property-name)

To propertize a string before it's inserted into a buffer, use:

(propertize "hello" 'my-property-name <value> 'another-prop <value2>)

Navigating the buffer

Here are the common ones:

  • (goto-char <point>) - go to the point.
  • (forward-char n) - go forward n chars. Accepts a negative argument.
  • (end-of-line) - self-explanatory.
  • (beginning-of-line) - self-explanatory.
  • (skip-chars-forward "chars") - skip given chars.
  • (skip-chars-backward "chars") - skip given chars back.
  • (search-forward "foo") - search for foo, move cursor there.
  • (search-backward "foo") - search backward.
  • (search-forward-regexp "blah") - same, but with regexes.
  • (search-backward-regexp "blah") - same, but with regexes.

If there's a kind of navigation you want to do that you don't know the function name for, think of how you would do it with your keyboard and then use C-h k on the commands to find out the functions being run.

Save excursion

Often you want to jump around the buffer to either query or manipulate something, and then go back to where you were originally. To do this, use:

(save-excursion ...)

For example:

(save-excursion (beginning-of-line) (looking-at "X"))

Will return whether the current line starts with X.

Similarly there is save-window-excursion.

Querying the buffer

  • (buffer-substring start end) - get the string at point, including text properties.
  • (buffer-substring-no-properties start end) - get the string at point, excluding text properties.
  • (buffer-string) - return the string of the whole buffer.
  • (looking-at "[a-zA-Z]+") - does text following point match the regex?
  • (looking-back "[a-zA-Z]+") - does text preceding point match the regex?

Temporary buffers

It's often useful to do some work in a temporary buffer so that you can use your normal Elisp code to generate a string and some properties, for example:

(with-temp-buffer
  (insert "Hello!"))

Defining interactive functions

To be able to run a function of your own from a keybinding, it needs to be interactive. You need to add (interactive) to your defun:

(defun foo ()
  "Some function."
  (interactive)
  (do-some-stuff))

There's a bunch of variations for INTERACTIVE, see the manual.

Now your function foo is interactive, you can use it in a keybinding:

(define-key emacs-lisp-mode (kbd "C-c C-f") 'foo)

Defining your own major mode

You can generally use define-derived-mode. See the manual on this.

Example:

(define-derived-mode hypertext-mode
   text-mode "Hypertext"
   "Major mode for hypertext.
 \\{hypertext-mode-map}"
   (setq case-fold-search nil))

(define-key hypertext-mode-map
   [down-mouse-3] 'do-hyper-link)

Defining a minor mode

Minor modes act as enhancements to existing modes. See the manual about define-minor-mode.

A dummy example:

(defvar elisp-guide-mode-map (make-sparse-keymap))
(define-minor-mode elisp-guide-mode "A simple minor mode example."
  :lighter " ELGuide"
  :keymap elisp-guide-mode-map
  (if (bound-and-true-p elisp-guide-mode)
      (message "Elisp guide activated!")
    (message "Bye!")))
(define-key elisp-guide-mode-map (kbd "C-c C-a") 'elisp-guide-go)
(defun elisp-guide-go ()
  (interactive)
  (message "Go!"))

Run M-x elisp-guide-mode to activate it and run it again to disable it.

Real examples of minor modes:

Markers

Markers are handy objects that store a point, and changes to the buffer make the marker position move along. See the manual, which has a good section explaining it. Their use-case is probably more intermediate than for a tutorial like this, so I include them only so that you're aware of them.

Here's an example:

(defun my-indent-region (beg end)
  (interactive "r")
  (let ((marker (make-marker)))
    (set-marker marker (region-end))
    (goto-char (region-beginning))
    (while (< (point) marker)
      (funcall indent-line-function)
      (forward-line 1))))

You need to store the end of the region before you start changing the buffer, because the integer position will increase as you start indenting lines. So you store it in a marker and that marker's value updates as the buffer's contents changes.

Overlays

See the manual on overlays, these are a handy tool for a special kind of text that behaves as if separate and above the buffer. This is more advanced, by the time you want to use overlays you'll be happy reading the manual entry about it.

Standard practices

Namespacing

Emacs Lisp doesn't support modules. We go by convention. If your module name is foo, then name all your top-level bindings by prefixing it with foo-. Example:

(defun foo-go ()
  "Go!"
   ...)

(provide 'foo)

To make this easier on your fingers, you can use something like:

(defun emacs-lisp-expand-clever ()
  "Cleverly expand symbols with normal dabbrev-expand, but also
if the symbol is -foo, then expand to module-name-foo."
  (interactive)
  (if (save-excursion
        (backward-sexp)
        (when (looking-at "#?'") (search-forward "'"))
        (looking-at "-"))
      (if (eq last-command this-command)
          (call-interactively 'dabbrev-expand)
        (let ((module-name (emacs-lisp-module-name)))
          (progn
            (save-excursion
              (backward-sexp)
              (when (looking-at "#?'") (search-forward "'"))
              (unless (string= (buffer-substring-no-properties
                                (point)
                                (min (point-max) (+ (point) (length module-name))))
                               module-name)
                (insert module-name)))
            (call-interactively 'dabbrev-expand))))
    (call-interactively 'dabbrev-expand)))

(defun emacs-lisp-module-name ()
  "Search the buffer for `provide' declaration."
  (save-excursion
    (goto-char (point-min))
    (when (search-forward-regexp "^(provide '" nil t 1)
      (symbol-name (symbol-at-point)))))

And then:

(define-key emacs-lisp-mode-map (kbd "M-/") 'emacs-lisp-expand-clever)

Now you can write (defun -blah M-/ and get (defun foo-blah. You need a (provide 'foo) line at the bottom of your file for this to work.

Alternative sources

More Repositories

1

intero

Haskell
1,021
star
2

jquery-console

A simple JQuery console emulator
JavaScript
668
star
3

hell

Haskell-based shell scripting language
Haskell
520
star
4

jl

Functional sed for JSON
Haskell
473
star
5

lucid

Clear to write, read and edit DSL for writing HTML
Haskell
284
star
6

vado

A demo web browser engine written in Haskell
Haskell
281
star
7

z

A strict, impure, curried, partially applied programming language with rather peculiar syntax.
Haskell
277
star
8

duet

A tiny language, a subset of Haskell aimed at aiding teachers teach Haskell
Haskell
201
star
9

dynamic

Dynamic typing in Haskell
Haskell
193
star
10

tryhaskell

Try Haskell
Haskell
187
star
11

hulk

Haskell IRC daemon.
Haskell
142
star
12

emacs-config

My Emacs config
Emacs Lisp
118
star
13

haskell-style-guide

95
star
14

ircbrowse

An IRC analysis server.
Haskell
80
star
15

purify

Reproducible builds for PureScript
Haskell
73
star
16

labels

Declare and access tuple fields with labels
Haskell
61
star
17

descriptive

Self-describing consumers/parsers
Haskell
41
star
18

ghci-reload-demo

A demo of using GHCi as a persistent development environment
Haskell
41
star
19

chrisdone-xmonad

My xmonad configuration.
Haskell
33
star
20

freenect

Haskell interface to Kinect.
Haskell
26
star
21

bdo

Do things in the browser from Emacs, namely update the stylesheet (but maybe more later)
Haskell
26
star
22

ats-examples

Examples from Introduction to Programming in ATS
ATS
25
star
23

present

Make presentations for data types
Haskell
25
star
24

audit

Code auditing mode for Emacs
Emacs Lisp
25
star
25

webshow

Show programming language printed values in a web UI
Haskell
22
star
26

sdl2-sprite

Create and animate sprites easily with sdl2 (Haskell)
Haskell
22
star
27

prana

Interpreter for GHC Haskell
Haskell
22
star
28

flycheck-stack

A flycheck checker that uses stack ghci
Emacs Lisp
22
star
29

ini

Quick and easy INI configuration files for Haskell
Haskell
22
star
30

zenburn

Fork of Zenburn theme for emacs
Emacs Lisp
20
star
31

inflex

Pure, statically typed, content-addressable, programming language for spreadsheet use
Haskell
20
star
32

ghc-server

A server interface to GHC.
Haskell
20
star
33

advent-2017-maze-rust-haskell

Haskell
17
star
34

google-closure-purescript

Dockerfile
16
star
35

streaming-parsers

Streaming parsers collection
Haskell
15
star
36

ace

Attempto Controlled English parser and printer
Haskell
15
star
37

scrobble

Scrobbling server. A library providing server-side and client-side support for the Audioscrobbler Realtime Submission protocol: http://www.audioscrobbler.net/development/protocol/
Haskell
15
star
38

flo

Generate flow charts from your code base.
Haskell
14
star
39

conditions

Conditions for Haskell
Haskell
14
star
40

pgsql-simple

A mid-level client library for the PostgreSQL database, intended to be fast and easy to use.
Haskell
13
star
41

sandbox

Small random demonstrations of code
Haskell
12
star
42

duta

Haskell
12
star
43

pure-io

Pure IO monad.
Haskell
11
star
44

caseof

A simple way to query constructors, like cases but slightly more concise
Haskell
11
star
45

css

Monadic Haskell DSL for CSS.
Haskell
10
star
46

rocksdb-haskell-ng

Haskell
9
star
47

snappy

A reactive library for using SVG in the browser for Haskell
Haskell
9
star
48

display

Haskell
8
star
49

ety

Simple API for etymology online
Haskell
8
star
50

copy-paste-sync

An easy way to share clipboard (not encrypted) on a trusted LAN
Haskell
8
star
51

tdiff

Simply print the time difference between lines from stdin
Haskell
8
star
52

frisby

Linear time composable parser for PEG grammars
Haskell
7
star
53

forge

Haskell form library
Haskell
7
star
54

asp-mode

A simple ASP mode for Emacs which does syntax highlighting and indentation support
Emacs Lisp
7
star
55

basic-lens

Basic lens type and functions
Haskell
6
star
56

number

Emacs number manipulation
Emacs Lisp
6
star
57

osdkeys

Show keys pressed with an on-screen display (Linux only)
Haskell
6
star
58

emacs-magit-config

Handy pre-made Emacs config for using magit
Emacs Lisp
6
star
59

org-focus

Emacs Lisp
6
star
60

haskell-exercises

Haskell training test suite
Haskell
6
star
61

gmail

GMail client for Emacs
Emacs Lisp
6
star
62

maintainer

Haskell
5
star
63

hex-server

A minimal X11 server written in Haskell
Haskell
5
star
64

cabal-sign

Haskell
5
star
65

blogination

Very simple blog software
Haskell
5
star
66

sorting

Sorting algorithms
Haskell
4
star
67

stack-doc

Show stack's documentation in Emacs
Emacs Lisp
4
star
68

fore

Haskell Core to JavaScript compiler
Haskell
4
star
69

cron-daemon

Run a program as a daemon
Haskell
4
star
70

keyboard-stats

Gather and produce statistics about keyboard typing habbits
Haskell
4
star
71

codeparty

Online code sharing teaching platform
JavaScript
4
star
72

pdfinfo

Simple pdfinfo wrapper
Haskell
4
star
73

haskelldb-demo

Haskell
4
star
74

hog

IRC logger bot
Haskell
3
star
75

clockin

Track clocking in and out of work.
Haskell
3
star
76

sourcemap

Implementation of source maps as proposed by Mozilla and Google
Haskell
3
star
77

proclog

Haskell
3
star
78

haskell-trace

Add tracing to modules.
Haskell
2
star
79

hamlet-mode

Emacs Lisp
2
star
80

pid1-rust

Rust
2
star
81

senza

An interface to blaze-html without the need for operators.
Haskell
2
star
82

env-args

Source program arguments from the environment in a predictable way
Haskell
2
star
83

url-generic

Parse/format generic key/value URLs from record data types.
Haskell
2
star
84

typegraph

Haskell
1
star
85

riker

Simple reverse proxy, replacement for nginx
Haskell
1
star
86

servant-example

Haskell
1
star
87

liquid-post

Haskell
1
star
88

terminal

Haskell
1
star
89

snap-app

Small snap modules for MVC.
Haskell
1
star
90

yesod-lucid

Haskell
1
star
91

novella

Haskell
1
star
92

codepad

Haskell library for pasting to CodePad
Haskell
1
star