My Current Emacs Config
Table of Contents
Emacs is an extensible Lisp interpreter that functions something like an operating system or window manager with a text editor packaged in. Doom emacs is a prepacked Emacs distribution for people who want to use Emacs without spending months editing their config file to be efficient, which also has vim keybindings enabled by default. I’ve really fallen in love with this piece of software the past month or so - to me it feels in many ways like it fulfills the promise of what a computer should be like, instead of the fragmented, bloated, on-rails experience typical software gives us. Because it’s essentially just a Lisp interpreter, every aspect of Emacs can be customized by its user on the fly. Instead of the usual slow, plodding graphical interfaces most modern apps give, it presents a simple and intuitive text-based GUI that’s arguably only a step or two below Neuralink. And because you can do multiple things in Emacs, you can use the same commands and unified interface for a wide variety of tasks, instead of enduring the mental load of switching different tools and contexts all day. And far from requiring fancy subscriptions and a dev team that could pull the plug on your favorite editor whenever they want, Emacs has had a vibrant community of enthusiasts creating content for free since the 1970s.
I used Doom Emacs to write this, my new website. I’ve also been using Emacs lately as a Rust IDE, for personal and work notes, scheduling and TODOs, and for finding, downloading, and organizing academic papers. This is in addition, of course, to playing Tetris. I’ve been really enjoying the process and so I wanted to write a short post describing how I wrote my website using Doom Emacs, in addition to some other neat features and use cases I’ve discovered so far. I’ll be describing the process using Doom Emacs’ default keybindings, or evil mode, which are similar to Vim’s keybindings. In particular, the “leader” key, or spacebar, will be used very frequently.
Website
This website was written originally in org-mode, Emac’s own format for organizing text files that’s a little bit like Markdown. Its most obvious feature is support for various levels of headers, by using the corresponding number of asterisks. For example, the “Website” header above is a level 1 header. Here are some deeper subheaders:
Level 2
Text in a level 2 header
Level 3
Text in a level 3 header
Back to Level 1
One other cool feature is that you can write tables made of | and - characters, and org-mode will automatically align them correctly:
Color | Bird |
---|---|
Brown | Sparrow |
Blue | Bluejay |
Red | Robin |
.org
files, however, don’t render in web browsers. To turn org files into a web site, we need to convert them to .html
files first. We could do this file-by-file using existing Doom Emacs functionality, but this would be cumbersome. To make this more efficient, we can edit our Doom Emacs config.el
file. Essentially, you put in your config.el
file all of the commands you want to be run when Doom Emacs loads. You can also rerun these commands without restarting Emacs with a simple SPC h r r
by default.
The code we want in our config file is:
(setq org-publish-project-alist '(("org-site" :base-directory "~/org/site" :publishing-function org-html-publish-to-html :publishing-directory "~/public_html" )))
We also need the following line at the top of each of our webpages:
#+EXPORT_FILE_NAME: ~/org/<pagename>.html
Here setq
is a function that sets a variable. org-publish-project-alist
is a variable used to set the projects that can be published with the org-publish-project
command. Here we are defining a to-be-published project called org-site
which is located in /org/site
, and which will be published by automatically converting .org
files into .html
files. The .html
files will be published to ~/public_html
with the names provided in their #+EXPORT_FILE_NAME
tags.
I also added the following code to my config to make the org-mode header bullets prettier:
;; Use UTF-8 symbols for org mode bullets (require 'org-bullets) (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
This requires installing a new package, org-bullets
. This is on MELPA, a repository for Emacs packages, so I can just add
(package! org-bullets)
to init.el
in my Doom Emacs config directory to download it automatically.
Note that because Emacs is a unified and self-documenting system, we can easily look up any function or variable we come across. Calling describe-variable
with SPC h v
then typing in org-publish-project-alist
gives us a detailed explanation of what the variable does, in addition to a hyperlink we can use to jump to its definition in the relevant piece of code, which we of course we can also edit. Similarly, calling describe-function
with SPC h f
and searching for org-publish-project-alist
gives us a detailed description of what this function does as well as a hyperlink to its code.
Org Babel
The embedded piece of Elisp code above also showcases another cool package for org mode called org babel. This package allows you to embed and even run code in your documents, similar to literate programming notebooks like Jupyter. Here is some Python:
x = 4 y = 3 z = x + y return z
7
As you can see, we’ve run the code with org-babel-execute-maybe
(ctrl+c ctrl+v ctrl+e
), which automatically prints the result.
Styling your html files
The .html files we can generate this way are a bit bland, however. If you’re familiar with webdev and know how to use css you might be able to spruce them up to look better. If not, there’s an easier solution. Adding #+SETUPFILE: https://fniessen.github.io/org-html-themes/org/theme-readtheorg.setup
will automatically style our pages with ReadTheOrg, which is designed to make org files exported to html look pretty.
I wanted a header on each page to provide a hyperlink back to my homepage, so I also add #+INCLUDE: "~/org/site/header.org"
to each page. This file just contains some simple html code to link back to the homepage of my website.
Downloading and organizing papers
One of the biggest other use cases for org mode for me has been downloading and organizing academic papers, particularly for cryptography. I wrote the following simple code in my config file to download pdfs:
(defun download-paper (url name) "Download a pdf given a URL and filename" (interactive (let ((arg1 (read-string "URL: ")) (arg2 (read-string "Filename: "))) (list arg1 arg2))) (shell-command (format "curl %s --output ~/org/papers/%s.pdf" url name)))
The interactive
function here tells emacs to make this function callable from emacs directly. All such functions can be searched through and called by holding the “meta” key and pressing x. On MacOS, this is Command+x
by default. So to download a paper, I type Command+x
, search for “download-paper”, hit enter and copy-paste the URL, then finally type in a filename which the pdf will be saved as in my filesystem.
Next to organize my papers, I have a file ~/org/papers.org
that contains headers for various subfields I’m interested in like “Signature Schemes”, “SNARKs”, or “Emacs”. I’ve added the following “Paper” org capture template to make adding to it easy:
(setq org-capture-templates '(("p" "Paper" entry (file+headline "~/org/journal.org" "dummy") "* [[pdf:../papers/%^{FILENAME}.pdf][%^{TITLE}]] %?\n *** %^{DESCRIPTION}") ("b" "Bookmark" entry (file "~/org/bookmarks.org") "* %?\n%i") ("t" "Personal TODO" entry (file "~/org/agenda/personal.org") "* TODO %?\n%i" :prepend t) ("z" "Cryptography Code" entry (file "~/org/cryptography.org") "* %U\n #+BEGIN_SRC rustic \n %?\n%i #+END_SRC") ("c" "Cryptography Note" entry (file "~/org/cryptography.org") "* %U %?\n%i")))
There are a few things going on here. Note the file being written to by default is not papers.org
. This is because I don’t want to save my capture note with the usual ctrl+c ctrl+c
shortcut that saves to the default file. Instead I use the refile shortcut, which is crtl+c ctrl+w
. This allows me to search the headers of all my emacs files to choose one to save my note under. If I want to save a SNARK paper for example, I’ll type crtl+c ctrl+w
, then type in “SNARKs”, and refile the note under ~/org/papers.org/SNARKs
.
Note that [[][]]
is the org-mode syntax for hyperlinks. The Paper template automatically creates a hyperlink to my papers folder given the correct filename. It’d be nice to link the download-paper
function and org capture template together so I don’t need to retype the filename when adding the paper to my papers.org file, but that’s a task for another day. After retyping the filename, I copy-paste the paper’s title into the TITLE prompt, then a brief description into the DESCRIPTION prompt. I also like to add the year the paper was published to the right of the title in parenthesis. This shows up as a different font color with most of the color schemes for Emacs, which looks quite nice.
Once the hyperlink is added to my org file, I only need to highlight it with my cursor and hit “enter” to open the PDF. Because PDFView is my default PDF file viewer in Emacs, the PDF opens in a new Emacs buffer, which also supports evil mode for Vim keybindings. And because the papers.org file is written in org mode, I can easily create additional subheaders underneath the hyperlink to add notes on the paper itself. Org mode allows you to close and open the contents of different subheaders with the tab key, so it doesn’t need to get too cluttered if you do this.
Those notes can even contain LaTeX embeded in the org document itself by encasing it in dollar signs, such as \(x \leftarrow 3\). This will automatically display as LaTeX when exporting your file to html, but you can even display it in Emacs itself using the org-latex-preview
function, which by default has the shortcut ctrl+c ctrl+x ctrl+l
.
Elfeed
Not only do I use Emacs to organize my cryptography papers, I also use it to keep up to date with research. Elfeed is another neat Emacs package that can be used to track RSS feeds inside of Emacs. I use it to track the eprint RSS feed at https://eprint.iacr.org/rss/rss.xml. If a paper title on the RSS feed interests me, I hit enter on it to open the abstract. From there the keyboard shortcut g o
opens the eprint webpage for the paper. The function eww-copy-page-url
copies the url to my clipboard, and adding “.pdf” to the end gives me the url necessary to either download the paper or open it in another browser. Searching “PDF” on the page also takes me to the hyperlink to the paper which I can also open in PDFView inside Emacs.
Note that the links only open in Emacs by default because I have the following in my config.el
:
;; Default to using eww browser for web links (setq browse-url-browser-function 'eww-browse-url)
Magit
I also want to be able to save these papers to my github account to ensure they’re not lost if my computer gets wiped. To do this I use Magit, which is Emacs’ most popular version control wrapper for git. I won’t give a detailed guide for it here, but it makes saving my private org files repo, including my saved papers, very easy. I execute the “Magit” function, then type s
to stage my new and modified files, then c c
to commit, type a commit message, ctrl+c ctrl+c
to save the commit message, then p u
to push to main. This is really one of the best packages available for Emacs - I use it for software developement as well.
Of course, I also have my Doom Emacs config directory saved to a Git repository, so I can easily port it across machines.
Rust
One of my other main uses for Emacs lately has been as an IDE for Rust. For this I use the default Rust support that can be added to Doom Emacs in its init.el
file, which can be added by uncommenting out the “Rust” line. This includes typical IDE features such as syntax highlighting, autocomplete, jumping to definitions, and so on. One thing I like is that this provides a Vim-like aesthetic and experience when using evil mode (Vim keybindings in Emacs), but with extra features you could only get in a GUI interface such as optional mouse controls and clicking to run tests, in addition to being easily able to access all the other features of Emacs from the same interface. Some of my most frequently used movement shortcuts are ctrl+o
and ctrl+i
to go back or towards the last point jumped from, and ctrl+0
and ctrl+1
to close the current window or all but the current window respectively. I’ve also rebound going to the previous and next buffers to command (meta) + [ or ] respectively.
One of the nice things about Emacs is that when you open a file, it is always opened in a new buffer which stays open even if you navigate away. So if you jump to a definition (which I have set to SPC c d
), then later decide to reopen the same file, you can open up your list of buffers (SPC b i
), search for the filename, and open it. This also gives me a bit of flexibility in navigation with the shortcuts I described above. Say I’ve jumped down a series of definitions through multiple files, and I want to come back up. If I want to be a bit more fine-grained with how I do things, I can use ctrl+o
to go back to every point I’ve jumped to. But if I’ve searched around a few files, this might be more than I want. I can use command+[
then to go back file-by-file instead of point-by-point. And because the buffers containing those files never closed, my cursor will be back in the same place I left it.
Another related neat thing about Emacs is that it stores metadata about all of the actions you took on a file. You can close Emacs completely, reopen it, and you will still be able to undo any changes you made on a file in Emacs. There is a limit to this but by default it’s on the order of hundreds of thousands of bytes of undo data per buffer.
In my config file I also have the following piece of code which sorts my buffers in ibuffer according to the type of file they are, which makes navigating them easier:
(setq ibuffer-saved-filter-groups '(("MyList" ("Dired" (mode . dired-mode)) ; Filter by mode ("Rust" (mode . rustic-mode)) ("Circom" (filename . ".circom")) ("Move" (filename . ".move")) ("Org" (filename . ".org")) ; By filename )))
There are also a number of functions that can be used to call cargo within a .rs
file, provided by the rustic
package. Cargo build (SPC m b b
), cargo add (ctrl+c ctrl+c a
), and cargo test (SPC m t a
) are a few of the cargo commands which have shortcuts provided by the rustic package. One of my most used is rustic-cargo-current-test
(SPC m t t
), which runs cargo test with the name of the test that the cursor is nearest in the current file. These commands also open their own small window when run, so their results are visible without cluttering the screen. And if you want to run a command without a shortcut, you can use the option+!
(M-!
) shortcut to run the shell-command function, to execute a shell command in the directory of your current file without even opening a terminal.
Another nice convenience function associated with rust-analyzer instead of rustic is lsp-rust-analyzer-open-cargo-toml
, which opens the Cargo.toml file nearest the file open in the current buffer.
Grep and file search
I use a package called affe
to handle grepping for strings in directories, and for searching for substrings of files. One of the downsides of Emacs is that it’s single threaded. This makes it easier to extend, but obviously isn’t always ideal for performance. Fortunately, affe
spawns its search processes in a separate program which return their results to Emacs asynchronously, so you can do other things while it’s running. So far this is the only downgrade I’ve experience from using Vim - I found Silver Searcher in Vim to have a smoother experience. But affe is still decent.
For moving around my filesystem normally, I use dired
. It has a lot of features, and I won’t get into them here. One that’s kind of neat is you can edit filenames directly in dired as though you were editing a text buffer, and it’ll actually modify the filenames in your filesystem. I wanted normal Vim keybindings for navigation so I added the following to my config.el
:
(evil-define-key 'normal dired-mode-map (kbd "l") 'dired-find-file (kbd "h") 'dired-up-directory)
Org Agenda and Capture
Any discussion of Emacs wouldn’t be complete without talking about Org Agenda. It’s pretty rapidly become my defacto organizer for all of my personal and work daily tasks. Earlier I mentioned using Org Capture to help organize technical papers, and shared some code that had some other templates in it. One of most useful is my personal TODOs template. If I think of something I need to remember or take care of, I type SPC x
, then t
, then type whatever it is and hit ctrl+c ctrl+c
to save it tp personal.org
. If I leave the TODO, the item gets added to my Org Agenda TODO list, easily accessible with SPC o A t
. I also have a file for work TODOs which I prefer to edit by hand. Both show up on the same list organized by priority, which I can edit with shift+up
or down
. If I want only my personal or work TODOs, I type <
while highlighting an item, and only TODOs from the same category (in my basic setup, identical to the film containing the item) will appear. On the other hand, if I type SPC m d s
to add a date or time to an item, regardless of whether I put a TODO on it, it will appear on my Agenda calendar, which I can open with SPC o A a
. This looks like SCHEDULED: <2024-08-18 Sun 08:15>
. I can also make events recurring weekly with the syntax SCHEDULED: <2024-08-18 Sun 08:15 +1w>
. The nice thing about Capture mode is that, because Emacs is a unified system, it’s very easy to access while doing something else. If I remember a call I need to make or something else while working, I can type a few keyboard strokes to record it without even leaving the file I’m currently on.
My other Capture mode templates are a file that I use to store links to interesting pages on the internet, and shortcuts to write notes and Rust code snippets to a file dedicated to cryptography notes, which of course supports LaTeX because it uses org mode. I’m just getting started though, so I’m sure I’ll find more use cases as I go on.
Touch Typing
Speed type is a nice little package that helps you to practice speed typing. I’ve been learning to touch type recently so it’s nice to be able to open it a few times a day to keep my practice up, without having to leave Emacs. When you call speed-type-mode
it automatically downloads a passage from project Gutenberg for you to type. You can even use Vim commands while typing.
Color Styles
It’s also very easy to change the color scheme of your Doom Emacs GUI. You can try out over 90 default themes with load-theme
(SPC h t
). I use the Iris software to change the color of my screen manually based on my environment and the position of the sun. I always keep it red after sunset so I need a theme that looks good both in full color and when the screen has no blue in it aside from the backlight. After a lot of experimentation I found that doom-1337
works well for this. I have it set as my default theme with:
(setq doom-theme 'doom-1337)
Tetris
Of course, calling the tetris
function starts a game of tetris. It even supports evil mode for Vim keybindings! I’m pretty bad at it unfortunately - I didn’t get into cryptography because I’m good at shape rotating.
Acknowledgements
Thanks to Programmers Are Human Too for inspiring me to use Emacs initially with this video, and to DistroTube for some very helpful videos in getting started.