Configuration is at the same time the most fun and biggest challenge of
any Emacs installation. I think it’s a good time to
recall Anthony Bourdain’s thoughts about mise en place1 mise is, by no coincidence, the name of an excellent SDK
management tool: https://github.com/jdx/mise.
Mise-en-place is the religion of all good line cooks. Do not mess with a line cook’s ‘meez’ — meaning his setup, his carefully arranged supplies of sea salt, rough-cracked pepper, softened butter, cooking oil, wine, backups, and so on. As a cook, your station, and its condition, its state of readiness, is an extension of your nervous system… The universe is in order when your station is set up the way you like it: you know where to find everything with your eyes closed, everything you need during the course of the shift is at the ready at arm’s reach, your defenses are deployed. If you let your mise-en-place run down, get dirty and disorganized, you’ll quickly find yourself spinning in place and calling for backup. I worked with a chef who used to step behind the line to a dirty cook’s station in the middle of a rush to explain why the offending cook was falling behind. He’d press his palm down on the cutting board, which was littered with peppercorns, spattered sauce, bits of parsley, bread crumbs and the usual flotsam and jetsam that accumulates quickly on a station if not constantly wiped away with a moist side towel. “You see this?” he’d inquire, raising his palm so that the cook could see the bits of dirt and scraps sticking to his chef’s palm. “That’s what the inside of your head looks like now.”
— Anthony Bourdain, from Kitchen Confidential (Bourdain 2013).
This an annotated version of my DOOM Emacs configuration. The source files can be found on Github or Sourcehut.
Installation
The most basic installation of Doom Emacs consists of:
$ git clone --depth 1 https://github.com/doomemacs/doomemacs ~/.emacs.d
$ ~/.emacs.d/bin/doom install
After any configuration changes you should run the sync command with
$ ~/.emacs.d/bin/doom sync
Any upgrade to the doom Emacs packages can be done using the upgrade
command.
$ ~/.emacs.d/bin/doom upgrade
Languages
Python
virtualenv
In order to use Python’s virtualenv, the
virtualenvwrapper.el2 https://github.com/porterjamesj/virtualenvwrapper.el #### Black
formatter module is used. This is done by adding to
packages.el
(package! virtualenvwrapper)
The only configuration I use for this library is setting my virtualenv
root location in config.el
(use-package! virtualenvwrapper)
(after! virtualenvwrapper
(setq venv-location "~/.virtualenvs/")
)
From a Python project the virtual environment can be
selected by using M-x venv-workon.
To allow formatting of Python blocks in org-mode and
elsewhere, add python-black 3 https://github.com/emacs-vault/emacs-python-black to packages.el.
(package! python-black)
Then we configure it with
(use-package! python-black
:after python
:hook (python-mode . python-black-on-save-mode-enable-dwim))
We should install black-machiatto 4 https://github.com/wbolster/black-macchiato to allow formatting of partial
regions.
Go
The following modules must be enabled in init.el: - (go +lsp) in the
lang section - lsp in the tools section - snippets in the
editor section
gopls should be installed.
Templates
To enable support of Go templates, install the lang/web packages by
adding to init.el.
(web +html)
This will install the web-mode package5 https://web-mode.org/ To specify the sepcific
template engine as Go M-x web-mode-set-engine to go.
Running doom sync will finish the setup. ### Pikchr Support for
Pikchr6 https://pikchr.org/ is added via the pikchr-mode package. By
adding
(package! pikchr-mode)
It is necessary to install the pikchr binary according to the
instructions in Pikchr. That page also contains examples.
xonsh
I also use a basic mode7 https://github.com/seanfarley/xonsh-mode to support xonsh8 https://xon.sh/ scripts. The package can be installed with
;; packages.el
(package! xonsh-mode)
and invoked with
;; config.el
(use-package! xonsh-mode)
org-mode
org-agenda
To disable completed items to show up in agenda views, the following is
set in config.el
(setq org-agenda-skip-scheduled-if-done t)
(setq org-agenda-skip-deadline-if-done t)
Key bindings
For Doom Emacs we add some additional key-bindings to the org-mode
specifically. These bindings go under the local org leader key with
the u prefix (which in my case is ) SPC m u. They are -
SPC m u - a, archive an org-agenda item using
#org-archive-subtree-default - r, get a random note using
#org-randomnote
For more information on how to set doom Emacs keybings, check the elevant section.
Pretty bullets
The default Doom Emacs org-mode bullets are *. To get
“pretty” bullets you need to add the +pretty flag to init.el:
(org +pretty ) ; organize your plain life in plain text
Optionally, you can specify the bullet’s hierarchy glyphs with
(setq
org-superstar-headline-bullets-list '("⁖" "◉" "○" "✸" "✿")
)
UI
Resolution dependent fonts
I have to work with a variety of monitor resolutions, from a 720p pocket
book to a 2160p iMac. The fonts usually look tiny in my larger screen so
I’ve added support for resolution dependent font sizes in my
config.el.
For instance
(when (window-system) ;; only apply to GUI frames
;; Adjust font size dependent of the screen resolution
(when (> (x-display-pixel-width) 3000)
(setq doom-font (font-spec :family "Ubuntu Mono" :size 26 :weight 'regular)))
(when (< (x-display-pixel-width) 3000)
(setq doom-font (font-spec :family "Ubuntu Mono" :size 14 :weight 'regular)))
)
Would set a larger font size for monitors with a horizontal resolution higher than 3000 pixels.
Prettify symbols
Since Emacs 24.49 https://www.emacswiki.org/emacs/PrettySymbol there is a builtin prettify-symbols-mode. It can
be customized by changing prettify-symbols-alist. These strings will
be replace by our selection, typically an unicode symbol. In this
configuration we use the following:
(defun my/pretty-symbols ()
(setq prettify-symbols-alist
'(("#+begin_src python" . "🐍")
("#+begin_src elisp" . "λ")
("#+begin_src jupyter-python" . "🐍")
("#+end_src" . "―")
("#+results:" . "🔨")
("#+RESULTS:" . "🔨"))))
This will, for instance, replace the beginning of Python
org-babel~ blocks with the single symbol. To register the prettify
list with each mode we use
(add-hook 'org-mode-hook 'my/pretty-symbols)
Or we can register the prettify-symbols-mode as a global mode
(global-prettify-symbols-mode +1)
company
company is great, but it can get in the way when using on org-mode
buffers. To disable add the following:
(after! org
;; disable auto-complete in org-mode buffers
(remove-hook 'org-mode-hook #'auto-fill-mode)
;; disable company too
(setq company-global-modes '(not org-mode))
;; ...
)
Beacon
Beacon highlights the current cursor line after major movements.
Especially useful for HDPi screens. Add it on packages.el:
(package! beacon)
And enable the global minor-mode on config.el with:
;; global beacon minor-mode
(use-package! beacon)
(after! beacon (beacon-mode 1))
Focus
This mode relies on the Focus
package that dims regions not on … focus. Since the package is on
MELPA, it can be installed by adding to packages.el:
(package! focus)
Next, require it from config.el
(use-package! focus)
And call it by setting the mode with M-x focus-mode.
Navigation
Treemacs
treemacs10 https://github.com/Alexander-Miller/treemacs is a great file navigation explorer for Emacs. However,
since it has its own iternal concept of project, it needs an external
helper to be able to synchronise with other project management tools,
such as projectile.
To be able to synchronise treemacs and projectile the
treemacs-projectile module must be used. It can be activated using
(use-package treemacs-projectile
:after (treemacs projectile))
(after! (treemacs projectile)
(treemacs-project-follow-mode 1))
This guarantees that when moving to a buffer of a different projectile
project, the treemacs tree will reflect that.
Personally, I’m not a fan of doom Emacs’ and treemacs’ default
behaviour of use variable pitch fonts. If you want, for consistency, to
set treemacs to use a monospaced font, set the following on your
config.el:
(setq doom-themes-treemacs-enable-variable-pitch nil)
Opening on project
To open Treemacs automatically in Doom Emacs when you open a project, regardless of whether it’s recognized by Projectile or another project management system Doom integrates with, you can leverage Doom’s project detection mechanisms and hooks. Since SPC p p uses Doom’s project management system which is built on top of Projectile but also accommodates other forms of project recognition, you can write a function that checks if you’re in a recognized project directory at startup and opens Treemacs accordingly.
Doom Emacs doesn’t have a direct hook that fires after opening a project
with SPC p p (or +projectile/find-file), since this action
is more interactive and manual. However, you can achieve automatic
Treemacs opening on startup if you’re in a project directory by using
the doom-first-file-hook. This hook runs after the first buffer is
opened, which can be used to check if the opened buffer is part of a
recognized project.
Here’s how you can do it. Add a Custom Function**: Insert the
following Elisp code into your config.el:
(defun my/open-treemacs-in-project ()
"Automatically open Treemacs in a project."
(when (doom-project-root) ; Checks if the current buffer is in a Doom-recognized project
(treemacs))) ; Opens Treemacs
(add-hook 'doom-first-file-hook 'my/open-treemacs-in-project)
This function my/open-treemacs-in-project checks if the current buffer
belongs to a project (Doom’s doom-project-root will return non-nil if
so) and opens Treemacs if it does. By adding this function to
doom-first-file-hook, it ensures Treemacs opens automatically when you
start Doom Emacs in a project directory or open a file that is part of a
project.
Dirvish
Dirvish offers a suitable
replacement/enhancement for dired with features such as improved UI
and image preview. The only requirement for dirvish is the ls
alternative exa It is available from MELPA
which means you can add it to packages.el with
(package! dirvish)
and then enable it on config.el with
(use-package! dirvish)
Tools
vterm
An interesting talk on the advantages of using vterm as the default
Emacs terminal emulator can be found can found at EmacsConf 2021 “A
Tour of vterm”. To use vterm as
the Emacs shell, the respective section in init.el should be selected:
(doom!
:term
;;eshell ; the elisp shell that works everywhere
;;shell ; simple shell REPL for Emacs
;;term ; basic terminal emulator for Emacs
vterm ; the best terminal emulation in Emacs
)
We also need to install libvterm, with in macOS can be done with
brew install libvterm
and in Linux with
$ sudo apt-get install -y libvterm-dev # Ubuntu
$ sudo dnf -y install libvterm # Fedora
deadgrep
For full-text search, deadgrep11 https://github.com/Wilfred/deadgrep is used, which leverages
ripgrep. To install ripgrep
on Linux, run
$ sudo apt install ripgrep # Ubuntu
$ sudo dnf install ripgrep # Fedora
Defining key bindings
(map! :leader
(:prefix-map ("f" . "foo")
(:prefix ("b" . "bar")
:desc "Baz" "b" #'foo-bar-baz
:desc "Qux" "q" #'foo-bar-qux)))
This will define SPC-f-b-b
to invoke foo-bar-baz and
SPC-f-b-q to invoke
foo-bar-qux.
Dynamic modules
The best place to put dynamic modules in Doom Emacs is inside the actual
.doom.d folder. This allows to load modules from Doom’s “private dir”.
For instance, for a module called my_module and sub-directory named
modules we would create
mkdir ~/.doom.d/modules
and then add to config.el
(add-to-list 'load-path (expand-file-name "modules/my_module" doom-private-dir))
(def-package! my_module
:commands (mymodule-foo mymodule-bar))
Bourdain, Anthony. 2013. Kitchen Confidential. A&C Black.