I have zero understanding of what happens when my Emacs boots up and loads the extensions, applications and utils I have asked for in my configuration. Why? Because I have written my configuration with use-package, which hides all practical details under a nice, declarative macro language11 Which is great – please don’t get me wrong here! That macro language is absolutely amazing, but it steps in the way of fully understanding things..
I dislike not understanding what is going on, so I’m starting to slowly migrate
my Emacs configuration over to use more basic primitives.22 As basic as is
humanly reasonable, actually. I will prefer things like
key action) over
(global-set-key key action) because the latter is just a
thin wrapper over the former, and I – for once – want to expose the
implementation. But since I’ve only known
bind-key and its
high level companions, I didn’t really know how to write a low-level Emacs
These were the things I learned.
This is more of an Emacs Lisp language question than an Emacs configuration question, but it’s caused me some confusion and it does make a difference in many places in your configuration, so I’ll quickly go through it first.
add-to-list are used to add a new element to a list, updating
it in place. The main difference (besides the syntactic convenience of
add-to-list works like a set inclusion operator. In other words, if
the element you are trying to add to the list already exists in the list, it
will not be added again.
This can be a good thing (if duplicates are bad in that particular list) or it
could be a bad thing (if duplicates are okay and the list is very long – then
add-to-list has to traverse the entire list every time you add something to
it! That’s going to be slow.)
Loading and the Load Path
This is going to be a short section. Loading in Emacs terminology simply means
evaluating an Emacs Lisp file. On the most basic level, you do that with the
load function. If you call
(load "filename") Emacs will try to read and
evaluate any of the following, in the following order:
As you can guess, it is advantageous to not specify the
.el file extension,
because if you omit it, Emacs will automatically first try to load the compiled
version of the same code!
So where does Emacs look for these files? In whichever directories are specified
load-path variable. It should contain a list of directories to look in,
and entries appearing earlier in the list are given priority.
This is one of those things which you may expect to be complicated, but it quickly turns out that’s not the case. There are three things to understand:
- There is a global variable called
features, which contains a list of symbols, and this is interpreted by Emacs as a record of which files it has loaded.
- When you call
(provide 'symbol), Emacs will add
- When you call
(require 'symbol), Emacs first checks if
symbolis in the
featureslist. If it isn’t, Emacs will load try to load a file with the name
That’s it. As you can see, a “feature” isn’t really a thing in Emacs, it’s
just about a convention that when you write a file to be loaded, you end that
file with a call to
provide to be nice and tell Emacs that it has successfully
loaded the file and should not do it again, even if the file is
Note that if you byte-compile your Emacs configuration, any
require calls you
have will be executed also during compilation. This is because anything you
require can introduce new macros, and the compiler needs to know about these
in order to be able to expand them.33 It also helps prevent it from warning
you about variables not being known to exist.
Binding and Unbinding Keys
Keybinds are recorded in maps. The global map contains keys which are active at all times, and then one or more local maps may also be active, and these provide additional bindings (which overshadow the global map in case of collisions). Local maps are often associated with major and minor modes, and activated and deactivated with them.
If you don’t use the
bind-key utilities that ship with
want to bind keys manually. You could do this through the functions
global-unset-key and so on. But these are
just thin wrappers over the fundamental operation:
Basic usage is
(define-key map key action)
nil as an action means unbinding the key from the map. The map can
global-map if you want a bind that’s available at all times. Many
modes have their own maps, which are active only when that mode is active.
You can also create your own maps! I have some custom Org binds, for example, which are collected in a single map under the F4 key. You do this by first preparing a symbol to hold a keymap, then you add some keys to it, and then, as a last step, you bind that keymap to a key. I suspect it has to be the last thing you do, because you’re binding the value of the keymap to a key, not the symbol. So any updates to the symbol will be invisible to the bound keymap.
(define-prefix-command 'keymap) (define-key 'keymap key-second action) (define-key global-map key-first 'keymap)
After this, consecutively pressing
key-first and then
Declare Eager Dependencies
If you want to load and configure some dependency immediately when your Emacs configuration is loaded44 Why would you not want to do that? It depends. If the dependency takes a long time to load, you may very well want to postpone it until it is actually needed the first time., you can do that with the interesting combination of
(when (require 'dependency nil 'noerror) configuration-code)
This will attempt to load
dependency, but failing to do so, it will simply
nil and not try to perform any configuration, in contrast to throwing
an error message. From what I can tell ,the configuration code will be executed
each time this code is executed, even if
dependency has already been required.
If you think about it, that makes sense, though.
Loading a full dependency can take a few milliseconds. When you start to have many dependencies, the milliseconds stack up and your Emacs will boot up slower. On the other hand, there is no reason to load all dependencies when Emacs boots. Many can be deferred and loaded only once they are actually needed.
I should say that all well-designed dependencies do this automatically. When you “load” these dependencies (using the technique in the section above), you don’t actually load their full implementation, you just evaluate a few autoload declarations.
That said, now and then you come across a package that is not as well designed, so you’ll need to set up the proper autoloads manually. You do this through the somewhat weird pattern of,
- Define autoloads for the dependency
- Define triggers for the autoloads (maybe
- Tell Emacs what configuration you want to run after the dependency is loaded
In code, this may look like
(autoload 'command-from-dependency "dependency") (define-key global-map key #'command-from-dependency) (eval-after-load "dependency" list-of-configuration-statements)
Here, we say that if
command-from-dependency is executed and
not in the
features list, Emacs should require
dependency. We also say we
key to execute
command-from-dependency, so in effect pressing
dependency to be loaded.
Then we have some
list-of-configuration-statements we cannot run until after
dependency has been loaded: in this case, we get to use
which does what it says on the tin: it evaluates the second argument whenever
the first argument is loaded. Note that
to be quoted! Since it’s a regular function argument, it will get evaluated at
call time, and then the result will be evaluated once the dependency is loaded.
Of course, the trigger for the autoloaded command does not need to be a key – it could be anything, including automatically calling a command whenever a file with a particular extension is opened.
(push '("\\.extension\\'" . dependency-command) auto-mode-alist)
Again, keep in mind that it may not be necessary for you to lazy-load well-written modes manually – they should lazy-load themselves at the correct points in time.
The way I understand this – and I’m not at all sure I have the correct understanding now, since I haven’t had time to dig into it myself – is that some people like to byte-compile their Emacs configuration to decrease load times. Compilation gets tricky in the presence of powerful macros, which Lisp have.
Of the two forms above,
eval-when-compile is probably the simplest, and it is
mostly just an optimisation technique. Anything inside
be executed once during compilation, and then the entire thing will be replaced
with the result of that execution. So if you have a really expensive function,
you could create an
eval-when-compile form that turns it into a lookup table,
Then we have
eval-and-compile, which is described in the manual as mostly
having “fairly sophisticated” uses. You can probably tell from the name what it
does: it’s a little like
eval-when-compile, except it doesn’t replace the
original body with the result. It keeps the original body verbatim,
in addition to executing it once during compilation. This means that any
functions or values that are defined in the body will be available both during
compilation and later when the code runs. Useful e.g. if you create a macro that
depends on a function to generate the correct code, because then the compiler
can run the function to see which code to generate.