doomemacs/docs/getting_started.org

1182 lines
45 KiB
Org Mode
Raw Normal View History

2019-10-29 12:51:04 +08:00
#+TITLE: Getting Started Guide
#+STARTUP: nofold
* Table of Contents :TOC_4:
- [[#install][Install]]
- [[#emacs--dependencies][Emacs & dependencies]]
- [[#on-linux][On Linux]]
- [[#arch-linux][Arch Linux:]]
- [[#ubuntu][Ubuntu:]]
- [[#nixos][NixOS]]
2019-10-30 22:41:10 +08:00
- [[#on-macos][On macOS]]
2019-10-29 12:51:04 +08:00
- [[#where-not-to-install-emacs-from][Where *not* to install Emacs from]]
- [[#on-windows][On Windows]]
- [[#chocolatey--scoop][chocolatey / scoop]]
- [[#wsl][WSL]]
- [[#wsl2][WSL2]]
- [[#doom-emacs][Doom Emacs]]
- [[#install-doom-manually][Install Doom Manually]]
- [[#alongside-other-emacs-configs-with-chemacs][Alongside other Emacs configs (with Chemacs)]]
- [[#externalsystem-dependencies][External/system dependencies]]
- [[#update][Update]]
- [[#doom][Doom]]
- [[#plugins][Plugins]]
- [[#rollback][Rollback]]
- [[#customize][Customize]]
- [[#how-to-enable-or-disable-modules][How to enable or disable modules]]
- [[#package-management][Package management]]
- [[#installing-packages][Installing packages]]
- [[#installing-packages-from-external-sources][Installing packages from external sources]]
- [[#disabling-packages][Disabling packages]]
- [[#changing-a-built-in-recipe-for-a-package][Changing a built-in recipe for a package]]
- [[#usingloading-local-packages][Using/loading local packages]]
- [[#configuring-doom][Configuring Doom]]
- [[#configuring-packages][Configuring packages]]
- [[#reloading-your-config][Reloading your config]]
- [[#binding-keys][Binding keys]]
- [[#doomdir-file-structure][DOOMDIR file structure]]
- [[#writing-your-own-modules][Writing your own modules]]
- [[#structure-of-a-module][Structure of a module]]
- [[#initel][=init.el=]]
- [[#configel][=config.el=]]
- [[#packagesel][=packages.el=]]
- [[#autoloadel-or-autoloadel][=autoload/*.el= OR =autoload.el=]]
- [[#doctorel][=doctor.el=]]
- [[#additional-files][Additional files]]
- [[#load-order][Load order]]
- [[#module-flags][Module flags]]
- [[#testing-for-flags][Testing for flags]]
- [[#module-settings][Module settings]]
- [[#module-cookies][Module cookies]]
- [[#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-plugins][Using ~org-babel-do-load-languages~ to load your babel plugins]]
- [[#using-delete-trailing-whitespaces-or-whitespace-cleanup-to-manage-leftover-whitespace][Using ~delete-trailing-whitespaces~ or ~whitespace-cleanup~ to manage leftover whitespace]]
- [[#troubleshoot][Troubleshoot]]
- [[#ive-run-into-an-issue-where-do-i-start][I've run into an issue, where do I start?]]
- [[#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~]]
2019-10-29 12:51:04 +08:00
- [[#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]]
2019-10-29 12:51:04 +08:00
* Install
To embark on this grand Emacs adventure, you'll need a couple things installed,
including Emacs (shocking, I know), Doom Emacs, the plugins Doom depends on, and
any external tools /they/ depend on as well.
In summary, you'll be installing:
+ *git*
+ *Emacs 26.1+*
+ *ripgrep*
+ *all-the-icons fonts* -- unnecessary for exclusive use of terminal Emacs
And then some optional dependencies that you will likely want, as the will
optimize Doom's performance and stability.
+ [[https://github.com/sharkdp/fd][fd]]
2019-10-30 22:41:10 +08:00
+ *GNU ls* (BSD ls on macOS/BSD Linux has some limitations)
2019-10-29 12:51:04 +08:00
+ *clang* -- with which to compile certain external dependencies, like the
emacsqlite binary, irony server (requires clang), or vterm module
The following sections will cover how to install Emacs and these dependencies
across various operating systems.
#+BEGIN_QUOTE
If any of these install instructions are outdated, or your OS is missing, please
help us by [[https://github.com/hlissner/doom-emacs/issues/new][letting us know]] (or correcting it yourself; pull requests are
welcome).
#+END_QUOTE
** Emacs & dependencies
*** On Linux
Emacs should be available through your distribution's package manager.
Otherwise, it can be [[https://www.gnu.org/software/emacs/manual/html_node/efaq/Installing-Emacs.html][built from source]].
**** Arch Linux:
#+BEGIN_SRC bash
pacman -S git tar clang emacs ripgrep fd
#+END_SRC
Emacs 27 (HEAD) can be installed through [[https://aur.archlinux.org/packages/emacs-git/][emacs-git]], available on the AUR.
**** Ubuntu:
#+BEGIN_SRC bash
apt-get install git tar clang ripgrep fd-find
#+END_SRC
On Ubuntu 18.04, the latest version of Emacs available is 25.3 (and 24.3 on
Ubuntu 16 or 14). Therefore, we have a few extra steps to install 26.1+:
#+BEGIN_SRC bash
add-apt-repository ppa:kelleyk/emacs
apt-get update
apt-get install emacs26
#+END_SRC
**** NixOS
On NixOS Emacs 26.x can be installed via ~nix-env --install emacs~, or more
permanently by adding the following entry to ~etc/nixos/configuration.nix~:
#+BEGIN_SRC nix
environment.systemPackages = with pkgs; [
coreutils # basic GNU utilities
git
clang
emacs
ripgrep
fd
];
#+END_SRC
2019-10-30 22:41:10 +08:00
*** On macOS
2019-10-29 12:51:04 +08:00
Mac users several options to install Emacs, but only a few of them are
recommended for Doom Emacs (you'll need to [[http://brew.sh/][install Homebrew]] first). To start
with:
#+BEGIN_SRC bash
brew install git clang ripgrep fd coreutils
#+END_SRC
As for Emacs, there are several formulas to choose from. There are the best
options, in order from most to least recommended for Doom.
- [[https://github.com/d12frosted/homebrew-emacs-plus][emacs-plus]] (the safest option):
#+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://formulae.brew.sh/formula/emacs][emacs]] is another acceptable option.
#+BEGIN_SRC bash
brew install emacs
#+END_SRC
- [[https://bitbucket.org/mituharu/emacs-mac/overview][emacs-mac]] is also acceptable. It offers slightly better integration into
2019-10-30 22:41:10 +08:00
macOS, with native emojis and better childframe support. However, at the time
2019-10-29 12:51:04 +08:00
of writing, it [[https://github.com/railwaycat/homebrew-emacsmacport/issues/52][lacks multi-tty support]] (which impacts daemon usage). Use it if
you experience crashing or performance issues with emacs-plus.
#+BEGIN_SRC bash
brew tap railwaycat/emacsmacport
brew install emacs-mac
ln -s /usr/local/opt/emacs-mac/Emacs.app /Applications/Emacs.app
#+END_SRC
**** Where *not* to install Emacs from
These builds/forks have known compatibility issues with Doom and are likely to
cause you issues later on. Do not use them:
+ emacsformacosx.com
+ ~brew cask install emacs~ (installs from emacsformacosx.com)
+ AquaMacs
+ XEmacs
*** On Windows
*Support for Windows is immature,* so your mileage will vary. Some have reported
success with installing Doom via WSL, chocolatey on git-bash or cygwin.
2019-10-29 12:51:04 +08:00
#+BEGIN_QUOTE
If you manage to get Doom on Windows and found this 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 llvm emacs ripgrep fd
#+END_SRC
#+begin_quote
You can also use [[https://scoop.sh/][scoop]] by simply replacing ~choco~ with ~scoop~ in the above
snippet to achieve the same result. This hasn't been tested, however.
#+end_quote
You will also need to [[https://mywindowshub.com/how-to-edit-system-environment-variables-for-a-user-in-windows-10/][add a ~HOME~ system variable]], pointing to
=C:\Users\USERNAME\=, otherwise Emacs will treat
=C:\Users\USERNAME\AppData\Roaming= is your ~HOME~, which causes issues.
It's also a good idea to add =C:\Users\USERNAME\.emacs.d\bin= to your ~PATH~.
**** TODO WSL
**** TODO WSL2
** Doom Emacs
The quickest way to get Doom up and running is:
#+BEGIN_SRC bash
git clone https://github.com/hlissner/doom-emacs ~/.emacs.d
~/.emacs.d/bin/doom install
#+END_SRC
=doom install= performs the following for you:
1. It creates your =DOOMDIR= at =~/.doom.d=, if it (or =~/.config/doom=) don't
already exist.
2. Copies =~/.emacs.d/init.example.el= to =$DOOMDIR/init.el=, which contains a
~doom!~ statement that controls what modules to enable and in what order they
are loaded.
3. Creates dummy config.el and packages.el files in ~$DOOMDIR~.
4. Optionally generates an envvar file (equivalent to using ~doom env~), which
stores your shell environment in an env file that Doom will load at startup.
2019-10-30 22:41:10 +08:00
*This is essential for macOS users!*
2019-10-29 12:51:04 +08:00
5. Installs all dependencies for enabled modules (specified by
=$DOOMDIR/init.el=),
6. And prompts to install the icon fonts required by the [[https://github.com/domtronn/all-the-icons.el][all-the-icons]] package.
#+BEGIN_QUOTE
You'll find a break down of ~doom install~ into shell commands in the next
section.
#+END_QUOTE
Consider the =~/.emacs.d/bin/doom= script your new best friend. It performs a
variety of essential functions to help you manage your Doom Emacs configuration,
not least of which is installing or updating it or its plugins. If nothing else,
get to know these four commands:
- ~doom refresh~: Ensures that Doom is in a proper state to be used (i.e. needed
packages are installed, orphaned packages are removed and necessary metadata
correctly generated).
- ~doom upgrade~: Updates Doom Emacs (if available) and its packages.
- ~doom env~: Generates an "envvar file", which scrapes your shell environment
into a file that is loaded by Doom Emacs at startup. This is especially
2019-10-30 22:41:10 +08:00
necessary for macOS users who open Emacs through an Emacs.app bundle.
2019-10-29 12:51:04 +08:00
- ~doom doctor~: If Doom misbehaves, the doc will diagnose common issues with
your installation and environment. If all else fails, you'll find help on
Doom's [[https://discord.gg/bcZ6P3y][Discord server]] and [[https://github.com/hlissner/doom-emacs/issues][issue tracker]].
Run ~doom help <COMMAND>~ for documentation on these commands, or ~doom help~
for an overview of what the =bin/doom= script is capable of.
#+begin_quote
I recommend you add =~/.emacs.d/bin= to your ~PATH~ so you can call =doom=
directly, from anywhere. You don't need to be CDed into =~/.emacs.d/bin= to use
it. A quick way to do so is to add this to your .bashrc or .zshrc file:
2019-10-30 06:52:40 +08:00
~export PATH="$HOME/.emacs.d/bin:$PATH"~
2019-10-29 12:51:04 +08:00
#+end_quote
*** Install Doom Manually
If you'd rather install Doom yourself, without the magic of =bin/doom install=,
here is its equivalent in bash shell commands:
#+BEGIN_SRC bash
git clone https://github.com/hlissner/doom-emacs ~/.emacs.d
# So we don't have to write ~/.emacs.d/bin/doom every time
export 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
# 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
# Edit ~/.doom.d/init.el and adjust the modules list to your liking before
# running this:
doom install
# If you know Emacs won't be launched from your shell environment (e.g. you're
2019-10-30 22:41:10 +08:00
# on macOS or use an app launcher that doesn't launch programs with the correct
2019-10-29 12:51:04 +08:00
# shell), then creating an envvar file is necessary to ensure Doom inherits your
# shell environment.
#
# If you don't know whether you need this or not, no harm in doing it anyway.
# `doom install` will prompt you to generate an envvar file. If you responded
# no, you can generate it later with the following command:
doom env
# 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 [[#customize][Customize]] section further below.
2019-10-29 12:51:04 +08:00
*** Alongside other Emacs configs (with Chemacs)
[[https://github.com/plexus/chemacs][Chemacs]] is a bootloader for Emacs. It makes it easy to switch between multiple
Emacs configurations. Here is a quick guide for setting it up with Doom Emacs as
the default config.
After you've followed the installation instructions for Doom and Emacs, outlined
above, deploy [[https://raw.githubusercontent.com/plexus/chemacs/master/.emacs][the Chemacs' startup script]] to =~/.emacs=:
#+BEGIN_SRC bash
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
2019-11-24 19:21:49 +08:00
Then create =~/.emacs-profiles.el= with a list of your Emacs profiles. This file
2019-10-29 12:51:04 +08:00
is structured like a =.dir-locals.el= file. Here is an example with Doom (as the
default), Spacemacs, and Prelude:
#+BEGIN_SRC emacs-lisp
(("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
Your system, your rules. There are as many ways to set up a programming
environment as there are dislikes on Youtube Rewind 2018, so Doom entrusts this
task to you, dear user.
Doom is comprised of modules which provide most of its features, including
language support and integration with external tools. However, some of these
have external dependencies that you must install yourself. You'll find what
modules need what and how to install them in that module's README.org file. If
you find a module without a README file, helps us out by creating one for us!
~doom doctor~ will provide an overview of missing dependencies (only for the
modules you have enabled) by reporting which ones haven't been installed yet.
Once you know what's missing, have a look at the documentation for that module.
Use ~M-x doom/help-modules~ (bound to =SPC h d m=) to quickly jump to a module's
documentation from inside Doom. Otherwise, check out the [[file:index.org::*Module list][Module Index]].
* Update
Doom is an active project and many of its 300+ plugins are in active development
as well. It is wise to occasionally update them. The following section will go
over how to do so.
#+begin_quote
*Important: you may encounter errors after up/downgrading Emacs.* Emacs bytecode
is not forward compatible, so you must recompile or reinstall your plugins to
fix this, i.e.
+ ~doom build~, to rebuild all your installed plugins,
+ Or delete =~/.emacs.d/.local= then ~doom refresh~ to reinstall them
#+end_quote
** Doom
The =bin/doom= script provides a simple command for upgrading Doom (which will
also update your plugins):
#+BEGIN_SRC bash
doom upgrade # short version: 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 refresh # refreshes plugins & autoloads
doom update # updates installed plugins
#+END_SRC
To minimize issues while upgrading, avoid modifying Doom's source files. All
your customization should be kept in your =DOOMDIR= (typically, =~/.doom.d=).
Read the [[#customize][Customize]] section for more on configuring Doom.
2019-10-29 12:51:04 +08:00
** Plugins
To update /only/ your plugins (i.e. not Doom), run ~doom update~ (short version:
~doom u~).
** Rollback
The =bin/doom= script doesn't currently offer rollback support for Doom or its
plugins (yet).
* Customize
Your private configuration is located in =~/.doom.d=, by default (if
=~/.config.d/doom= exists, that will be used instead). This directory is
referred to as your ~$DOOMDIR~ or your "private module".
~doom install~ will create three files in your DOOMDIR to start you off:
+ init.el :: This is where you'll find your ~doom!~ block, which controls what
modules are enabled and in what order they are loaded. This is copied from
=~/.emacs.d/init.example.el=.
+ config.el :: This is where the bulk of your private configuration will go.
+ packages.el :: This is where you tell Doom what packages you want to install
and where from.
** How to enable or disable modules
Every private config starts with a ~doom!~ block, found in =$DOOMDIR/init.el=.
If you followed the Doom installation instructions and ran ~doom install~, this
file should exist and will contain one.
This block controls what modules are enabled and in what order they are loaded.
To enable a module, add it to this list. To disable it, either remove it or
comment it out (in Emacs Lisp, anything following a semicolon is ignored by the
Elisp interpreter; i.e. it's "commented out").
#+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
Some modules have optional features that can be enabled by passing them flags
like so:
#+BEGIN_SRC emacs-lisp
(doom! :completion
(company +auto)
:lang
(csharp +unity)
(org +attach +babel +capture +export +present +protocol)
(sh +fish))
#+END_SRC
Different modules support different flags. To see a quick list of what modules
support what flags in [[file:index.org::*Module list][the Module Index]].
*WARNING:* when changing your ~doom!~ block you *must* run =~/.emacs.d/bin/doom
refresh= and restart Emacs for the changes to take effect. This ensures the
needed packages are installed, orphaned packages are removed, and necessary
metadata for your Doom Emacs config has been generated.
** Package management
Doom's package manager is declarative. Your ~DOOMDIR~ is a module, and modules
may optionally possess a packages.el file, where you may declare what packages
you want to install (and where from) using the ~package!~ macro. It can be used
to:
1. Install packages (conditionally, even),
2. Disable packages (uninstalling them and disabling their configuration),
3. Or change where a package is installed from.
If a package is installed via ELPA and does not have a ~package!~ declaration,
Doom will assume the package is unwanted and uninstall it for you next time
~doom refresh~ is executed.
#+begin_quote
Remember to run ~doom refresh~ after modifying your packages, to ensure they are
installed and properly integrated into Doom.
#+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)
;; Tell Doom to install it from a particular archive (e.g. elpa). By default, it
;; will search orgmode.org and melpa.org before searching elpa.gnu.org. See
;; `package-archives' to adjust this order (or to see what values :pin will
;; accept).
(package! example :pin "elpa")
;; Instruct Doom to install this package once, but never update it when you run
;; `doom update` or `doom upgrade`:
(package! example :freeze t)
;; 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 isn't disabled and is cleared for
install. Use this fact to conditionally install other packages, 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 .el and must have at least a Package-Version
;; or Version line in its header.
2019-10-29 12:51:04 +08:00
(package! example :recipe (:host github :repo "username/my-example-fork"))
;; If the source files for a package are in a subdirectory in said repo, you'll
;; need to specify what files to pull in.
(package! example :recipe
(:host github
:repo "username/my-example-fork"
:files ("*.el" "src/lisp/*.el")))
;; To grab a particular commit:
(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 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))
#+END_SRC
*** 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-packages!~ and ~after!~ blocks for it will be
ignored, and the package will be removed the next time you run ~doom refresh~.
2019-10-30 22:41:10 +08:00
Use this to disable undesirable packages included with the built-in modules.
2019-10-29 12:51:04 +08:00
Alternatively, the ~disable-packages!~ macro exists for more concisely disabling
multiple packages:
#+BEGIN_SRC elisp
(disable-packages! irony rtags)
#+END_SRC
*** Changing a built-in recipe for a package
If a module installs package X, but you'd like to install it from somewhere else
(say, a superior fork or a fork with a bugfix), simple add a ~package!~
declaration for it in your =DOOMDIR/packages.el=. Your private declarations
always have precedence over modules (even your own modules).
#+BEGIN_SRC elisp
;; modules/editor/evil/packages.el
(package! evil) ; installs from MELPA
;; DOOMDIR/packages.el
(package! evil :recipe (:host github :repo "username/my-evil-fork"))
#+END_SRC
You will need to run ~doom refresh~ for this change to take effect.
*** TODO Using/loading local packages
** Configuring Doom
*** Configuring packages
If your configuration needs are simple, the ~use-package!~, ~after!~,
~add-hook!~ and ~setq-hook!~ emacros can help you reconfigure packages:
#+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
2019-10-30 22:41:10 +08:00
executed within your current session of Emacs. You can use this to modify
2019-10-29 12:51:04 +08:00
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!
+ unmap!
+ define-key!
*** TODO DOOMDIR file structure
** Writing your own modules
Modules are made up of several files, all of which are optional. This is a
comprehensive list of what they are:
#+begin_example
modules/
category/
module/
test/*.el
autoload/*.el
autoload.el
init.el
config.el
packages.el
doctor.el
#+end_example
By default, doom looks for modules in two places: =.emacs.d/modules/= where doom's
own modules are located and =$DOOMDIR/modules/= where you can define your
own private modules.
2019-10-29 12:51:04 +08:00
*** Structure of a module
**** =init.el=
This file is loaded first, before anything else, but after Doom core is loaded.
Use this file to:
+ Configure Emacs or perform setup/teardown operations that must be set before
other modules are (or this module is) loaded. Tampering with ~load-path~, for
instance.
+ 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!~ for this).
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.
The ~package!~ macro is the star of the show in =packages.el= files:
#+BEGIN_SRC emacs-lisp
;; from modules/lang/org/packages.el
(package! org-bullets)
;; from modules/tools/rotate-text/packages.el
(package! rotate-text :recipe (:host github :repo "debug-ito/rotate-text.el"))
#+END_SRC
Its ~:recipe~ property accepts [[https://github.com/melpa/melpa#recipe-format][a MELPA recipe]], which provides a lot of control
over where to fetch a package, including specific commit, tags or branches:
#+BEGIN_SRC emacs-lisp
(package! rotate-text
:recipe (:host github
:repo "debug-ito/rotate-text.el"
:commit "1a2b3c4d"))
#+END_SRC
You can also use this ~package!~ to disable other packages:
#+BEGIN_SRC emacs-lisp
;; Uninstalls evil, keeps it uninstalled, and tells Doom to ignore any
;; use-package! and after! blocks for it
(package! evil :disable t)
;; disable-packages! can be used to disable multiple packages in one statement
(disable-packages! evil evil-snipe evil-escape)
#+END_SRC
**** =autoload/*.el= OR =autoload.el=
Functions marked with an autoload cookie (~;;;###autoload~) in these files will
be lazy loaded.
2019-10-30 22:41:10 +08:00
When you run ~bin/doom autoloads~, Doom scans these files to populate autoload file
2019-10-29 12:51:04 +08:00
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
2019-10-30 22:41:10 +08:00
Sometimes, it is preferable that a module's config.el file be split up into
2019-10-29 12:51:04 +08:00
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.
*** Load order
Module files are loaded in a precise order:
#+BEGIN_SRC sh
~/.emacs.d/early-init.el # in Emacs 27+ only
~/.emacs.d/init.el
$DOOMDIR/init.el
{~/.emacs.d,$DOOMDIR}/modules/*/*/init.el
{~/.emacs.d,$DOOMDIR}/modules/*/*/config.el
$DOOMDIR/config.el
#+END_SRC
*** Module flags
In the code examples of the previous section, you may have noticed something odd
about that haskell entry: ~(haskell +intero)~. ~+intero~ is a module flag. You
may specify these for any module that supports them. Unsupported flags are
ignored.
You can find out what flags a module supports by looking at its documentation (a
README.org in the module's directory; which can be jumped to quickly with ~M-x
doom/describe-module~).
For example, the haskell module supports the ~+intero~ and ~+dante~ flags, which
represent the two Haskell backends available to Emacs. You may choose one or the
other (or neither, or both) by specifying the appropriate flags in you ~doom!~
block:
#+BEGIN_SRC emacs-lisp
(doom! :lang (haskell +dante))
#+END_SRC
You may specify as many flags are you like:
#+BEGIN_SRC emacs-lisp
(doom! :lang (org +attach +babel +capture +export +present))
#+END_SRC
#+begin_quote
=+flagname= is simply a naming convention and has no syntactical or functional
significance.
#+end_quote
**** Testing for flags
Modules are free to interpret flags however they like. If you are writing your
own module(s), you can test for flags using the ~featurep! MODULE SUBMODULE
&optional FLAG~ macro:
#+BEGIN_SRC emacs-lisp
(when (featurep! :lang haskell +dante)
[...])
#+END_SRC
The first two arguments if ~featurep!~ may be skipped if it is used from inside
a module. For example:
#+BEGIN_SRC emacs-lisp
;; In modules/lang/haskell/config.el
(when (featurep! +dante) ; same as (featurep! :lang haskell +dante)
[...])
#+END_SRC
*** Module settings
Some modules expose settings that can be configured from other modules. Use ~M-x
doom/help-autdefs~ (=SPC h d a= or =C-h d a=) to see what is available and how
to use them.
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
You'll find what settings a module exposes in its documentation (remember to use
~M-x doom/help-modules~ on =SPC h d m= or =C-h d m=).
*** Module cookies
There is a special syntax available to module files called module cookies. Like
autoload cookies (~;;;###autoload~), module files may have ~;;;###if FORM~ at or
near the top of the file. FORM is read by ~doom refresh~ and ~doom compile~ to
determine whether or not to ignore this file.
If FORM returns nil, the file won't be scanned for autoloads nor will it be
byte-compiled. 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! +intero)
#+END_SRC
#+BEGIN_SRC emacs-lisp
;;;###if (not (featurep 'evil-mode))
#+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.
** 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 can cause 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 refresh~ to sync your config).
*** Using ~org-babel-do-load-languages~ to load your babel plugins
You don't need ~org-babel-do-load-languages~. Doom lazy loads babel plugins
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, and they will, you will need to debug them. Fortunately,
Emacs (and Doom) provide you with tools to make this easier. I recommend
becoming acquainted with them. They will be yours (and our) best tool for
understanding the problem.
** I've run into an issue, where do I start?
Before you file a bug report, there are a number of things you should try first:
+ You'll find [[file:faq.org::Common%20Issues][a list of common issues & errors in the FAQ]]. That is a good place
to start. You can access and search this FAQ from inside Doom with =SPC h d f=
(or =C-h d f= for non-evil users).
+ Run ~doom doctor~ to diagnose any common issues with your environment or
config.
+ Run ~doom refresh~ to ensure the problem isn't caused by missing packages or
outdated autoloads files.
+ See if your issue is mentioned in the Common Issues section below.
+ Search Doom's issue tracker to see if your issue is mentioned there.
+ Ask for help on [[https://discord.gg/bcZ6P3y][our Discord server]]. This may not be immediately available to
everyone, so I won't fault you for skipping this step, but you'll sometimes
find help there quicker. In many cases, Henrik fixes issues.
** 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/bcZ6P3y][our Discord server]]). Before you
do, please generate a backtrace to include with it.
2019-10-29 12:51:04 +08:00
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~:
2019-10-29 12:51:04 +08:00
1. Start Emacs with ~emacs --debug-init~. Use this for errors that occur at
2019-10-29 12:51:04 +08:00
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~
2019-10-29 12:51:04 +08:00
Now that ~debug-on-error~ is on, recreate the error. A window should pop up with
2019-10-29 12:51:04 +08:00
a backtrace.
*** A backtrace from ~bin/doom~
2019-10-29 12:51:04 +08:00
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 refresh
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
2019-10-29 12:51:04 +08:00
"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 plugins 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
2019-10-29 12:51:04 +08:00
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
2019-10-29 12:51:04 +08:00
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
2019-10-29 12:51:04 +08:00
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