diff --git a/docs/getting_started.org b/docs/getting_started.org new file mode 100644 index 000000000..d65db0fb8 --- /dev/null +++ b/docs/getting_started.org @@ -0,0 +1,1213 @@ +#+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]] + - [[#acquiring-a-backtrace][Acquiring a backtrace]] + - [[#enabling-debug-on-error-1][Enabling ~debug-on-error~]] + - [[#a-backtrace-from-bindoom-1][A backtrace from ~bin/doom~]] + - [[#use-the-sandbox][Use the 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. [[https://www.reddit.com/r/emacs/comments/6bw35d/doom_an_emacsd_to_espouse_and_surpass_vim_in_any/dhtw32t/][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-profile.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 a lispyville.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 undesireable 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 acn 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 +*** 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 popuplate 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 preferrable 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 +*** Acquiring a backtrace +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~ + +To acquire a backtrace from an error emitted from `bin/doom`, re-run the same +command with the ~-d~ / ~--debug~ switches or the `DEBUG` environment variable: + +#+BEGIN_SRC sh +doom -d refresh +doom --debug install +DEBUG=1 doom update +#+END_SRC + +*Note:* switch order is important. ~-d~ / ~--debug~ /must/ come right after +~doom~. + +*** Use the 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 + +*** Bisecting your private config +*** Bisecting Doom Emacs diff --git a/docs/index.org b/docs/index.org index 0ffd9f812..16711fe21 100644 --- a/docs/index.org +++ b/docs/index.org @@ -39,7 +39,11 @@ with = d /=. * TODO Release Notes * Documentation -** TODO Getting Started +** [[file:getting_started.org][Getting Started]] +- [[file:getting_started.org::*Install][Install]] - How to install Emacs, Doom and its plugins +- [[file:getting_started.org::*Update][Update]] - Keep Doom and its packages up-to-date +- [[file:getting_started.org::*Customize][Customize]] - A primer on customizing and reconfiguring Doom +- [[file:getting_started.org::*Troubleshoot][Troubleshoot]] - How to debug Emacs & Doom, find help or look up documentation ** [[file:faq.org][Frequently Asked Questions]] - [[file:faq.org::*General][General]]