#+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]] - [[#on-macos][On macOS]] - [[#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~]] - [[#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 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]] + *GNU ls* (BSD ls on macOS/BSD Linux has some limitations) + *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 *** On macOS 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 macOS, with 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). 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. #+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. *This is essential for macOS users!* 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 necessary for macOS users who open Emacs through an Emacs.app bundle. - ~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 ~ 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: ~export PATH="$HOME/.emacs.d/bin:$PATH"~ #+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 # on macOS or use an app launcher that doesn't launch programs with the correct # 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. *** 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 Then 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 (("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. ** 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. (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~. Use this to disable undesirable packages included with the built-in modules. 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 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! + 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. *** 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. 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 "") [...]) #+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. *** 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. 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 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 "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 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