dwt1--dotfiles/.emacs.d/docs/getting_started.org

1427 lines
53 KiB
Org Mode

#+TITLE: Getting Started Guide
#+STARTUP: nofold
GNU Emacs is one grand ol' adventure, let alone Doom Emacs. Before you start
you'll need to set up Emacs, Doom, and its packages, then learn how to take care
of your new puppy slash operating system. This guide will walk you through
installing, using, configuring and troubleshooting Doom Emacs.
#+begin_quote
If you feel like we've missed something, [[https://discord.gg/qvGgnVx][join us on our Discord server]] and let
us know!
#+end_quote
* Table of Contents :TOC_4:
- [[#install][Install]]
- [[#emacs--dependencies][Emacs & dependencies]]
- [[#on-linux][On Linux]]
- [[#arch-linux][Arch Linux:]]
- [[#ubuntu][Ubuntu:]]
- [[#fedora][Fedora:]]
- [[#nixos][NixOS]]
- [[#opensuse][openSUSE]]
- [[#on-macos][On macOS]]
- [[#with-homebrew][With Homebrew]]
- [[#with-macports][With MacPorts]]
- [[#on-windows][On Windows]]
- [[#chocolatey--scoop][chocolatey / scoop]]
- [[#wsl][WSL]]
- [[#wsl2][WSL2]]
- [[#doom-emacs][Doom Emacs]]
- [[#the-bindoom-utility][The ~bin/doom~ utility]]
- [[#install-doom-manually][Install Doom Manually]]
- [[#install-doom-alongside-other-configs-with-chemacs][Install Doom alongside other configs (with Chemacs)]]
- [[#externalsystem-dependencies][External/system dependencies]]
- [[#update--rollback][Update & Rollback]]
- [[#rollback][Rollback]]
- [[#updowngrading-emacs][Up/Downgrading Emacs]]
- [[#migrate][Migrate]]
- [[#from-vanilla-emacs][From vanilla Emacs]]
- [[#from-spacemacs][From Spacemacs]]
- [[#configure][Configure]]
- [[#modules][Modules]]
- [[#package-management][Package management]]
- [[#installing-packages][Installing packages]]
- [[#installing-packages-from-external-sources][Installing packages from external sources]]
- [[#pinning-packages-to-specific-commits][Pinning packages to specific commits]]
- [[#disabling-packages][Disabling packages]]
- [[#changing-a-recipe-for-a-included-package][Changing a recipe for a included package]]
- [[#usingloading-local-packages][Using/loading local packages]]
- [[#adjust-your-load-path][Adjust your ~load-path~]]
- [[#local-repo][:local-repo]]
- [[#configuring-doom][Configuring Doom]]
- [[#configuring-packages][Configuring packages]]
- [[#reloading-your-config][Reloading your config]]
- [[#binding-keys][Binding keys]]
- [[#writing-your-own-modules][Writing your own modules]]
- [[#load-order][Load order]]
- [[#location][Location]]
- [[#file-structure][File structure]]
- [[#initel][=init.el=]]
- [[#configel][=config.el=]]
- [[#packagesel][=packages.el=]]
- [[#autoloadel-or-autoloadel][=autoload/*.el= OR =autoload.el=]]
- [[#doctorel][=doctor.el=]]
- [[#additional-files][Additional files]]
- [[#flags][Flags]]
- [[#module-cookies][Module cookies]]
- [[#autodefs][Autodefs]]
- [[#common-mistakes-when-configuring-doom-emacs][Common mistakes when configuring Doom Emacs]]
- [[#packages-are-eagerly-loaded][Packages are eagerly loaded]]
- [[#manual-package-management][Manual package management]]
- [[#using-org-babel-do-load-languages-to-load-your-babel-packages][Using ~org-babel-do-load-languages~ to load your babel packages]]
- [[#using-delete-trailing-whitespaces-or-whitespace-cleanup-to-manage-leftover-whitespace][Using ~delete-trailing-whitespaces~ or ~whitespace-cleanup~ to manage leftover whitespace]]
- [[#troubleshoot][Troubleshoot]]
- [[#looking-up-documentation-and-state-from-within-emacs][Looking up documentation and state from within Emacs]]
- [[#variables-functions-faces-etc][Variables, functions, faces, etc.]]
- [[#for-doom-modules-packages-autodefs-etc][For Doom Modules, packages, autodefs, etc.]]
- [[#how-to-extract-a-backtrace-from-an-error][How to extract a backtrace from an error]]
- [[#enabling-debug-on-error][Enabling ~debug-on-error~]]
- [[#a-backtrace-from-bindoom][A backtrace from ~bin/doom~]]
- [[#evaluating-elisp-on-the-fly][Evaluating Elisp on-the-fly]]
- [[#how-to-determine-the-origin-of-a-bug][How to determine the origin of a bug]]
- [[#testing-in-dooms-sandbox][Testing in Doom's sandbox]]
- [[#opening-the-sandbox][Opening the sandbox]]
- [[#launching-the-sandbox][Launching the sandbox]]
- [[#testing-packages-in-the-sandbox][Testing packages in the sandbox]]
- [[#bisecting-your-private-config][Bisecting your private config]]
- [[#bisecting-doom-emacs][Bisecting Doom Emacs]]
* Install
This is what you'll have installed by the end of this guide:
+ *Required:*
- Git 2.23+
- Emacs 26.3+
- [[https://github.com/BurntSushi/ripgrep][ripgrep]] 11.0+
- GNU Find
+ *Optional:*
- [[https://github.com/sharkdp/fd][fd]] 7.3.0+ -- improves performance for many file indexing commands
- GNU ~tar~ -- needed to read compressed elisp files and install packages with
package.el
- GNU ~ls~ -- to overcome limitations with BSD ls on MacOS or BSD systems
- ~gcc~ or ~clang~ (preferred) -- needed to build some module dependencies
like irony-server, emacsqlite for magit, epdfinfo for pdf-tools or vterm
These packages ought to be available through the package managers of most Linux
distributions, or homebrew & macports on macOS, or scoop/chocolatey on Windows.
The following sections will go over how to install them, beginning with Emacs.
#+BEGIN_QUOTE
If any of these install instructions are outdated, or instructions for your OS
is missing, [[https://github.com/hlissner/doom-emacs/issues/new/choose][let us know]] (or correct it yourself; pull requests are welcome).
#+END_QUOTE
** Emacs & dependencies
*** On Linux
In the unusual case that Emacs is unavailable through your package manager,
you'll have to [[https://www.gnu.org/software/emacs/manual/html_node/efaq/Installing-Emacs.html][build it from source]]. Otherwise:
**** Arch Linux:
#+BEGIN_SRC bash
# required dependencies
pacman -S git emacs ripgrep
# optional dependencies
pacman -S clang tar fd
#+END_SRC
The above installs Emacs 26.3 (at the time of writing). If you'd prefer Emacs
27/28 (HEAD), it is available through the AUR in the [[https://aur.archlinux.org/packages/emacs-git/][emacs-git]] package.
**** Ubuntu:
#+BEGIN_SRC bash
# required dependencies
apt-get install git ripgrep
# optional dependencies
apt-get install tar fd-find clang
#+END_SRC
Only 25.3 is available on Ubuntu 18.04 (and 24.3 on Ubuntu 14 or 16), which Doom
does not support. Extra steps are necessary to acquire 26.3:
#+BEGIN_SRC bash
add-apt-repository ppa:kelleyk/emacs
apt-get update
apt-get install emacs26
#+END_SRC
**** Fedora:
#+BEGIN_SRC bash
# required dependencies
sudo dnf install emacs git ripgrep
# optional dependencies
sudo dnf install tar fd-find clang multimarkdown ShellCheck
#+END_SRC
**** NixOS
On NixOS Emacs 26.3 can be installed via ~nix-env -Ai nixos.emacs~, or
permanently with the following added to ~etc/nixos/configuration.nix~:
#+BEGIN_SRC nix
environment.systemPackages = with pkgs; [
# required dependencies
git
emacs # Emacs 26.3
ripgrep
# optional dependencies
coreutils # basic GNU utilities
fd
clang
];
#+END_SRC
To acquire Emacs 27/28+, look into [[https://github.com/nix-community/emacs-overlay/issues][nix-community/emacs-overlay]], which can be
quickly integrated into your configuration.nix with:
#+BEGIN_SRC nix
nixpkgs.overlays = [
(import (builtins.fetchTarball https://github.com/nix-community/emacs-overlay/archive/master.tar.gz))
];
environment.systemPackages = with pkgs; [
emacsGit
];
#+END_SRC
**** openSUSE
***** Emacs 26.3
Check the [[https://software.opensuse.org/download.html?project=editors&package=emacs][package list]] and download the package for your distribution or manually install via zypper.
Example: installing on openSUSE Leap 15.1 (requires root):
#+BEGIN_SRC bash
zypper addrepo https://download.opensuse.org/repositories/editors/openSUSE_Leap_15.1/editors.repo
zypper refresh
zypper install emacs
#+END_SRC
If you already have an older version of Emacs installed, you will be prompted to install the update candidate (Emacs 26.3).
***** ripgrep
Tumbleweed has ripgrep 11.0.2, which can be downloaded from [[https://software.opensuse.org/download/package?package=ripgrep&project=openSUSE%3AFactory][the package list]] or installed manually (requires root):
#+BEGIN_SRC bash
zypper addrepo https://download.opensuse.org/repositories/openSUSE:Factory/standard/openSUSE:Factory.repo
zypper refresh
zypper install ripgrep
#+END_SRC
On Leap 15.1 and 15.2 only ripgrep 0.8.1 is officially available. You will need to install Rust and build ripgrep from source; you can download Rust [[https://software.opensuse.org/package/rust][from the package list]] or install it manually via zypper.
Example: installing on openSUSE Leap 15.1 (standard, requires root):
#+BEGIN_SRC bash
zypper addrepo https://download.opensuse.org/repositories/openSUSE:Leap:15.1:Update/standard/openSUSE:Leap:15.1:Update.repo
zypper refresh
zypper install rust
#+END_SRC
See the [[https://github.com/BurntSushi/ripgrep#building][ripgrep documentation]] for instructions on building from source.
*** On macOS
MacOS users have many options for installing Emacs, but not all of them are well
suited to Doom. Before we get to that you'll need either the Homebrew or
MacPorts package manager installed (you only need one):
+ [[http://brew.sh/][How to install Homebrew]]
+ [[https://www.macports.org/install.php][How to install MacPorts]]
**** With Homebrew
First, Doom's dependencies:
#+BEGIN_SRC bash
# required dependencies
brew install git ripgrep
# optional dependencies
brew install coreutils fd
# Installs clang
xcode-select --install
#+END_SRC
For Emacs itself, these three formulas are the best options, ordered from most
to least recommended for Doom (based on compatibility).
- [[https://github.com/d12frosted/homebrew-emacs-plus][emacs-plus]]:
#+BEGIN_SRC bash
brew tap d12frosted/emacs-plus
brew install emacs-plus
ln -s /usr/local/opt/emacs-plus/Emacs.app /Applications/Emacs.app
#+END_SRC
- [[https://bitbucket.org/mituharu/emacs-mac/overview][emacs-mac]] is another acceptable option. It offers slightly better integration
with macOS, native emojis and better childframe support. However, at the time
of writing, it [[https://github.com/railwaycat/homebrew-emacsmacport/issues/52][lacks multi-tty support]] (which impacts daemon usage):
#+BEGIN_SRC bash
brew tap railwaycat/emacsmacport
brew install emacs-mac --with-modules
ln -s /usr/local/opt/emacs-mac/Emacs.app /Applications/Emacs.app
#+END_SRC
- [[https://formulae.brew.sh/formula/emacs][emacs]] is another acceptable option, **but does not provide a Emacs.app**:
#+BEGIN_SRC bash
brew install emacs
#+END_SRC
***** Where *not* to install Emacs from
These builds/forks have known compatibility issues with Doom and are *very
likely* to cause issues later on. Do not use them:
+ emacsformacosx.com
+ ~brew cask install emacs~ (installs from emacsformacosx.com)
+ AquaMacs
+ XEmacs
**** With MacPorts
There are four ports (at time of writing) available through MacPorts, and they
are all acceptable options:
+ [[https://ports.macports.org/port/emacs/summary][emacs]] (26.3) and [[https://ports.macports.org/port/emacs-devel/summary][emacs-devel]] (27) -- Installs terminal-only Emacs
+ [[https://ports.macports.org/port/emacs-app/summary][emacs-app]] (26.3), [[https://ports.macports.org/port/emacs-app-devel/summary][emacs-app-devel]] (27) -- Installs GUI Emacs
+ [[https://ports.macports.org/port/emacs-mac-app/summary][emacs-mac-app]] (26.3) -- the [[https://bitbucket.org/mituharu/emacs-mac][Mitsuharu Yamamoto mac port]]
Some of these ports do not add an =emacs= binary to your ~PATH~, which is
necessary for Doom's installation process. You'll have to do so yourself by
adding this to your shell config:
#+BEGIN_SRC sh
# Add this to ~/.zshrc or ~/.bash_profile
export PATH="/Applications/MacPorts/Emacs.app/Contents/MacOS:$PATH"
#+END_SRC
Or by creating a shim script at ~/usr/local/bin/emacs~:
#+BEGIN_SRC
#!/bin/sh
/Applications/MacPorts/Emacs.app/Contents/MacOS/Emacs "$@"
#+END_SRC
*** On Windows
*Support for Windows is immature* so your mileage there will vary. Some have
reported success using Doom with WSL or WSL2. The maintainer has only (lightly)
tested installing Doom with chocolatey through [[https://gitforwindows.org/][git-bash]].
#+BEGIN_QUOTE
If you manage to get Doom running on Windows and found this guide wasn't enough
or could be improved, please help us expand this section!
#+END_QUOTE
**** [[https://chocolatey.org/][chocolatey]] / scoop
Chocolatey is the simplest to get Doom up and running with:
#+BEGIN_SRC sh
choco install git emacs ripgrep fd llvm
#+END_SRC
#+begin_quote
Scoop is also a viable way of installing Emacs. However, because Emacs is a GUI
application, it is relegated to the 'extras' Scoop bucket and that will need to
be enabled.
#+end_quote
#+BEGIN_SRC sh
scoop bucket add extras
scoop install git emacs ripgrep fd llvm
#+END_SRC
You will need [[https://mywindowshub.com/how-to-edit-system-environment-variables-for-a-user-in-windows-10/][the ~HOME~ system variable]] set to =C:\Users\USERNAME\=, otherwise
Emacs will treat =C:\Users\USERNAME\AppData\Roaming= as your ~HOME~, which
causes issues.
It's also a good idea to add =C:\Users\USERNAME\.emacs.d\bin= to your ~PATH~.
#+begin_quote
A pre-existing PATH variable should already exist among your system variables.
It contains a string of file paths separated by colons; ~pathA:pathB:pathC~.
Prepend the path to bin/doom to that string:
~C:\Users\username\.emacs.d\bin:pathA:pathB:pathC~
#+end_quote
**** TODO WSL
**** TODO WSL2
** Doom Emacs
With Emacs and Doom's dependencies installed, next is to install Doom Emacs
itself:
#+BEGIN_SRC bash
git clone https://github.com/hlissner/doom-emacs ~/.emacs.d
~/.emacs.d/bin/doom install
#+END_SRC
=doom install= will set up your =DOOMDIR= at =~/.doom.d= (if it doesn't already
exist) and will work you through the first-time setup of Doom Emacs.
#+BEGIN_QUOTE
If you'd like a more technical break down of ~doom install~, it's been
translated into shell commands below, in the "Install Doom Manually" section.
#+END_QUOTE
*** The ~bin/doom~ utility
This utility is your new best friend. It won't spot you a beer, but it'll
shoulder much of the work associated with managing and maintaining your Doom
Emacs configuration, and then some. Not least of which is installation of and
updating Doom and your installed packages.
It exposes a variety of commands. ~bin/doom help~ will list them all, but here
is a summary of the most important ones:
+ ~bin/doom sync~: This synchronizes your config with Doom Emacs. It ensures
that needed packages are installed, orphaned packages are removed and
necessary metadata correctly generated. Run this whenever you modify your
~doom!~ block or =packages.el= file.
+ ~bin/doom upgrade~: Updates Doom Emacs (if available) and all its packages.
+ ~bin/doom env~: (Re)generates an "envvar file", which is a snapshot of your
shell environment that Doom loads at startup. If your app launcher or OS
launches Emacs in the wrong environment you will need this. **This is required
for GUI Emacs users on MacOS.**
+ ~bin/doom doctor~: If Doom misbehaves, the doc will diagnose common issues
with your installation, system and environment.
+ ~bin/doom purge~: Over time, the repositories for Doom's plugins will
accumulate. Run this command from time to time to delete old, orphaned
packages, and with the ~-g~ switch to compact existing package repos.
Use ~bin/doom help~ to see an overview of the available commands that =bin/doom=
provides, and ~bin/doom help COMMAND~ to display documentation for a particular
~COMMAND~.
#+begin_quote
I recommend you add =~/.emacs.d/bin= to your ~PATH~ so you can call =doom=
directly and from anywhere. Accomplish this by adding this to your .bashrc or
.zshrc file: ~export PATH=~/.emacs.d/bin:$PATH~
#+end_quote
*** Install Doom Manually
If you'd rather install Doom yourself, instead of rely on the magic of =bin/doom
install=, here is its equivalent in bash shell commands (assuming
=hlissner/doom-emacs= has been cloned to =~/.emacs.d=):
#+BEGIN_SRC bash
# So we don't have to write ~/.emacs.d/bin/doom every time
PATH="$HOME/.emacs.d/bin:$PATH"
# Create a directory for our private config
mkdir ~/.doom.d # or ~/.config/doom
# The init.example.el file contains an example doom! call, which tells Doom what
# modules to load and in what order.
cp ~/.emacs.d/init.example.el ~/.doom.d/init.el
cp ~/.emacs.d/core/templates/config.example.el ~/.doom.d/config.el
cp ~/.emacs.d/core/templates/packages.example.el ~/.doom.d/packages.el
# If your ISP or proxy doesn't allow you to install from
# raw.githubusercontent.com, then you'll have to install straight (our package
# manager) manually:
mkdir -p ~/.emacs.d/.local/straight/repos
git clone -b develop https://github.com/raxod502/straight.el ~/.emacs.d/.local/straight/repos/straight.el
# You might want to edit ~/.doom.d/init.el here and make sure you only have the
# modules you want enabled.
# Then synchronize Doom with your config:
doom sync
# If you know Emacs won't be launched from your shell environment (e.g. you're
# on macOS or use an app launcher that doesn't launch programs with the correct
# shell) then create an envvar file to ensure Doom correctly inherits your shell
# environment.
#
# If you don't know whether you need this or not, there's no harm in doing it
# anyway. `doom install` will have prompted you to generate one. If you
# responded no, you can generate it later with the following command:
doom env
# Lastly, install the icon fonts Doom uses:
emacs --batch -f all-the-icons-install-fonts
#+END_SRC
To understand the purpose of the =~/.doom.d= directory and =~/.doom.d/init.el=
file, see the [[#configure][Configure]] section further below.
*** Install Doom alongside other configs (with Chemacs)
[[https://github.com/plexus/chemacs][Chemacs]] is a bootloader for Emacs. It allows you to switch between multiple
Emacs configurations. Here is a quick guide for setting it up with Doom Emacs as
the default config:
1. First, install Doom somewhere:
#+BEGIN_SRC sh :eval no
git clone https://github.com/hlissner/doom-emacs ~/doom-emacs
~/doom-emacs/bin/doom install
#+END_SRC
2. Download [[https://raw.githubusercontent.com/plexus/chemacs/master/.emacs][the Chemacs' startup script]] to =~/.emacs=:
#+BEGIN_SRC bash :eval no
wget -O ~/.emacs https://raw.githubusercontent.com/plexus/chemacs/master/.emacs
#+END_SRC
#+begin_quote
*WARNING:* the =~/.emacs.d= directory must not exist for this to work.
#+end_quote
3. Create =~/.emacs-profiles.el= with a list of your Emacs profiles. This file
is structured like a =.dir-locals.el= file. Here is an example with Doom (as
the default), Spacemacs, and Prelude:
#+BEGIN_SRC emacs-lisp :eval no
(("default" . ((user-emacs-directory . "~/doom-emacs")))
("spacemacs" . ((user-emacs-directory . "~/spacemacs")))
("prelude" . ((user-emacs-directory . "~/prelude"))))
#+END_SRC
To start Emacs with a specific config, use the =--with-profile= option:
#+BEGIN_SRC bash
emacs --with-profile spacemacs
#+END_SRC
If no profile is specified, the =default= profile is used.
** External/system dependencies
Doom is comprised of modules which provide most of its features, including
language support and integration with external tools. Many of them have external
dependencies that you must install yourself. You'll find what a module needs and
how to install them in that module's README.org file or by running ~bin/doom
doctor~.
#+begin_quote
Use ~M-x doom/help-modules~ (bound to =SPC h d m= or =C-h d m=) to jump to a
module's documentation from within Doom, otherwise, place your cursor on a
module in your ~doom!~ block (in =~/.doom.d/init.el=) and press =K= to jump to
its documentation (or =gd= to jump to its source code). =C-c g k= and =C-c g d=
for non-evil users, respectively.
Otherwise, check out the [[file:modules.org][Module Index]].
Keep in mind that documentation is an ongoing effort. Some modules may not have
README.org files yet.
#+end_quote
* Update & Rollback
Doom is an active project and many of its 300+ packages are in active
development as well. It is wise to occasionally update. Doom strives to make
this as painless a process as possible.
The =bin/doom= script provides one simple command for upgrading Doom and your
packages:
#+BEGIN_SRC bash :eval no
doom upgrade # or 'doom up'
#+END_SRC
If you want to update Doom manually, ~doom upgrade~ is equivalent to:
#+BEGIN_SRC bash
cd ~/.emacs.d
git pull # updates Doom
doom clean # Ensure your config isn't byte-compiled
doom sync # synchronizes your config with Doom Emacs
doom update # updates installed packages
#+END_SRC
To upgrade only your packages (and not Doom itself):
#+BEGIN_SRC bash
doom upgrade --packages
#+END_SRC
#+begin_quote
To minimize issues while upgrading, avoid modifying Doom's source files. All
your customization should be kept in your =DOOMDIR= (e.g. =~/.doom.d=). Read the
[[#Configure][Configure]] section for more on configuring Doom.
#+end_quote
** TODO Rollback
The =bin/doom= script doesn't currently offer rollback support for Doom or its
packages (yet).
** Up/Downgrading Emacs
*Important: you may encounter errors after up/downgrading Emacs.* Emacs bytecode
is generally not forward compatible. You will have to recompile or reinstall
your packages to fix this, i.e.
+ ~doom build~, to rebuild all your installed packages,
+ Or delete =~/.emacs.d/.local= then ~doom sync~ to reinstall them
* TODO Migrate
If you're here from another Emacs distribution (or your own), here are a few
things to be aware of while you convert your old config to Doom:
+ Doom does not use =package.el= to manage its packages, but ~use-package~ does!
You will see errors if you have ~:ensure ...~ properties in your ~use-package~
blocks. Remove these and, instead, add ~package!~ declarations to =~/.doom.d/packages.el= to install your packages.
See [[#package-management]["Package Management"]], earlier in this guide.
(This section is incomplete)
** TODO From vanilla Emacs
#+begin_quote
Have you migrated from your own config? Help me flesh out this section by
letting me know what kind of hurdles you faced in doing so. You'll find me [[https://discord.gg/qvGgnVx][on
our Discord server]].
#+end_quote
** TODO From Spacemacs
#+begin_quote
Have you migrated from Spacemacs? Help me flesh out this section by letting me
know what kind of hurdles you faced in doing so. You'll find me [[https://discord.gg/qvGgnVx][on our Discord
server]].
#+end_quote
* Configure
Doom looks for your private configuration in:
1. =$XDG_CONFIG_HOME/doom=
2. or =~/.doom.d=
This directory is referred to as your =DOOMDIR=.
#+begin_quote
You can override the location of your =DOOMDIR= by changing the environment
variable of the same name. Symlinks will work as well.
#+end_quote
~doom install~ will deploy three files to your =DOOMDIR=:
+ init.el :: Where you'll find your ~doom!~ block, which controls what Doom
modules are enabled and in what order they will be loaded.
This file is evaluated early in the startup process, before any other module
has loaded.
+ config.el :: Where 99.99% of your private configuration should go. Anything
put here will run /after/ all other modules have loaded.
+ packages.el :: Where you declare what packages to install and where from.
#+begin_quote
Note: do not use ~M-x customize~ or the customize API in general. Doom is
designed to be configured programmatically from your config.el, which can
conflict with Customize's way of writing variables to ~custom-file~.
Doom provides the ~setq!~ macro for triggering ~defcustom~ setters.
#+end_quote
** Modules
Doom consists of around 130 modules. A Doom module is a bundle of packages,
configuration and commands, organized into a unit that can be enabled or
disabled by adding or removing them from your ~doom!~ block (found in
=$DOOMDIR/init.el=).
#+begin_quote
If =$DOOMDIR/init.el= doesn't exist, you haven't installed Doom yet. See [[#install][the
"Install" section]] above.
#+end_quote
Your ~doom!~ block will look something like this:
#+BEGIN_SRC emacs-lisp
;; To comment something out, you insert at least one semicolon before it. The
;; Emacs Lisp interpreter will ignore whatever follows.
(doom! :lang
python ; this module is not commented, therefore enabled
;;javascript ; this module is commented out, therefore disabled
;;lua ; this module is disabled
ruby ; this module is enabled
php) ; this module is enabled
#+END_SRC
It controls what modules are enabled and in what order they are loaded. Some
modules have *optional features* that can be enabled by passing them flags,
denoted by a plus prefix:
#+BEGIN_SRC emacs-lisp
(doom! :completion
(company +auto)
:lang
(csharp +unity)
(org +brain +dragndrop +gnuplot +hugo +jupyter)
(sh +fish))
#+END_SRC
Different modules support different flags. Flags that a module doesn't recognize
will be silently ignored. You'll find a comprehensive list of available modules
and their supported flags summarized in [[file:index.org::*Module list][the Module Index]].
#+begin_quote
*IMPORTANT:* don't forget to run =bin/doom sync= after changing your ~doom!~
block, then restart Emacs for the changes to take effect.
#+end_quote
#+begin_quote
Run ~doom doctor~ to determine if there are any issues with your ~doom!~ block,
such as duplicate or misspelled modules.
#+end_quote
** Package management
**Doom Emacs does not use package.el** (the package manager built into Emacs).
Instead, it uses its own declarative package manager built on top of [[https://github.com/raxod502/straight.el][Straight]].
#+begin_quote
If you are coming from another Emacs distro (or vanilla Emacs), be wary of the
~:ensure~ property in ~use-package~ blocks, because it will attempt (and fail)
to install packages through package.el.
#+end_quote
Packages are declared in ~packages.el~ files located in Doom's modules. This
applies to your ~DOOMDIR~ as well, which is considered a module. You can install
your own packages in =~/.doom.d/packages.el=.
#+begin_quote
If a package is installed without an accompanying ~package!~ declaration (e.g.
with ~M-x package-install~ or ~M-x straight-use-package~), it will be
uninstalled the next time you run ~bin/doom sync~ or ~bin/doom purge~.
#+end_quote
*** Installing packages
To install a package, add a ~package!~ declaration for it to
=DOOMDIR/packages.el=:
#+BEGIN_SRC emacs-lisp
;; Install a package named "example" from ELPA or MELPA
(package! example)
;; Or tell Doom to not manage a particular package at all.
(package! example :ignore t)
#+END_SRC
~package!~ will return non-nil if the package is cleared for install and hasn't
been disabled elsewhere. Use this fact to chain package dependencies together.
e.g.
#+BEGIN_SRC elisp
(when (package! example)
(package! plugin-that-example-depends-on))
#+END_SRC
*** Installing packages from external sources
To install a package straight from an external source (like github, gitlab,
etc), you'll need to specify a [[https://github.com/raxod502/straight.el#the-recipe-format][MELPA-style straight recipe]]:
Here are a few examples:
#+BEGIN_SRC elisp
;; Install it directly from a github repository. For this to work, the package
;; must have an appropriate PACKAGENAME.el file which must contain at least a
;; Package-Version or Version line in its header.
(package! example
:recipe (:host github :repo "username/my-example-fork"))
;; If the source files for a package are in a subdirectory in said repo, use
;; `:files' to target them.
(package! example :recipe
(:host github
:repo "username/my-example-fork"
:files ("*.el" "src/lisp/*.el")))
;; To grab a particular branch or tag:
(package! example :recipe
(:host gitlab
:repo "username/my-example-fork"
:branch "develop"))
;; If a package has a default recipe on MELPA or emacsmirror, you may omit
;; keywords and the recipe will inherit the rest of the recipe from their
;; original.
(package! example :recipe (:branch "develop"))
;; If the repo pulls in many unneeded submodules, you can disable recursive cloning
(package! example :recipe (:nonrecursive t))
;; A package can be installed straight from a git repo by setting :host to nil:
(package! example
:recipe (:host nil :repo "https://some/git/repo"))
#+END_SRC
The specification for the ~package!~ macro's ~:recipe~ is laid out [[https://github.com/raxod502/straight.el#the-recipe-format][in
Straight.el's README]].
#+begin_quote
*IMPORTANT:* Run ~bin/doom sync~ whenever you modify packages.el files to
ensure your changes take effect.
#+end_quote
*** Pinning packages to specific commits
All of Doom's packages are pinned by default. A pinned package is a package
locked to a specific commit, like so:
#+BEGIN_SRC elisp
(package! evil :pin "e00626d9fd")
#+END_SRC
To unpin a package, use the ~unpin!~ macro:
#+BEGIN_SRC elisp
(unpin! evil)
;; It can be used to unpin multiple packages at once
(unpin! evil helm org-mode)
;; Or to unpin all packages in modules
(unpin! (:lang python ruby rust) (:tools docker))
;; Or to unpin an entire category of modules
(unpin! :completion :lang :tools)
;; This will work too, if you prefer the syntax, but it provides no concise
;; syntax for unpinning multiple packages:
(package! helm :pin nil)
#+END_SRC
Though it is *highly* discouraged, you may unpin all packages and make Doom
Emacs rolling release:
#+BEGIN_SRC elisp
(unpin! t)
#+END_SRC
#+begin_quote
Unpinning all packages is discouraged because Doom's modules are designed
against the pinned versions of its packages. More volatile packages (like
lsp-mode, ein and org) change rapidly, and are likely to cause breakages if
unpinned.
Instead, it's a better idea to selectively unpin packages, or repin them to the
exact commit you want.
#+end_quote
*** Disabling packages
The ~package!~ macro possesses a ~:disable~ property:
#+BEGIN_SRC emacs-lisp
(package! irony :disable t)
(package! rtags :disable t)
#+END_SRC
Once a package is disabled, ~use-package!~ and ~after!~ blocks for it will be
ignored, and the package is removed the next time you run ~bin/doom sync~. Use
this to disable Doom's packages that you don't want or need.
There is also the ~disable-packages!~ macro for conveniently disabling multiple
packages:
#+BEGIN_SRC elisp
(disable-packages! irony rtags)
#+END_SRC
#+begin_quote
*IMPORTANT:* Run ~bin/doom sync~ whenever you modify packages.el files to
ensure your changes take effect.
#+end_quote
*** Changing a recipe for a included package
If a Doom module installs package X from one place, but you'd like to install it
from another (say, a superior fork), add a ~package!~ declaration for it in your
=DOOMDIR/packages.el=. Your private declarations always have precedence over
modules (even your own).
#+BEGIN_SRC elisp
;; in modules/editor/evil/packages.el
(package! evil) ; installs from MELPA
;; in DOOMDIR/packages.el
(package! evil :recipe (:host github :repo "username/my-evil-fork"))
#+END_SRC
To install a package only if a built-in package doesn't exist, use ~:built-in
'prefer~:
#+BEGIN_SRC elisp
(package! so-long :built-in 'prefer)
#+END_SRC
#+begin_quote
*IMPORTANT:* Run ~bin/doom sync~ whenever you modify packages.el files to
ensure your changes take effect.
#+end_quote
*** Using/loading local packages
Say you have a local elisp package you want to install. You have two options:
**** Adjust your ~load-path~
Emacs searches for packages in your ~load-path~. Add the path to your package
and Emacs will find it when it tries to load it. e.g.
#+BEGIN_SRC elisp
(add-load-path! "lisp/package")
;; or
(use-package my-package
:load-path "/path/to/my/package")
#+END_SRC
**** :local-repo
Alternatively, you can specify a ~:local-repo~ in a ~package!~'s ~:recipe~
declaration:
#+BEGIN_SRC elisp
(package! my-package :recipe (:local-repo "/path/to/my/package"))
;; Don't forget to use :files to include files in an unconventional project structure:
(package! my-package
:recipe (:local-repo "/path/to/my/package"
:files ("*.el" "src/lisp/*.el")))
#+END_SRC
Remember to run ~doom sync~ to rebuild your package after you've changed it, and
to re-index any autoloads in it.
** Configuring Doom
*** Configuring packages
If your configuration needs are simple, the ~use-package!~, ~after!~,
~add-hook!~ and ~setq-hook!~ macros are your bread and butter.
#+BEGIN_SRC emacs-lisp
;;; ~/.doom.d/config.el (example)
(setq doom-font (font-spec :family "Fira Mono" :size 12))
;; Takes a feature symbol or a library name (string)
(after! evil
(setq evil-magic nil))
;; Takes a major-mode, a quoted hook function or a list of either
(add-hook! python-mode
(setq python-shell-interpreter "bpython"))
;; These are equivalent
(setq-hook! 'python-mode-hook python-indent-offset 2)
(setq-hook! python-mode python-indent-offset 2)
(use-package! hl-todo
;; if you omit :defer, :hook, :commands, or :after, then the package is loaded
;; immediately. By using :hook here, the `hl-todo` package won't be loaded
;; until prog-mode-hook is triggered (by activating a major mode derived from
;; it, e.g. python-mode)
:hook (prog-mode . hl-todo-mode)
:init
;; code here will run immediately
:config
;; code here will run after the package is loaded
(setq hl-todo-highlight-punctuation ":"))
#+END_SRC
For more flexibility, the ~use-package-hook!~ is another option, but should be
considered a last resort (because there is usually a better way). It allows you
to disable, append/prepend to and/or overwrite Doom's ~use-package!~ blocks.
These are powered by ~use-package~'s inject-hooks under the hood.
~use-package-hook!~ *must be used before that package's ~use-package!~ block*.
Therefore it must be used from your private init.el file.
#+BEGIN_SRC emacs-lisp
;;; ~/.doom.d/init.el (example)
;; If a :pre-init / :pre-config hook returns nil, it overwrites that package's
;; original :init / :config block. Exploit this to overwrite Doom's config.
(use-package-hook! doom-themes
:pre-config
(setq doom-neotree-file-icons t)
nil)
;; ...otherwise, make sure they always return non-nil!
(use-package-hook! evil
:pre-init
(setq evil-magic nil)
t)
;; `use-package-hook' also has :post-init and :post-config hooks
#+END_SRC
*** Reloading your config
You may find it helpful to have your changes take effect immediately. For things
that don't require a complete restart of Doom Emacs (like changing your enabled
modules or installed packages), you can evaluate Emacs Lisp code on-the-fly.
+ Evil users can use the =gr= operator to evaluate a segment of code. The return
value is displayed in the minibuffer or in a popup (if the result is large
enough to warrant one). =gr= works for most languages, but using it on Elisp is a special case; it's
executed within your current session of Emacs. You can use this to modify
Emacs' state on the fly.
+ Non-evil users can use =C-x C-e= to run ~eval-last-sexp~, as well as ~M-x +eval/buffer-or-region~ (on =SPC c e=).
+ Another option is to open a scratch buffer with =SPC x=, change its major mode
(~M-x emacs-lisp-mode~), and use the above keys to evaluate your code.
+ An ielm REPL is available by pressing =SPC o r=
(~+eval/open-repl-other-window~).
+ There's also =M-:= or =SPC ;=, which invokes ~eval-expression~, which you can
use to run elisp code inline.
While all this is helpful for reconfiguring your running Emacs session, it can
also be helpful for debugging.
*** TODO Binding keys
+ define-key
+ global-set-key
+ map!
+ undefine-key!
+ define-key!
** Writing your own modules
*** Load order
Module files are loaded in a precise order:
1. =~/.emacs.d/early-init.el= (Emacs 27+ only)
2. =~/.emacs.d/init.el=
3. =$DOOMDIR/init.el=
4. ={~/.emacs.d,$DOOMDIR}/modules/*/*/init.el=
5. ={~/.emacs.d,$DOOMDIR}/modules/*/*/config.el=
6. =$DOOMDIR/config.el=
*** Location
Doom searches for modules in =~/.emacs.d/modules/CATEGORY/MODULE/= and
=$DOOMDIR/modules/CATEGORY/MODULE/=. If you have a private module with the same
name as an included Doom module, yours will shadow the included one (as if the
included one never existed).
#+begin_quote
Doom refers to modules in one of two formats: ~:category module~ or
~category/module~.
#+end_quote
*** File structure
A module consists of several files, all of which are optional. They are:
#+begin_example
modules/
category/
module/
test/*.el
autoload/*.el
autoload.el
init.el
config.el
packages.el
doctor.el
#+end_example
**** =init.el=
This file is loaded early, before anything else, but after Doom core is loaded.
Use this file to:
+ Configure Emacs or perform setup/teardown operations that must be set early;
before other modules are (or this module is) loaded.
+ Reconfigure packages defined in Doom modules with ~use-package-hook!~ (as a
last resort, when ~after!~ and hooks aren't enough).
+ To change the behavior of ~bin/doom~.
Do *not* use this file to:
+ Configure packages with ~use-package!~ or ~after!~
+ Preform expensive or error-prone operations; these files are evaluated
whenever ~bin/doom~ is used.
**** =config.el=
This file is the heart of every module.
Code in this file should expect that dependencies (in =packages.el=) are
installed and available, but shouldn't make assumptions about what /modules/ are
activated (use ~featurep!~ to detect them).
Packages should be configured using ~after!~ or ~use-package!~:
#+BEGIN_SRC emacs-lisp
;; from modules/completion/company/config.el
(use-package! company
:commands (company-mode global-company-mode company-complete
company-complete-common company-manual-begin company-grab-line)
:config
(setq company-idle-delay nil
company-tooltip-limit 10
company-dabbrev-downcase nil
company-dabbrev-ignore-case nil)
[...])
#+END_SRC
#+begin_quote
For anyone already familiar with ~use-package~, ~use-package!~ is merely a thin
wrapper around it. It supports all the same keywords and can be used in much the
same way.
#+end_quote
**** =packages.el=
This file is where package declarations belong. It's also a good place to look
if you want to see what packages a module manages (and where they are installed
from).
A =packages.el= file shouldn't contain complex logic. Mostly conditional
statements and ~package!~, ~disable-packages!~ or ~depend-on!~ calls. It
shouldn't produce side effects and should be deterministic. Because this file
gets evaluated in an environment isolated from your interactive session, code
within should make no assumptions about the current session.
See the "[[*Package management][Package Management]]" section for details.
**** =autoload/*.el= OR =autoload.el=
Functions marked with an autoload cookie (~;;;###autoload~) in these files will
be lazy loaded.
When you run ~bin/doom autoloads~, Doom scans these files to populate autoload file
in =~/.emacs.d/.local/autoloads.el=, which will tell Emacs where to find these
functions when they are called.
For example:
#+BEGIN_SRC emacs-lisp
;; from modules/lang/org/autoload/org.el
;;;###autoload
(defun +org/toggle-checkbox ()
(interactive)
[...])
;; from modules/lang/org/autoload/evil.el
;;;###autoload (autoload '+org:attach "lang/org/autoload/evil" nil t)
(evil-define-command +org:attach (&optional uri)
(interactive "<a>")
[...])
#+END_SRC
**** =doctor.el=
This file is used by ~make doctor~, and should test for all that module's
dependencies. If it is missing one, it should use the ~warn!~, ~error!~ and
~explain!~ macros to inform the user why it's a problem and, ideally, a way to
fix it.
For example, the ~:lang cc~ module's doctor checks to see if the irony server is
installed:
#+BEGIN_SRC emacs-lisp
;; from lang/cc/doctor.el
(require 'irony)
(unless (file-directory-p irony-server-install-prefix)
(warn! "Irony server isn't installed. Run M-x irony-install-server"))
#+END_SRC
**** Additional files
Sometimes, it is preferable that a module's config.el file be split up into
multiple files. The convention is to name these additional files with a leading
=+=, e.g. =modules/feature/version-control/+git.el=.
There is no syntactical or functional significance to this convention.
Directories do not have to follow this convention, nor do files within those
directories.
These additional files are *not* loaded automatically. You will need to use the
~load!~ macro to do so:
#+BEGIN_SRC emacs-lisp
;; from modules/feature/version-control/config.el
(load! +git)
#+END_SRC
The ~load!~ macro will try to load a =+git.el= relative to the current file.
*** Flags
A module flag is an arbitrary symbol. By convention, these symbols are prefixed
with a ~+~ or a ~-~, to respectively denote the addition or removal of a
feature. There is no functional significance to this notation.
A module may choose to interpret flags however it likes. They can be tested for
with the ~featurep!~ macro:
#+BEGIN_SRC elisp
;; Has the current module been enabled with the +my-feature flag?
(when (featurep! +my-feature) ...)
;; It can be used to check the presence of flags in other modules:
(when (featurep! :lang python +lsp) ...)
#+END_SRC
*** Module cookies
A special syntax exists called module cookies. Like autoload cookies
(~;;;###autoload~), module files may have ~;;;###if FORM~ at or near the top of
the file. FORM is read determine whether or not to ignore this file when
scanning it for autoloads (~doom sync~) or byte-compiling it (~doom compile~).
Use this to prevent errors that may occur if that file contains (for example)
calls to functions that won't exist if a certain feature isn't available to that
module, e.g.
#+BEGIN_SRC emacs-lisp
;;;###if (featurep! +lsp)
#+END_SRC
#+BEGIN_SRC emacs-lisp
;;;###if (not (locate-library "so-long"))
#+END_SRC
Remember that these run in a limited, non-interactive sub-session, so do not
call anything that wouldn't be available in a Doom session without any modules
enabled.
*** Autodefs
An autodef is a special kind of autoloaded function or macro which Doom
guarantees will always be defined, whether or not its containing module is
enabled (but will no-op without evaluating its arguments when it is disabled).
You can browse the available autodefs in your current session with ~M-x
doom/help-autodefs~ (=SPC h d u= or =C-h d u=).
What distinguishes an autodef from a regular autoload is the ~;;;###autodef~
cookie:
#+BEGIN_SRC elisp
;;;###autodef
(defun set-something! (value)
...)
#+END_SRC
An example would be the ~set-company-backend!~ function that the =:completion
company= module exposes. It lets you register company completion backends with
certain major modes. For instance:
#+BEGIN_SRC emacs-lisp
(set-company-backend! 'python-mode '(company-anaconda))
#+END_SRC
** Common mistakes when configuring Doom Emacs
Having helped many users configure Doom, I've spotted a few recurring oversights
that I will list here, in the hopes that it will help you avoid the same
mistakes:
*** Packages are eagerly loaded
Using ~use-package!~ without a deferring keyword (one of: ~:defer :after
:commands :defer-incrementally :after-call~) will load the package immediately.
This causes other packages to be pulled in and loaded, which will compromise
many of Doom's startup optimizations.
This is usually by accident. Choosing which keyword to use depends on the
needs of the package, so there is no simple answer to this.
*** Manual package management
A lot of Emacs documentation and help will contain advice to install packages
with package.el's API (e.g. ~package-install~) or with use-package's ~:ensure~
keyword). You are free to do this, if it is your preference, but otherwise, Doom
has its own package management system.
Migrating ~use-package~ code to Doom is usually a case of removing the ~:ensure~
keyword and adding a ~(package! PACKAGENAME)~ to =~/.doom.d/packages.el= (and
running ~doom sync~ to sync your config).
*** Using ~org-babel-do-load-languages~ to load your babel packages
You don't need ~org-babel-do-load-languages~. Doom lazy loads babel packages
based on the language name in ~#+BEGIN_SRC~ blocks needed. As long as the babel
plugin is installed and the plugin is named after its language (e.g.
~#+BEGIN_SRC rust~ will load ~ob-rust~), you don't need to do anything else.
There may be some special cases, however. Doom tries to handle a couple of them
(e.g. with ob-jupyter, ob-ipython and ob-async). If you are experiencing errors
while trying to use a certain language in org src blocks, check out the [[file:../modules/lang/org/README.org][:lang
org module documentation]] for details on how to add support for it.
*** Using ~delete-trailing-whitespaces~ or ~whitespace-cleanup~ to manage leftover whitespace
#+BEGIN_SRC elisp
(add-hook 'after-save-hook #'delete-trailing-whitespace)
;; or
(add-hook 'after-save-hook #'whitespace-cleanup)
#+END_SRC
These two lines are a common sight in Emacs configs, but they are unnecessary
for Doom Emacs. We already use the more sophisticated =wsbutler= to manage
extraneous whitespace. However, you might have the impression that it isn't
working. That's because =wsbutler= works in two unusual ways, meant to be less
imposing than its alternatives:
1. It only cleans up trailing whitespace /on lines that you've touched/ (but
always strips newlines at EOF).
Why do this? Because I believe file-wide reformatting should be a deliberate
act (and not blindly automated). If it is necessary, chances are you're
working on somebody else's project -- or with other people, but here, large
scale whitespace changes could cause problems or simply be rude. We don't
endorse PRs that are 1% contribution and 99% whitespace!
However, if it's truly deliberate, ~M-x delete-trailing-whitespaces~ and ~M-x
whitespace-cleanup~ are available to be called =deliberately=, instead.
2. =wsbutler= replaces trailing whitespace and newlines with *virtual*
whitespace. This is whitespace that only exists in the Emacs buffer, but
isn't actually written to the file.
Why do this? Because you might have wanted to use that space for something in
your current editing session, and it would be inconvenient for the editor to
delete it before you got to it.
If you use it, it's there. If you don't, it isn't written to the file.
* Troubleshoot
When problems arise, you should be prepared to collect information in order to
solve them, or for the bug report you're about to write. Both Emacs and Doom
provide tools to make this easier. Here are a few things you can try, first:
+ Investigate the =*Messages*= log for warnings or error messages. This log can
be opened with =SPC h e=, =C-h e= or =M-x view-echo-area-messages=.
+ Look up errors/warnings [[file:faq.org::Common Issues][on the FAQ]] and [[https://github.com/hlissner/doom-emacs/issues][Doom's issue tracker]]. It is possible
that a solution for your issue already exists. The FAQ can be searched from
inside Doom with =SPC h d f= (or =C-h d f= for non-evil users).
+ Run ~bin/doom doctor~ on the command line to diagnose common issues with your
environment and config. It will suggest solutions for them as well.
+ ~bin/doom clean~ will ensure the problem isn't stale bytecode in your private
config or Doom core. If you haven't used ~bin/doom compile~, there's no need
to do this.
+ ~bin/doom sync~ will ensure the problem isn't missing packages or outdated
autoloads files
+ ~bin/doom build~ will ensure the problem isn't stale package bytecode or
broken symlinks.
+ ~bin/doom update~ will ensure that your packages are up-to-date, eliminating
issues that originate from upstream.
+ If you happen to know what module(s) are relevant to your issue, check their
documentation (press =<leader> h m= to jump to a module's documentation). Your
issue may be documented.
+ If possible, see if the issue can be reproduced in vanilla Emacs (Emacs
without Doom) and/or vanilla Doom (Doom without your private config). [[*Use the sandbox][Doom's
sandbox can help you check]].
+ Ask for help on [[https://discord.gg/qvGgnVx][our Discord server]]. It is the quickest way to get help,
sometimes straight from Doom's maintainer, who is very active there.
If none of these things have helped you, then it's time to open a bug report.
See "[[file:contributing.org::*Reporting issues][Reporting Issues]]" in the [[file:contributing.org][contributing guidelines]] on how to file an
effective bug report.
** Looking up documentation and state from within Emacs
...
*** Variables, functions, faces, etc.
Emacs is a Lisp interpreter whose state you can access on-the-fly with tools
provided to you by Emacs itself. They're available on the =SPC h= prefix by
default. Use them to debug your sessions.
Here are some of the more important ones:
+ ~describe-variable~ (=SPC h v=)
+ ~describe-function~ (=SPC h f=)
+ ~describe-face~ (=SPC h F=)
+ ~describe-bindings~ (=SPC h b=)
+ ~describe-key~ (=SPC h k=)
+ ~describe-char~ (=SPC h '=)
+ ~find-library~ (=SPC h P=)
You can also evaluate code with ~eval-expression~ (=M-;= or =SPC ;=).
*** TODO For Doom Modules, packages, autodefs, etc.
+ ~doom/open-news~ (=SPC h n=) ::
...
+ ~doom/open-manual~ (=SPC h D=) ::
...
+ ~doom/describe-module~ (=SPC h d=) ::
Jumps to a module's documentation.
+ ~doom/describe-autodefs~ (=SPC h A=) ::
Jumps to the documentation for an autodef function/macro. These are special
functions that are always defined, whether or not their containing modules
are enabled.
+ ~doom/describe-package~ (=SPC h p=) ::
Look up packages that are installed, by whom (what modules) and where jump
to all the places it is being configured.
+ ~doom/info~ ::
...
** How to extract a backtrace from an error
If you encounter an error while using Doom Emacs, you're probably about to head
off and file a bug report (or request help on [[https://discord.gg/qvGgnVx][our Discord server]]). Before you
do, please generate a backtrace to include with it.
To do so you must enable ~debug-on-error~ then recreate the error.
*** Enabling ~debug-on-error~
There are three ways to enable ~debug-on-error~:
1. Start Emacs with ~emacs --debug-init~. Use this for errors that occur at
startup.
2. Evil users can press =SPC h d d= and non-evil users can press =C-h d d=.
3. If the above don't work, there's always: ~M-x toggle-debug-on-error~
Now that ~debug-on-error~ is on, recreate the error. A window should pop up with
a backtrace.
*** A backtrace from ~bin/doom~
If the error you've encountered is emitted from ~bin/doom~, you can re-run the
same command with the ~-d~ or ~--debug~ switches to force it to emit a backtrace
when an error occurs. The ~DEBUG~ environment variable will work to.
#+BEGIN_SRC sh
doom -d sync
doom --debug install
DEBUG=1 doom update
#+END_SRC
#+BEGIN_QUOTE
Note: switch order is important. ~-d~ / ~--debug~ /must/ come right after ~doom~
and before the subcommand. This will be fixed eventually.
#+END_QUOTE
** Evaluating Elisp on-the-fly
Often, you may find it helpful for debugging to evaluate some Emacs Lisp. Here
are couple things you can do:
+ Use =M-;= (bound to ~eval-expression~),
+ =SPC x= will open a scratch buffer. ~M-x emacs-lisp-mode~ will change it to
the appropriate major mode, then use ~+eval:region~ (=gr=) and ~+eval:buffer~
(=gR=) to evaluate code,
** How to determine the origin of a bug
** Testing in Doom's sandbox
"The sandbox" is one of Doom Emacs' features; it is a test bed for running elisp
in a fresh instance of Emacs with varying amounts of Doom loaded (none at all,
all of it, or somewhere in between). This can be helpful for isolating bugs to
determine who you should report a bug to.
If you can recreate a bug in vanilla Emacs than it should be reported to the
developers of the relevant packages or, perhaps, the Emacs devs themselves.
Otherwise, it is best to bring it up on the Doom Emacs issue list, rather than
confusing and inundating the Emacs community with Doom-specific issues.
*** Opening the sandbox
There are three common ways to access the sandbox:
+ =SPC h E= (for evil users)
+ =C-h E= (for non-evil users)
+ ~M-x doom/sandbox~
Doing any of the above will pop up a ~*doom:sandbox*~ window. What you enter
into this buffer will be executed in the new instance of Emacs when you decide
to launch it.
*** Launching the sandbox
You have four options when it comes to launching the sandbox:
- =C-c C-c= :: This launches "vanilla Emacs". Vanilla means nothing is loaded;
purely Emacs and nothing else. If you can reproduce an error here, then the
issue likely lies in the plugin(s) you are testing or in Emacs itself.
- =C-c C-d= :: This launches "vanilla Doom", which is vanilla Emacs plus Doom's
core. This does not load your private config, nor any of Doom's (or your)
modules.
- =C-c C-p= :: This launches "vanilla Doom+". That is, Doom core plus the
modules that you have specified in the ~doom!~ block of your private config
(in =~/.doom.d/init.el=). This *does not* load your private config, however.
- =C-c C-f= :: This launches "full Doom". It loads Doom's core, your enabled
modules, and your private config. This instance should be identical to the
instance you launched it from.
#+BEGIN_QUOTE
All new instances will inherit your ~load-path~ so you can access any packages
you have installed.
#+END_QUOTE
*** Testing packages in the sandbox
Instances of Emacs launched from the sandbox have inherited your ~load-path~.
This means you can load packages -- even in Vanilla Emacs -- without worrying
about installing or setting them up. Just ~(require PACKAGE)~ and launch the
sandbox. e.g.
#+BEGIN_SRC elisp
(require 'magit)
(find-file "~/some/file/in/a/repo")
(call-interactively #'magit-status)
#+END_SRC
** TODO Bisecting your private config
** TODO Bisecting Doom Emacs