Emacs from scratch again

geekery emacs

I’ve been here before, but I find myself back here again. I think that many people who start off with one of the big frameworks (like Spacemacs or Doom Emacs) eventually circle around to thinking, “hey, why don’t I just build my own Emacs config that includes the best bits of Spacemacs/Doom?”. Usually, that is followed some time later (as happened in my case last time), by the realization that those frameworks are really well crafted, and getting anything like that degree of polish and sleekness yourself is very difficult without basically replicating the entirety of those projects. However, I’m playing with configuring from scratch again, just for kicks.

My reasons are nebulous and not very well defined, and can basically be boiled down to — I felt like it.

As I’ve got more comfortable with Doom, I’ve learned a lot more about which packages work best for me, and how I like things configured, so it has helped me to narrow down a comfortable setup without a lot of work on my part. There have also been some new packages out recently, and updates to packages I was using previously, which have enabled me to build a more streamlined system. The constellation of what I suppose we might call completion-related packages (Selectrum/Vertico, Consult, Orderless, Marginalia and Embark, some of which I wrote about here) have become really sleek and capable, and much easier to configure than they used to be. The built-in project.el package handles a significant subset of the capabilities of projectile, without needing to load an external package. projectile is still a brilliant package, but if you (like me) only use a small subset of its powers, then project.el will probably work well for you. Finally, chemacs has been around for a while, but the latest version now handles including an early.init.el in your configurations, which is useful with more recent versions of Emacs. Chemacs, for those not familiar with it, is a brilliant tool which enables you to keep several different versions of Emacs configurations (including either Spacemacs or Doom Emacs) around and choose to load any one of them. You can even open two versions of Emacs, one running Doom and one running your new configuration. This makes it much less disruptive to tinker with your Emacs configuration, because you can continue to use your working version as normal, as well as editing your new configuration with your usual Emacs configuration.

First things first, I decided to take the plunge and move to Emacs 28 with native compilation (gccemacs). I used the d12frosted/emacs-plus formula from Homebrew, specifying emacs-plus@28 --with-native-comp as the formula. It took quite a while for everything to compile, but once finished, it worked beautifully. Natively compiled Emacs 28 feels a lot more snappy on my Macs, and I haven’t yet found any problems with running it.

Doom uses a clever custom packaging system which is built on straight.el. I had also got used to using Doom’s use-package configuration, which made everything a bit neater and more modular. When I looked into straight.el more, I found that it had a neat way of making configurations completely reproducible by combining the init file and a versions lockfile. It also works with use-package: if you set it up with (setq straight-use-package-by-default t), use-package will use straight to fetch and build packages by default. This also means that you are not limited to packages on the main repositories (like ELPA and MELPA), but you can also specify those on GitHub or local packages, which increases flexibility. Now that I have got used to this system, I really like it. If you save a versions file for a working configuration, you can update packages without worrying that it will break your system, because you can always restore your system to the version in the lockfile if things go wrong.

I haven’t finished building all the features I want into my scratch configuration yet, but it is already comfortable enough to edit the configuration (and this blog post) with, without having to resort to my Doom Emacs configuration. I’m still using evil bindings, and I have started to build SPC leader bindings using general.el so that I have a custom menu of options without having to remember all the built-in bindings. I’m also using Vertico for completions which I have really come to like, Orderless for more advanced completion styles, Marginalia for minibuffer annotations, Embark for custom actions in the minibuffer and buffer, and Consult for some handy commands which integrate well with the other packages. All of these packages build on top of standard Emacs functions (like completing-read), so integration is tight and fairly seamless.

I could have just used doom-modeline or configured my own modeline, but I tried out telephone-line, really for no other reason that the name is based on a great ELO song1, and because it’s pretty. I like it a lot, and it turned out to be quite easy to configure to my liking.

I’m also trying out the new org-cite framework which is built into Org 9.5, along with the bibtex-actions package to make it easier to choose, insert and act on citations. Now that org-cite and pandoc can use the same citation format, it should be much more seamless when including references in documents. bibtex-actions is great now that I have it working, but I did get a bit stuck initially trying to set up the example configuration for org-cite that is included in the README. It is probably some interaction with the way that straight.el defines packages, but I found that I had to set it up like this to get it working with Zotero and org-cite:

(defvar my/bibs '("~/Documents/bibtex/zotero.bib"))

(use-package citeproc)
(use-package bibtex-actions
  :bind (("s-b" . org-cite-insert)
         ("M-o" . org-open-at-point)
         :map minibuffer-local-map
         ("M-b" . bibtex-actions-insert-preset))
  :after (embark oc)
  :config
  (setq bibtex-actions-bibliography my/bibs
        org-cite-global-bibliography my/bibs
        org-cite-insert-processor 'oc-bibtex-actions
        org-cite-follow-processor 'oc-bibtex-actions
        org-cite-activate-processor 'oc-bibtex-actions)
  (setq org-cite-csl-styles-dir "~/Zotero/styles"))

;; Use consult-completing-read for enhanced interface.
(advice-add #'completing-read-multiple :override #'consult-completing-read-multiple)

;; a hack to get bibtex-actions working
(load "~/.emacs-configs/scratch-emacs/straight/build/bibtex-actions/oc-bibtex-actions.el")

If I didn’t load the oc-bibtex-actions.el file manually at the end, none of the variables in the use-package block got defined. I’m probably missing something obvious, but this makes it work for me. I will try to remember to log an issue on the GitHub project to ask what I’m doing wrong.

Anyway, I’m having fun. My custom Emacs config is working pretty well, and it is still snappy to load and run. I’ve learned more along the way about some of the packages that I was just loading blindly before, so it has been a useful process. I wouldn’t lay any bets with myself that I won’t have scurried back to the luxury of my Doom Emacs configuration within a couple of months, but for now I’m enjoying the process!


  1. Every time I edit the telephone-line config, I sing “Oh, oh, telephone line, give me some time…” ↩︎