Skip to content

Latest commit

 

History

History
989 lines (800 loc) · 46.2 KB

faq.org

File metadata and controls

989 lines (800 loc) · 46.2 KB

Frequently Asked Questions

󰐃 Our documentation was designed to be read in Doom Emacs (M-x doom/help) or online at https://docs.doomemacs.org. Avoid reading it elsewhere (like Github) where it will be rendered incorrectly.

General

This section is for general questions about the Doom Emacs project and its author.

Is Emacs (or Doom) for me?

These four sections of our user manual answer this question:
  • Why Emacs?
  • Why not Emacs?
  • Why Doom?
  • Why not Doom?

How does Doom compare to <insert starter kit>?

I’ve compiled comparisons to several starter kits in our migration guide.

Is Doom a fork of another starter kit?

No. I started Doom from scratch in 2013 to learn Emacs and Emacs Lisp, and to write a private config for myself. Starter kits were brought to my attention later, when early Doom users vocally compared them.

That’s not to say I’ve taken no inspiration from them since. Doom’s earliest file structure was inspired by Prelude’s, until it was replaced with a module system. Other concepts (like SPC as a leader key) came from Spacemacs or were PRed from migrating users, and were accepted because they seemed sensible.

More similarities (and differences) will no doubt emerge as our userbase grows and more starter kits appear.

Doom claims to be an Emacs framework, not a starter kit. What’s the difference?

I don’t claim to own these terms, but I use them to distinguish Doom’s core (a framework) from Doom’s module library (a starter kit).

My premise is: starter kits and Emacs frameworks have different goals. Where starter kits help you avoid work by doing it for you, an Emacs framework helps you do that work yourself, but more effectively (by providing extra tools, APIs, or organizational systems for writing/debugging). Of course, there will be some crossover.

Who maintains Doom Emacs?

My name is Henrik, I’m this project’s author and its sole maintainer, for the moment. I plan to onboard co-maintainers once the project has:

  • Proper technical documentation for users, contributors, and maintainers. Many important organizational questions haven’t been formally answered or committed to paper: such as our versioning scheme, git conventions, community policies, and code/documentation style guides. Even Doom’s goals aren’t formally stated anywhere.
  • More unit, integration, and package tests. Total coverage isn’t required (or desired), but Emacs issues are complex and esoteric, so some measure of automated sanity checks (and protocols for merges and releases) are needed to spare future maintainers a stroll through a minefield.
  • Resolved its stability, performance, and standardization issues that plague its CLI. Issues too esoteric for me to unleash onto unsuspecting co-maintainers in good conscience. I could live with them when Doom was my private config, but that is no longer the case. It needs to be rewritten.

Most of these issues will be resolved in the final 3.0.0 release.

I am looking for module maintainers though!

Why is the project called “Doom”?

As a kid in the Cretaceous period (1999), the source code of idsoftware’s classic Doom was my first exposure to programming. Totally clueless about C and compilers, all I could do was peek at it from time to time and hope I’d absorb its secrets if I stared hard enough. It didn’t work, but it sure jump-started by gamedev addiction.

So “Doom Emacs” was what you got when you combined childhood, demon-carnage nostalgia, terrible naming sense, and the sneaking suspicion that Emacs is the unwritten tenth circle Dante censored for humanity’s protection.

I’ve doomed us all.

Why does Doom use straight.el and not package.el?

package.el simply doesn’t cut it. Its flaws become apparent the more packages you manage, the more complex your config becomes, and how often those packages see updates:

No disaster recovery
When things go wrong, we don’t always have time to deal with it. Or we need to wait for upstream to deploy a fix. While we wait, we still have work to do, but now what? Emacs is broken! package.el doesn’t give you any options to roll back, so you have to deal with it, and now. Or hope your old config was backed up.

Though Doom doesn’t have a ‘doom rollback’ command (yet), the ability to quickly checkout an old commit of a problematic package (or Doom itself), without the overhead of forking and/or maintaining a local copy, is priceless.

Rolling release or bust
package.el installs the latest version of every package, or none at all. There’s no rollback, no pinning to a stable ref, and no git history to peek into. It offers little reproducibility; wiping/losing/copying your config becomes a gamble if you aren’t constantly backing up your packages (then recompiling them if you’re up/downgrading Emacs).

melpa-stable was well intentioned, but it offers no guarantees or standards on how/when maintainers tag their projects. I’d rather the user decide for themselves, because they’re the ones in the trenches.

Can’t install packages from superior sources
Often, a crucial fix sits in a pull request somewhere for too long, a package becomes outdated through official channels, or a superior fork springs up somewhere other than an ELPA. package.el cannot reach those sources.
Slow at startup (by default)
Initializing package.el can be expensive, depending on the number (and complexity) of installed packages – especially for batch scripts. package-quickstart helps, up to a point, but Doom’s package manager can do better with the assumptions available to its monolithic ecosystem. All without imposing straight.el or package.el on your runtime environments.

Package management needs to be easier, because Emacs is hard enough already. Doom fills these gaps with straight.el’s help, and beyond.

Granted, you can get most of the above with a little Git know-how, but it stops being convenient as you reach package 5 or 15, your tenacity permitting.

Why is startup time important? Why not use the daemon?

It isn’t, but it gets a disproportional amount of attention because it’s the first thing Doom’s users notice. Doom is perfectly compatible with the daemon and I don’t intend to discourage its use. If I had to say something about it, it’s that I’m unhappy that a daemon is needed at all to get sane startup times out of Emacs.

It’s left to the user to know or care about optimal load paths, and to implement them, but that’s a lot to ask when the problem domain is so vast, esoteric, and a moving target (with a high cost-to-benefit). Who has the time to inspect, much less fix, all their packages? And maintain that effort across Emacs or package updates? It’s easier to use the daemon, so people do.

That said, there’s no one to blame for that. I consider Doom’s effort, the daemon, even native compilation (though all excellent endeavors) stop-gap measures for a deeper, underlying issue in Emacs that needs smarter people than I to address.

Rather than startup time, runtime performance is a bigger priority, though the two rarely stray far from each other.

Where do I follow the development of the project?

Our development resources are listed in our manual.

Where do I report issues, request features, or get user support?

Check out our community resources for a complete list of communities and platforms. I’d recommend our Discourse.

I don’t like Discord. Can Doom move to IRC/Telegram/Matrix/other?

This is requested a lot–and not always so kindly. We have a Discourse and there are plans for a Matrix space, but that’s as many platforms as I have bandwidth for. Please do not ask me to reconsider.

How do I add a question to the FAQ?

There is no submission process for FAQs. Our community leaders select them from our Discord, Discourse, and Github communities (sometimes elsewhere) based on frequency (actual or anticipated). Ask your questions there. If they make the cut they will naturally find their way here.

How do I…

For common how-to and configuration questions from Doom users. You’ll find more on our Discourse.

Find out what version of Doom am I running?

Use M-x doom/info or $ doom info to produce detailed information about your installation and environment.

Alternatively, M-x doom/version or $ doom version will only list the versions of installed Doom components.

The installed version of Doom core is also displayed in the Doom dashboard’s mode-line.

Turn (Doom) Emacs into a <insert language here> IDE with LSP?

This is frequently asked: how to transform Doom Emacs into an IDE for some programming language. In almost all cases, it’s recommended that you enable Doom’s LSP support and install a supported LSP client.

This provides code completion, lookup {definition,references,documentation} functionality, and syntax checking, all in one:

  1. Enable Doom’s doom-module::tools lsp module. (How do I enable modules?)
  2. Enable the +lsp flag on the :lang module corresponding to the language you want LSP support for. E.g. For python, enable doom-module::lang python +lsp. For rust, enable doom-module::lang rust +lsp. (How do I enable module flags?)
  3. Install a supported LSP client on your system using your OS package manager OR from within Emacs using M-x lsp-install-server (warning: not all servers can be installed this way).
  4. Run $ doom sync on the command line.
  5. Restart Emacs.
  6. (Optional) If Emacs fails to find your LSP server, you may need to run $ doom env to regenerate your envvar file (which contains your $PATH, which tells Emacs where to find programs on your system).

Potential issues

  1. Some language modules lack LSP support (either because it doesn’t exist or I’m not aware of it – let me know!). If you’re certain a language is supported by doom-package:lsp-mode, simply adding fn:lsp! to that major mode’s hook will be enough to enable it:
    ;; Remember to replace MAJOR-MODE with the major mode that powers the language.
    ;; E.g. `ruby-mode-local-vars-hook' or `python-mode-local-vars-hook'
    (add-hook 'MAJOR-MODE-local-vars-hook #'lsp! 'append)
    
    ;; For Elisp gurus: Doom provides MAJOR-MODE-local-vars-hook, and we use it
    ;; instead of MAJOR-MODE-hook because it runs later in the mode's startup
    ;; process (giving other functionality or packages -- like direnv -- time to
    ;; configure the LSP client).
        
  2. Some languages have alternatives that are superior to the LSP offerings (such as Cider for Clojure or Sly for Common Lisp).

When in doubt, check that language module’s documentation! Look up a module’s documentation with <help> d m (or M-x doom/help-modules).

Change my fonts

Doom exposes a couple variables for setting fonts. They are:

  • var:doom-font: the primary font for Emacs to use.
  • var:doom-variable-pitch-font: used for non-monospace fonts (e.g. when using variable-pitch-mode or mixed-pitch-mode). Popular for text modes, like Org or Markdown.
  • var:doom-emoji-font: used for rendering emoji. Only needed if you want to use a font other than your operating system’s default.
  • var:doom-symbol-font: used for rendering symbols.
  • var:doom-serif-font: the sans-serif font to use wherever the face:fixed-pitch-serif face is used.
  • var:doom-big-font: the large font to use when fn:doom-big-font-mode is active.

Each of these variables accept one of:

  • A font-spec object: (font-spec :family "FontName" :size 12.0 :weight 'light)
  • An xft font string:
    • Short form: ~”JetBrainsMono-12”~
    • Long form: ~”Terminus (TTF):pixelsize=12:antialias=off”~
  • An XLFD string: ~”-*-Fira Code-regular-normal-normal-*-11-*-*-*-*-*-*-*”~

For example:

;; in $DOOMDIR/config.el
(setq doom-font (font-spec :family "JetBrainsMono" :size 12 :weight 'light)
      doom-variable-pitch-font (font-spec :family "DejaVu Sans" :size 13)
      doom-symbol-font (font-spec :family "JuliaMono")
      doom-big-font (font-spec :family "JetBrainsMono" :size 24))

󰐃 If you or Emacs can’t find your font, use M-x describe-font to look them up, or run $ fc-list to see all the available fonts on your system. Font issues are /rarely/ Doom issues!

To change fonts on the fly:

  1. Select your setq statements,
  2. Evaluate them with M-x eval-region (evil users can use the gr operator to evaluate regions of elisp, non-evil users can use C-x C-e),
  3. Then reload the fonts: M-x doom/reload-font.

Your changes should take effect immediately.

Change, customize, or make themes?

  • To change themes, add (setq doom-theme 'name-of-theme) to $DOOMDIR/config.el.
  • To switch themes on-the-fly, type <help> t or M-x load-theme.
  • To customize or write themes, see our guide on the Discourse.

Properly update Doom?

You can update Doom one of two ways:

  1. The correct way: by running $ doom upgrade in the shell and restarting Emacs.
  2. The manual way (if doom upgrade is broken for some reason):
    $ cd ~/.emacs.d
    $ git pull       # pull the latest version of Doom's source
    $ doom sync -u   # update Doom's packages and 'doom sync'
        

This may change in the future, so $ doom upgrade will always be the safest option. That said, $ doom help upgrade will always document the correct procedure for manual updates if you need it.

Bind my own keys (or change existing ones)?

Emacs provides a couple functions to bind keys:

  • define-key KEYMAP KEY DEF
  • global-set-key KEY DEF
  • local-set-key KEY DEF
  • evil-define-key STATES KEYMAP KEY DEF &rest ...

However, Doom provides a more general map! macro, to conveniently wrap up the above four into a more succinct syntax. Comprehensive examples of map!’s usage can be found in its documentation (keyboard shortcut: <help> f map\!).

There are also live examples map!’s usage in config/default/+evil-bindings.el.

Unfortunately, binding keys in Emacs can be a complicated affair. A more detailed guide on keys, keymaps, and keymap precedence can be found on our Discourse.

Change or alias the leader or localleader key?

This is documented in more detail in our user manual:

  • How to change your leader keys
  • How to bind new keys under the leader prefix
  • How to bind aliases for your leader / localleader prefix

Change the style of (or disable) line-numbers?

Doom uses the doom-package:display-line-numbers package, which is included with Emacs 26+.

To disable line numbers entirely

;;; in $DOOMDIR/config.el
(setq display-line-numbers-type nil)
;; or
(remove-hook! '(prog-mode-hook text-mode-hook conf-mode-hook)
              #'display-line-numbers-mode)

To switch to relative line numbers

To change the style of line numbers, change the value of the display-line-numbers-type variable. It accepts the following values:

t            normal line numbers
'relative    relative line numbers
'visual      relative line numbers in screen space
nil          no line numbers

For example:

;;; add to $DOOMDIR/config.el
(setq display-line-numbers-type 'relative)

You’ll find more precise documentation on the variable through <help> v display-line-numbers-type (<help> is SPC h for doom-package:evil users, C-h otherwise).

To cycle through different styles of line numbers

Use M-x doom/toggle-line-numbers (bound to <leader> t l by default) to cycle through the available line number styles in the current buffer.

E.g. normal -> relative -> visual -> disabled -> normal

Disable Evil (vim emulation)?

By disabling the doom-module::editor evil module (how to toggle modules).

Read the ”Removing evil-mode” section in the module’s documentation for precise instructions.

Know when to run $ doom sync?

As a rule of thumb, run $ doom sync whenever you:
  • Update Doom with $ git pull instead of $ doom upgrade,
  • Change your doom! block in $DOOMDIR/init.el,
  • Change autoload.el or autoload/*.el files in any module (or $DOOMDIR),
  • Change the packages.el file in any module (or $DOOMDIR).
  • Install an Emacs package or dependency outside of Emacs (i.e. through your OS package manager).

If anything is misbehaving, it’s a good idea to run $ doom sync first, to rule out any issues with missing packages or autoloads.

This command is never needed for changes to $DOOMDIR/config.el.

Suppress confirmation prompts when executing a doom command?

-! or --force are the universal “suppress all prompts” switch for most doom commands.

Copy or sync my config to another system?

Short answer: it is safe to sync $DOOMDIR across systems, but not $EMACSDIR. Once moved, use $ doom sync to ensure everything is set up correctly.

Long answer: packages can contain baked-in absolute paths and non-portable byte-code. It is never a good idea to mirror it across multiple systems, unless they are all the same (same OS, same version of Emacs, same paths). Most issues should be solved by running $ doom sync on the other end, once moved.

Start over, in case something went terribly wrong?

Delete $EMACSDIR/.local/straight and run $ doom sync.

Restore the s and S keys to their default vim behavior (#1307)

s and S have been intentionally replaced with the doom-package:evil-snipe plugin, which provides 2-character versions of the f/F/t/T motion keys, ala vim-seek or vim-sneak.

These keys were changed because they are redundant with cl and cc respectively (and the new behavior was deemed more useful).

If you still want to restore the old behavior, simply disable evil-snipe-mode:

;; in $DOOMDIR/config.el
(remove-hook 'doom-first-input-hook #'evil-snipe-mode)

Common issues

For problems that come up especially often. You’ll find more on our Discourse and Github issue tracker. Consult our troubleshooting guide for help debugging issues.

Doom and/or Emacs is slow

The answer changes from version to version (of Emacs), and is often updated with new information, so this is answered on Discourse instead.

Doom starts up with a vanilla splash screen

The most common cause for this is a ~/.emacs file. If it exists, Emacs will read this file instead of the ~/.emacs.d directory, ignoring Doom altogether.

If this isn’t the case, run $ doom doctor. It can detect a variety of common issues and may offer you clues.

I see a scratch buffer at startup instead of the dashboard

The common explanations for this are:

  • Emacs can’t find your private doom config (in ~/.doom.d or ~/.config/doom). Make sure only one of these two folders exist, and that it has an init.el file with a doom! block. Running $ doom install will create these files and directories for you.
  • An error occurred while starting up Doom. Use C-h e to inspect Emacs’ log. Search it for errors or warnings. If you find one, producing a backtrace from the error can shed more light on it (and will be required if you ask the community for help debugging it).
  • You have disabled the doom-module::ui doom-dashboard module. Read about what Doom modules are and how to toggle them.

If you’re still stuck, run $ doom doctor. It can detect a variety of common issues and may give you some clues as to what is wrong.

Doom fails to find executables (or inherit my shell’s $PATH)

The three most common causes for $PATH issues in Doom are:

  1. Your shell configuration doesn’t configure $PATH correctly. Run $ which <PROGRAM> in your shell. If it doesn’t emit the path you expect (or any path at all) then you need to modify you shell config to do so correctly.
  2. Your app launcher (rofi, albert, docky, dmenu, sxhkd, etc) is launching Emacs with the wrong shell, either because it defaults to a different shell from the one you actively use or the app launcher itself inherits the wrong environment because it is being launched from the wrong shell.
  3. You’re a Mac user launching Emacs from an Emacs.app file. MacOS launches these apps from an isolated environment.

As long as your shell is properly configured, there is a simple solution to issues #1 and #3: generate an envvar file by running $ doom env. This scrapes your shell environment into a file that is loaded when Doom Emacs starts up. Run $ doom help env for details on how this works.

For issue #2, you’ll need to investigate your launcher. There are too many launchers write a walkthrough for, you’ll have better luck asking about it on our Discord or Discourse.

Changes to my config aren’t taking effect

  1. Make sure you don’t have both ~/.doom.d and ~/.config/doom directories. Doom will ignore the first if the second exists.
  2. Remember to run $ doom sync after making certain changes to your config. Run $ doom help sync to know exactly when you should use it.
  3. If you are reconfiguring a package, make sure you’ve deferred your settings until the package loads with the after! macro:
    (after! magit
      (setq magit-repository-directories '(("~/projects" . 2))
            magit-save-repository-buffers nil))
        

    There are two exceptions to this rule:

    ;; Setting file/directory variables don't (and shouldn't be) deferred. e.g.
    (setq org-directory "~/org")
    
    ;; Don't defer setting variables whose documentation explicitly say they must
    ;; be set *before* the package is loaded. e.g.
    (setq evil-respect-visual-line-mode t)
        

If none of these solve your issue, try $ doom doctor. It will detect a variety of common issues, and may give you some clues as to what is wrong. Otherwise, consult the community.

Doom crashes and/or freezes

Here are a few common causes for random crashes:

  • Some fonts cause Emacs to crash when they lack support for a particular glyph (typically symbols). Try changing your font by changing doom-font or doom-symbol-font.
  • Ligatures can cause Emacs to crash. Try a different ligature font or disable the doom-module::ui ligatures module altogether.
  • On some systems (particularly MacOS), manipulating the fringes or window margins can cause Emacs to crash. This is most prominent in Doom’s Dashboard (which uses the margins to center its contents), in org-mode buffers (which uses org-indent-mode to create virtual indentation), or Magit (whose fringes are adjusted on the fly).

    There is currently no known fix for this, as it can’t be reliably reproduced. Your best bet is to reinstall/rebuild Emacs or disable the errant plugins/modules.

    E.g. To disable org-indent-mode:

    ;; in $DOOMDIR/config.el
    (after! org
      (setq org-startup-indented nil))
        

    Or disable the doom-module::ui doom-dashboard and doom-module::tools magit modules (see #1170).

If these don’t help, check our troubleshooting guides for hard crashes or freezes/hangs.

TRAMP connections hang forever when connecting

You’ll find solutions on the emacswiki.

Why do I see ugly indentation highlights for tabs?

Doom highlights non-standard indentation. i.e. Indentation that doesn’t match the indent style you’ve set for that file. Spaces are Doom’s default style for most languages (excluding languages where tabs are the norm, like Go).

There are a couple ways to address this:

  1. Fix your indentation! If it’s highlighted, you have tabs when you should have spaces (or spaces when you should be using tabs).

    Two easy commands for that:

    • M-x tabify
    • M-x untabify
  2. Change indent-tabs-mode (nil = spaces, t = tabs) in $DOOMDIR/config.el:
    ;; use tab indentation everywhere
    (setq-default indent-tabs-mode t)
    
    ;; or only in certain modes
    (setq-hook! 'sh-mode-hook indent-tabs-mode t) ; shell scripts
    (setq-hook! '(c-mode-hook c++-mode-hook) indent-tabs-mode t)  ; C/C++
        
  3. Use editorconfig to configure code style on a per-project basis. If you enable Doom’s doom-module::tools editorconfig module, Doom will recognize .editorconfigrc files.
  4. Or trust in doom-package:dtrt-indent; a plugin Doom uses to analyze and detect indentation when you open a file (that isn’t in a project with an editorconfig file). This isn’t foolproof, and won’t work for files that have no content in them, but it can help in one-off scenarios.

“The directory ~/.emacs.d/server is unsafe” error at startup (Windows only)

If you’re getting this error you must reset the owner of C:\Users\USERNAME\.emacs.d to your own account:

  1. Right-click the ~/.emacs.d/server directory in Windows Explorer,
  2. Click Properties,
  3. Select the “Security” tab,
  4. Click the “Advanced” button,
  5. Select the “Owner” tab,
  6. Change the owner to your account name.

(source)

My new keybinds don’t work

Emacs has a complex and hierarchical keybinding system. If a global keybind doesn’t take effect, it’s likely that another keymap is in effect with higher priority than the global keymap. For example, non-evil users may have tried something like this, to rebind C-left and C-right:

(map! "<C-left>"  #'something
      "<C-right>" #'something)

Just to find that the rebinding had no effect (i.e. C-h k C-left reports that it’s still bound to sp-backward-slurp-sexp). That’s because these keys are bound in smartparens-mode-map. They need to be unbound for your global keybinds to work:

(map! :after smartparens
      :map smartparens-mode-map
      [C-right] nil
      [C-left] nil)

󰐃 I use [C-left] because it is easier to type than “<C-left>”, but they are equivalent; two different ways to refer to the same key.

Recursive load error on startup

If you see an error like:

Error: error ("Recursive load"
  "/Applications/Emacs.app/Contents/Resources/lisp/jka-compr.el.gz"
  "/Applications/Emacs.app/Contents/Resources/lisp/jka-compr.el.gz"
  "/Applications/Emacs.app/Contents/Resources/lisp/jka-compr.el.gz"
  "/Applications/Emacs.app/Contents/Resources/lisp/jka-compr.el.gz"
  "/Applications/Emacs.app/Contents/Resources/lisp/jka-compr.el.gz"
  "/Applications/Emacs.app/Contents/Resources/lisp/obsolete/cl.el.gz")

Then these are the three most common explanations:

  • GNU tar and/or gzip are not installed on your system.

    Warning macOS and *BSD distro users: you likely have BSD variants of tar and gzip installed by default. Emacs requires the GNU variants!

  • tar and/or gzip aren’t in your $PATH, somehow. Once you’ve corrected your shell config, run $ doom env to regenerate your envvar file (containing the $PATH Doom will see), then restart Emacs.
  • (macOS users only) You’ve installed Emacs from one of the sources I recommend you avoid. For example, emacsformacosx.com. Our user manual outlines where you should acquire Emacs from.

If none of the above help, then file a bug report.

Contributors

For folks who want to report bugs and submit pull requests.

How can I contribute to the project?

Our contributor’s manual covers a bunch of ways you can help or support the project.

How do I get my pull request processed ASAP?

The project does not have a dedicated support team – only one overworked meatball and a handful of busy volunteers – so there may be delays processing your PR. Sometimes this is unavoidable, but there are some measures you can take to mitigate these delays:
  • Ensure there are no open PRs that tackle the same issue. If yours is intended to replace an existing one, please mention it.
  • Include an explanation: why the PR is necessary, what it fixes, any gotchas I should be aware of, and issues it affects.
  • Be acquainted with our git commit conventions. Good commit etiquette is required. Do not be afraid to rebase or force-push to tidy up your PR, once it is ready for review.
  • Adhere to our code, documentation, and keybind conventions, where applicable.
  • Ensure you’ve targeted the master branch.
  • Keep your PR focused. It shouldn’t do too much in too many places, if that can be avoided.
  • If your PR introduces new tools, dependencies, or packages, I’m going to test them. It takes time to research them, acquire them, learn how to use them, and finally test them in the context of your PR. You can speed this up by including steps to set up an MVE with some mock inputs and expected results.

    Extra points if you supply a shell.nix or Dockerfile to do so (if applicable).

My PR was approved but not merged, what gives?

I approve PRs in bulk, often days before merging them. This is done to:

  • Allow me to merge them when I have time to respond to regressions they may cause.
  • Give me a second chance to catch issues,
  • Give the submitter extra time to correct mistakes,
  • Give users a change to test it themselves,

If your PR was approved, you only have to wait for Henrik to get off his glorious Canadian behind and merge it. If it’s been a week or so with no progress, feel free to ping him in-thread or on Discord (in the #contributing channel).

Why was my issue deleted or tagged “delete me”?

Due to the sheer complexity of Emacs, our issue tracker receives many false-positive, redundant, vague, or “support request”-type issues. This is a problem because they pollute our search results, make it difficult for users and maintainers to track real issues, and cost much effort to process; taking away time from real issues or project development.

Since Doom’s “support team” only consists of one overworked maintainer and a handful of busy volunteers, we have to be strict; we don’t have the capacity to chase issues that aren’t actionable, immediately reproducible, or cannot be investigated within a reasonable amount of time (which includes issues that are poorly researched, vague, or open-ended).

Posts that fall into these categories will be immediately closed, tagged for deletion, and given a brief explanation why, including instructions to overturn or contest the ruling if I’ve made a mistake.

Some examples:

  • Performance issues without a clear, verifiable, or reproducible cause.
  • Behavior that can’t be reproduced in vanilla Doom.
  • Behavior that can be reproduced in vanilla Emacs.
  • An open-ended request to improve something without concrete goals.
  • An issue that consists solely of “X doesn’t work” and little else.
  • An issue that omits important information, like steps to reproduce or system information.
  • A post asking how to configure or use Emacs to achieve some effect (our issue tracker is for bug reports, not support; ask on Discord or Discourse instead).
  • A convoluted and unfocused issue that present multiple issues in one.
  • A rude user that won’t meet us half way and/or expects us to do all the work for them.

To ensure your issue makes the cut, please consult ”How do I ensure my issue gets processed ASAP?” above.

How do I create and maintain a PR branch for Doom Emacs?

Our contributing guide offers a few techniques.

Sponsors

For the generous folks who want to sponsor the project and its author.

How do I sponsor the project?

Consider becoming my Github sponsor. If you’re not a fan of Github sponsorship, my page lists a couple alternatives.

If you do decide to sponsor me, thank you for your support! It is a big help, and directly translates to more hours on my Doom, Emacs-related, or open-source capers.

How do I claim my tier rewards?

Once you have sponsored, you’ll receive an automated email telling you how, but in case you didn’t: email me at contact@henrik.io or DM me on Discord (@Henrik#0666) with your github username and (optionally) Discourse username, and I’ll help sort you out!

Are there other ways to support the project or get sponsorship perks?

Yes! By becoming a module maintainer, community moderator, or regular you get the same perks as sponsors on the 25/mo tier. Here’s what they do:
  • Module maintainers look after one or more Doom modules. They become my consultants for that module(s)’ ecosystem, packages, and implementation, and issues about them. Some Emacs Lisp expertise is helpful, but it’s more important that you are knowledgeable about your chosen module’s ecosystem.
  • Moderators look after our Github, Discord, and/or Discourse communities. They keep our issue tracker, github projects, and repos organized, and they keep the peace by warning/banning bad actors. They’re held to a higher standard, however, as they represent us.
  • Regulars are pillars of our community; they’re folks that frequent our Discord and/or Discourse, are active, helpful, and friendly. This is the only role you can’t apply for, but we keep a eye out for folks to give it to!

If code, documentation, or bug reports are more your thing, visit our contributing manual for ideas.

What is the difference between “first shake” and “first priority”?

Some of my Sponsor tier rewards offer “first shake” or “first priority” on open issues/feature requests. To explain what these mean:

  • Issues that get first shake get triaged and investigated before other issues, and if it can be resolved in one sitting, I will.
  • Issues that get first priority get entirely resolved before I move on to anything else.

That said, the exception to these rules are issues that are extraordinarily difficult, outside my expertise, or depend on other development efforts to resolve.

Folks that depend on Doom for their work or businesses would benefit from getting first priority, to ensure their issues are resolved ASAP. Or check out my one-time tiers to hire me for dedicated support.

I have a question, comment, or complaint about sponsorships…

Feel free to DM me (Henrik#0666) on Discord, ask on Discourse, or email me at contact@henrik.io.

Technical

For questions regarding Doom’s code design, defaults, or conventions.

Why does Doom sharp-quote function symbols?

#'symbol is short for (function symbol), the same way ~’symbol~ is short for (quote symbol).

I use it to indicate to the byte-compiler (or human readers) that a symbol will be treated as a function rather than literal data.

However, at runtime, the sharp-quote serves no functional purpose like it does in other lisps. (funcall 'some-function) will function identically to (funcall #'some-function). The sole difference is at compile-time: the byte-compiler performs additional checks on function symbols and will warn if a function isn’t known to be defined where it’s used.

There’s more about quoting in the Emacs manual.

How does Doom Emacs start up so quickly?

󱌣 This post is a work in progress! However, there’s a post on our Discourse that outlines some of our older techniques.

How does Doom Emacs improve runtime performance?

󱌣 This post is a work in progress!

Why does Doom not use dash, f, s, or similar libraries?

subr-x, seq, map, pcase, and cl-lib are all built into Emacs and, since Emacs 27.1 (the minimum version Doom supports), have made Dash and co (mostly) redundant. One of Doom’s goals is to prefer native functionality where possible or trivial. That said, many third-party packages depend on them, so chances are they are already installed on your system.

Why does Doom discourage the use of M-x customize?

Customize exists so that you don’t need to be a Lisp programmer to configure Emacs. It’s helpful to beginners (with both configuration and discovery), but I think it should only serve as a stopgap until you are comfortable writing and navigating Emacs Lisp, then abandoned. Here’s why:

  • The way it applies its settings (through theme variables) defies conventional load order, which is troublesome to support in middleware like Doom (or user configuration) when lazy loading is involved.
  • I don’t see many instances in the wild where this load-order quirk is accommodated. I think this is because those writing/offering that code are Lisp programmers, who don’t use Customize and may not be exposed to its quirks, but for beginners this is frustration waiting to happen.
  • Customize works flawlessly if it is the sole source of truth for your Emacs configuration, but all Emacs configs eventually take on Lisp. At this point you acquire a second source of truth that Customize is happy to (quietly) override.
  • Without its unparalleled extensibility, I believe Emacs isn’t particularly interesting or effective software. And Customize exposes only a superficial portion of that extensibility. Learning Lisp is inevitable if you want to deal with issues or tweak where Customize can’t, and Doom wants to help you face Lisp, rather than work around it. Otherwise, you may be happier using modern, better polished, and less-DIY competitors.
  • Customize’s commands are safe for read-only use (e.g. to browse/search settings), but I’m not convinced it can be compete with Emacs’ self-documentating facilities. For example, its library of describe-* commands already set the bar pretty high.

All that said, I take no steps to disable or cripple Customize in Doom (besides a warning here and there, and hiding it in some menus where it is known to cause issues). If used sparingly, you may not even run into these issues.

Why no expand-region for evil users (by default)?

I believe doom-package:expand-region is redundant with and less precise than evil’s text objects and motions.

  • There’s a text object for every “step” of expansion that expand-region provides (and more).
    • To select the word at point = v i w
    • symbol at point = v i o
    • line at point = V
    • the block at point (by indentation) = v i i
    • the block at point (by braces) = v i b
    • sentence at point = v i s
    • paragraph = v i p
    • etc.
  • Selection expansion can be emulated by using text objects consecutively: v i w to select a word, followed by i o to expand to a symbol, then i b expands to the surrounding brackets/parentheses, etc. There is no reverse of this however; you’d have to restart visual mode.

The doom-package:expand-region way dictates you start at some point and expand/contract until you have what you want selected. The vim/evil way would rather you select exactly what you want from the get go. In the rare event a text object fails you, a combination of o (swaps your cursor between the two ends of the region) and motion keys can adjust the ends of your selection.

󰐃 There are also text objects for xml tags (x), C-style function arguments (a), angle brackets, and single/double quotes.

This is certainly more to remember compared to a pair of expand and contract commands, but text objects (and motions) are the bread and butter of vim’s modal editing paradigm. Vimmers will feel right at home. To everyone else: mastering them will have a far-reaching effect on your effectiveness in vim environments. I highly recommend putting in the time to learn them.

That said, if you aren’t convinced, it is trivial to install doom-package:expand-region and binds keys to it yourself:

;;; in $DOOMDIR/packages.el
(package! expand-region)

;;; in $DOOMDIR/config.el
(map! :nv "C-=" #'er/contract-region
      :nv "C-+" #'er/expand-region)

Why doom env instead of exec-path-from-shell?

For some context: there are scenarios where Emacs launches in an isolated environment where it cannot see your $PATH or other needed environment variables. This affects macOS users (all Emacs.app bundles launch Emacs in an isolated environment), Linux users who misconfigure their launchers to use the wrong shell, or Windows users who may have no shell environment at all.

doom-package:exec-path-from-shell was written to mitigate this, by polling the shell at startup for those environment variables. $ doom env was written as more reliable (and slightly faster) substitute. Here’s why it’s better:

  1. doom-package:exec-path-from-shell must spawn (at least) one process at startup to scrape your shell environment. This can be slow depending on the user’s shell configuration and may fail on non-standard shells (like fish). A single program (like pyenv or nvm) or config framework (like oh-my-zsh) could all our startup optimizations in one fell swoop.
  2. doom-package:exec-path-from-shell takes a whitelist approach and captures only $PATH and $MANPATH by default. You must be proactive in order to capture all the envvars relevant to your development environment and tools.

    $ doom env takes the blacklist approach and captures all of your shell environment. This front loads the debugging process, which is nicer than dealing with it later, while you’re getting work done.

That said, if you still want var:exec-path-from-shell, it is trivial to install yourself:

;;; in $DOOMDIR/packages.el
(package! exec-path-from-shell)

;;; in $DOOMDIR/config.el
(require 'exec-path-from-shell)
(when (display-graphic-p)
  (exec-path-from-shell-initialize))

Why ws-butler over whitespace-cleanup or delete-trailing-whitespace?

I believe doom-package:ws-butler is less imposing on teammates/project maintainers; it only cleans up whitespace on the lines you’ve touched.

You know the story: a PR with 99 whitespace adjustments around a one-line contribution. Why? Because they added fn:delete-trailing-whitespace (or fn:whitespace-cleanup) to var:before-save-hook, which mutates entire buffers.

Automated processes that mutate entire files (or worse, whole projects) should be deliberately invoked, and by someone privvy to the consequences, rather than automated. ws-butler achieves that balance by only cleaning whitespace on lines that you have modified since opening the file.