This document is a work in progress 🚧
- About DOOM Emacs
- About this document
- Formalities
- Basic text manipulation
- Getting an outline
- Smerge
- Navigation
- Interfacing
- Versioning
- Running stuff
- Languages
- Applications
- Closing thoughts
DOOM Emacs is a several things.
It is an Emacs-lisp library, a set of functions and variables to help write configurations in a clear, readable, concise and modular way.
It is also a stock of pre-available configurations.
It is also a collection of executables to install it and update it.
It is not a fork of Emacs.
Configuring DOOM Emacs is done within a directory. Either it is ~/.doom.d
or
it is ~/.config/doom
. Or any other directory really, as long as the $DOOMDIR
environment variable is set to it.
The core file to have when using DOOM Emacs is init.el
. It contains the list
of DOOM modules that you want to enable. This file is kind of weird though
because it’s not meant to talk to Emacs but to DOOM. After changing it, you need
to run ~~/.emacs.d/bin/doom refresh~ (or ~~/.config/emacs/bin/doom~ I guess?)
If you have more stuff to tell Emacs, and at this point actually tell Emacs, you
put your config in config.el
(and maybe other files that you’d load from there
if you want.)
If anything needs to be autoloaded, though, it has to go in its own file:
autoloads.el
.
That’s a few different files when you’d think one would suffice, but doing it this way allows for a number of optimizations, so Emacs launches fast.
This document is written in Org.
It is where I explain my configuration.
It is also the configuration.
All code blocks present in this document are extracted (or “tangled”) into the
respective .el
files I mentioned earlier.
All I have to do is make
to regenerate all of the files from this Org
document.
As stated, this document tangles a few .el
files. More specifically the
following files:
;;; init.el -*- lexical-binding: t; -*-
;;; packages.el -*- lexical-binding: t; -*-
;;; config.el -*- lexical-binding: t; -*-
Now, because I am tangling init.el
, which should contain a single doom!
expression, in such a way that I can introduce its content when relevant, I have
to open this doom!
block, and then close it at the end of the document.
Because I don’t want to worry about the future regarding that, I don’t want the
code block containing the opening doom!
to refer to any module, and I don’t
want to close the block in a code block containing any module either. So, now
I’m going to open this doom!
block and get started with configuring my damn
editor.
; init.el
(doom!
Okay now let’s do this.
It’s always a good thing to introduce oneself at some point. If what I’m doing is telling emacs to do things, I really ought to tell it my name and how to contact me.
; config.el
(setq user-full-name "Clément Busschaert"
user-mail-address (concat "clement.busschaert" "@" "gmail.com"))
Actually these variables are used from times to times when using GPG or other things like that. You never know when packages will need to know who you are.
; init.el
:editor (evil +everywhere)
; init.el
:editor multiple-cursors
; init.el
:completion (company +childframe)
; init.el
:editor file-templates
; init.el
:editor (format +onsave)
; init.el
:editor rotate-text
; init.el
:editor snippets
; init.el
:emacs electric
; init.el
:tools rgb
iMenu-list.
Step one, get the package.
; packages.el
(package! imenu-list)
Step two, use the package.
; config.el
(use-package! imenu-list
:commands imenu-list-smart-toggle)
Step three, bind the command.
; config.el
(map! :map doom-leader-code-map
:desc "List code items" "l" #'imenu-list-smart-toggle)
; config.el
(map! :map doom-leader-git-map
:desc "SMerge" "m" #'+vc/smerge-hydra/body)
Sometimes you want to keep a buffer in place. Sometimes you want that one window to keep that one buffer open.
I often use this feature to keep the magit-status buffer open in my VC workspace, or to keep a “compilation window” around.
Doom doesn’t offer that by default, so I took a snippet I found in spacemacs’ code, and used that.
; config.el
;; from http://dfan.org/blog/2009/02/19/emacs-dedicated-windows/
(defun toggle-window-dedication ()
"Toggle dedication state of a window."
(interactive)
(let* ((window (selected-window))
(dedicated (window-dedicated-p window)))
(set-window-dedicated-p window (not dedicated))
(message "Window %sdedicated to %s"
(if dedicated "no longer " "")
(buffer-name))))
Now we map that in the window keymap.
; config.el
(map! :map evil-window-map
:desc "Set dedication" "t" #'toggle-window-dedication)
; init.el
:ui (window-select +switch-window)
; init.el
:ui workspaces
; config.el
(map! :leader
:desc "IGNORED" "`" nil
:desc "Switch to last buffer" "TAB" #'evil-switch-to-windows-last-buffer
:desc "layouts" "l" doom-leader-workspace-map)
; init.el
:editor fold
; init.el
:tools (lookup +docsets)
; init.el
:emacs dired
; init.el
:emacs ibuffer
Doom can look like vanilla emacs if you want to look like a very intelligent godlike being able to understand how to use emacs without help. I’m not that arrogant. I’m a hip kid, I want a slick design and a cool theme and the best font ever.
There are modules that make a lot of the heavy lifting in regards to visuals:
; init.el
:ui doom
:ui modeline
I think their names are quite evocative of what they configure, but for the kid
in the last row with the yellow cap: doom
enables doom-themes and modeline
configures doom-modeline.
These modules do a good job by default, but there are a few things that need to be tweaked for me to have the bestest editing visual experience ever.
We want to configure two fonts: the monospace one, and the variable pitch one. I want both of them to be the same: the bestest font ever.
; config.el
(setq doom-font (font-spec :family "Comic Code" :size 13)
doom-variable-pitch-font (font-spec :family "Comic Code"))
An additional module is available to support unicode characters like ‘恋犬’ or ‘ਕਤੂਰੇ’, which sometimes you do want to be able to see clearly.
; init.el
:ui unicode
The theme is just that one single variable doom-theme
. I like Nova. Let’s use
Nova.
; config.el
(setq doom-theme 'doom-nova)
Which-key has this thing that describes available keybinds. It auto-opens a menu
when you press a prefix key. For example, you press SPC
and then you have this
popup listing all the keys available as a follower to SPC
.
; config.el
(setq which-key-idle-delay 0.5)
I like them, okay. I don’t know why. It just feels right.
; config.el
(setq display-line-numbers-type 'relative)
; init.el
:completion (ivy +childframe +fuzzy +icons)
; init.el
:ui doom-dashboard
; init.el
:ui hydra
; init.el
:ui doom-quit
; init.el
:ui fill-column
; init.el
:ui hl-todo
; init.el
:ui indent-guides
; init.el
:ui nav-flash
; init.el
:ui ophints
; init.el
:ui pretty-code
; init.el
:ui vc-gutter
; init.el
:ui vi-tilde-fringe
; init.el
:ui zen
; init.el
:emacs vc
; init.el
:tools magit
; init.el
:tools eval
; init.el
:checkers syntax
; init.el
:tools make
Can’t fully use emacs to its full potential if you can’t edit emacs-lisp like a pro.
; init.el
:lang emacs-lisp
I like OCaml a lot.
; init.el
:lang ocaml
Oh boy if you don’t know this, look it up!
; config.el
(after! tuareg
(add-hook! before-save #'ocamlformat-before-save)
(add-hook! tuareg-mode
(let ((ext (file-name-extension buffer-file-name t)))
(cond ((equal ext ".eliom")
(setq-local ocamlformat-file-kind 'implementation))
((equal ext ".eliomi")
(setq-local ocamlformat-file-kind 'interface))))))
; init.el
:lang javascript
; init.el
:lang web
; init.el
:lang python
; init.el
:lang rust
; init.el
:lang sh
; init.el
:lang data
; init.el
:lang latex
; init.el
:lang markdown
; init.el
:lang org
; init.el
:app calendar
; init.el
:config (default +bindings +smartparens)
)