Emacs Config Gems - Part 1
I’ve been working on my Emacs config for three weeks now, coming this weekend. It’s one of the deepest and most fun rabbit holes I’ve been exploring. As I stumble upon new ways to do things, I dig deeper, learn more, and keep tweaking my config, which makes this rabbit lair even bigger.
Eventually I realized that if I wait until I’m done to upload the config file, it will never happen: by the time I’m done, I will accumulate enough fixes and additional tricks and tweaks to warrant a whole new file.
The conclusion is what I should have done from the beginning: apply changes in chunks and explain what I’m doing and why as these happen.
I’m starting with changes to my .emacs1 file on my mac2, before we’re even touching the “good stuff” in my main emacs-settings.org file. Why? Because Emacs was built with Linux in mind, and we need to make some important adjustments to how Emacs works on a Mac before we use it. As you will see, I’m using this conceptually too: while some of the configurations in the .emacs file (the “init” file) could technically be placed in the big emacs-settings.org file, I still place them in what I consider Emacs’ “booting” process.
My .emacs file contains only these four code blocks, which are separated with spaces for visual convenience:
(when (memq window-system '(mac ns x))
(exec-path-from-shell-initialize))
(setq insert-directory-program "gls" dired-use-ls-dired t)
(setq custom-file (expand-file-name "emacs_custom.el" user-emacs-directory))
(load custom-file 'noerror)
(org-babel-load-file
"/Users/user/Sync/Public/emacs_settings/emacs_settings.org")
exec-path-from-shell-initialize
(when (memq window-system '(mac ns x))
(exec-path-from-shell-initialize))
This tells Emacs that if its windowing system is macOS-related (ns or x; there’s also the old mac version of Emacs that is not being used today — the Homebrew emacs-plus one we are using here is ns, which can be checked with M-x emacs-version), it should run exec-path-from-shell-initialize.
This function copies the PATH from the shell, as if we were using a terminal program. By design, macOS GUI applications (those that live in the user’s Applications folder and have an .app extension) are not exposed to this PATH because they’re launched by a different process altogether (launchd)3. But Emacs needs this PATH, as many of its core components integrate with the OS as a terminal application, which is what it is, at its core.
In fact, this is why we need this condition in a file that resides on a Mac, and why this condition is triggered by the windowing system, and not the OS itself (every other condition in our config would be written as eq system-type 'darwin or similar). If we run Emacs in terminal, the program already has access to PATH, and this execution is not needed.
Use gls in Dired
(setq insert-directory-program "gls" dired-use-ls-dired t)
This doesn’t have to live in our .emacs file, as it can live as part of our Dired options in emacs-settings.org, which will come later. However, this is a macOS-only thing, and since we need to get gls from Homebrew, it’s one of those things to prepare before we start Emacs for the first time. After all, we will probably use Dired right away after install, and we want to make sure it’s ready.
gls, GNU’s ls command, is bundled with other utilities inside coreutils, so we install it with brew install coreutils. Then the above command makes sense — we’re telling Emacs to use this flavor of this ls command instead of the one that comes with macOS, which is lighter and doesn’t have what we’re used to seeing in Emacs Dired (at least, not for me). As it turns out, there are other well-known utilities in this package, such as rm and mkdir, but we don’t use them, so it’s really just for gls.
Changing Emacs’ custom default file to emacs_custom.el
(setq custom-file (expand-file-name "emacs_custom.el" user-emacs-directory))
(load custom-file 'noerror)
This is something I discovered while working on my .emacs file. It was cluttered with comments and configurations from Emacs’s custom, Emacs’ settings wizard. This is because by default, Emacs doesn’t have a definition for it:
File used for storing customization information. The default is nil, which means to use your init file as specified by ‘user-init-file’. If the value is not nil, it should be an absolute file name.
It makes sense if you use custom often, which probably means you don’t bother with babel (coming up) and writing long Emacs posts like this one, but in reality, I haven’t met an Emacs user who used it for more than a few months at most without getting their hands dirty. It’s just too tempting.
The first line tells Emacs where the custom file config is (inside /.emacs.d/, the default for user-emacs-directory), and the second line tells it to “not worry” if the file is not there. Why? Because the first time we run Emacs (or a clean reinstall), we might not have this file at all yet, as it’s created by custom. If we don’t have this file, Emacs will do whatever it does whenever it encounters an error: tell us there’s an error and stop running the rest of the config. And this happens right at the beginning, so essentially our entire config will be skipped. So this is a good safety option4, and probably good practice.
Org-babel: load the configuration from an org file
(org-babel-load-file
"/Users/user/Sync/Public/emacs_settings/emacs_settings.org")
Now, after we put all the critical macOS5 configuration in place, it’s time to tell Emacs where the rest of the configurations are. This here was just the introduction, the Emacs “boot” for Mac only, after all6.
So here we are, done with part 1. It took me way longer to write than I thought it would take (I’ve been standing at my desk for about 2 hours now), but this is exactly the sort of thing that keeps me hooked on Emacs. Everything leads to more… everything. There’s a story behind every dot, apparently. As you can see from my footnotes, I’ve found additional tangents to go on while writing this just now, and that’s on top of a growing list I already have, of about 10 other things I want to check — and my config is only about 25% done. And as I said, by the time I’m done, it will be time for round 2, which in turn will probably lead to round 3…
“Emacs. It really whips the GNU’s…” errm. Anyway. See you next time!
Footnotes
1 The story of dot files (files that start with a dot, like .emacs) is an interesting one. Turns out it was a programming mistake back in the days when Unix started, and it stuck as an idea. These became convenient to use as configuration files because they are the sort of files that are usually created when you install something and configure it once, probably to never see it again (this was before Emacs users started popping up, obviously), so the bug became a feature.
2 On a Mac, you have several options when installing Emacs. The one I’ve been using over the years, and what seems to be the most popular, is emacs-plus at https://github.com/d12frosted/homebrew-emacs-plus. Some of the choices I made in my .emacs file are based on this fact.
3 There’s another rabbit hole here I didn’t explore much: Emacs on Homebrew, at least in some versions, has incorporated the option to grab the PATH during installation; however, it seems Apple blocked this option at some point, so we need to run it like this. I don’t recall ever getting a warning that Emacs needs access to my PATH or something similar, but I wouldn’t be surprised if something to that effect is happening when you first install it.
4 As I’m writing this, I realize there’s another worthwhile rabbit hole here: the option to tell Emacs to ignore errors for non-critical configurations, such as the theme, or the way org-mode displays, etc. While I want these in place, if there’s an error, I’d like Emacs to keep loading the config if it can. Since there are different “skip error” options depending on where and what is being skipped, and since I need to be sure what I’m skipping, I’ll do more digging another time.
5 Ah ha, but that last one, the custom file location, is also good on Linux! Good thing I’m writing this blog post. When I go back to my Linux machine, I will include this line there as well.
6 By the way, while there is no org-babel.el, it can almost be one from a quick look (yes, yet another rabbit hole). There are many different .el files scattered in Emacs that relate to org-babel which can do different things.