Emacs Lisp (Elisp) is a small, elegant Lisp dialect that powers Emacs. Even if you’re not writing full Emacs packages, understanding a few essential constructs can help you automate tasks, customize your editor, and write smarter configuration code.
In this article, we’ll explore some of the most useful, everyday Elisp building blocks that every Emacs user should know — with small, practical examples you can immediately paste into your config.
1. unless — Execute Code Only When a Condition Is False
unless is the opposite of when.
when= do something if condition is trueunless= do something if condition is false
Syntax
(unless CONDITION
BODY...)
Example: Load a theme only if it isn’t already active
(unless (member 'modus-operandi custom-enabled-themes)
(load-theme 'modus-operandi t))
Example: Create a directory only if it does NOT exist
(unless (file-directory-p "~/.emacs.d/temp")
(make-directory "~/.emacs.d/temp"))
2. file-directory-p — Check Whether a Path Is a Directory
Elisp provides several file-testing functions. One of the most frequently used is:
(file-directory-p "/path/")
It returns t if the path is a directory, nil otherwise.
Example: Verify a project folder
(if (file-directory-p "~/projects/my-app")
(message "Project folder found!")
(message "Directory missing!"))
Example: Create multiple directories if missing
(dolist (dir '("~/.cache/emacs" "~/.config/emacs/backups"))
(unless (file-directory-p dir)
(make-directory dir t)))
The t in make-directory allows creation of parent directories as well.
3. when — Run Code Conditionally (The Friendly if)
While if is the classic conditional, when is often easier to read when there is no “else” clause.
Syntax
(when CONDITION
BODY...)
Example: Enable line numbers only in programming modes
(add-hook 'prog-mode-hook
(lambda ()
(when (not (bound-and-true-p display-line-numbers-mode))
(display-line-numbers-mode 1))))
4. if — Two-Way Conditional Logic
When you need both “then” and “else” logic, stick with if.
Syntax
(if CONDITION
THEN-BODY
ELSE-BODY)
Example: Set a font depending on the system
(if (eq system-type 'darwin)
(set-face-attribute 'default nil :font "Menlo-14")
(set-face-attribute 'default nil :font "DejaVu Sans Mono-12"))
5. let — Create Local Variables
let is essential when you want to store values temporarily inside a function or block of code.
Syntax
(let ((var1 value1)
(var2 value2))
BODY...)
Example: Construct a file path dynamically
(let ((base-dir "~/.emacs.d/data")
(filename "session.json"))
(message "Loading %s" (expand-file-name filename base-dir)))
6. dolist — Loop Through a List
A clean way to iterate over items:
(dolist (item '(a b c))
(message "Item: %s" item))
Example: Batch-create directories
(dolist (dir '("~/.emacs.d/logs" "~/.emacs.d/tmp" "~/.emacs.d/cache"))
(unless (file-directory-p dir)
(make-directory dir)))
7. and and or — Simple Logic Operators
Example: Only run if BOTH conditions are true
(when (and (file-exists-p "~/notes.org")
(file-readable-p "~/notes.org"))
(message "Notes are ready!"))
Example: Try multiple file locations
(or (file-exists-p "~/.emacs.d/init.el")
(file-exists-p "~/.config/emacs/init.el")
(message "No init file found!"))
8. Combining Them Into a Real-World Example
Here’s a practical snippet that uses everything we’ve covered:
(let ((cache-dir "~/.emacs.d/cache"))
(unless (file-directory-p cache-dir)
(make-directory cache-dir t))
(when (file-exists-p "~/org/todo.org")
(message "Todo file found!")))
This snippet:
- Creates a variable
cache-dir - Checks if the directory exists
- Creates it if missing
- Checks for a specific org-mode file
- Prints a message if it exists
These tiny constructs let you build surprisingly powerful Emacs customizations.
Conclusion
Learning a handful of simple Elisp constructs — such as unless, when, file-directory-p, if, and let — dramatically expands what you can automate and customize in Emacs. These are the everyday “bread and butter” tools used in nearly all Emacs configuration and package code.
If you understand these, you're already well on your way to writing clean, effective Emacs Lisp.