This section is for general questions about the Doom Emacs project and its author. These four sections of our user manual answer this question: 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.
- Why Emacs?
- Why not Emacs?
- Why Doom?
- Why not Doom?
I’ve compiled comparisons to several starter kits in our migration guide.
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.
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.
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!
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.
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 imposingstraight.el
orpackage.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.
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.
Our development resources are listed in our manual.Check out our community resources for a complete list of communities and platforms. I’d recommend our Discourse.
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.
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. For common how-to and configuration questions from Doom users. You’ll find more on our Discourse.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.
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:
- Enable Doom’s doom-module::tools lsp module. (How do I enable modules?)
- 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?) - 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). - Run
$ doom sync
on the command line. - Restart Emacs.
- (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).
- 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).
- 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
).
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"
- Short form:
- 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!
- Select your
setq
statements, - 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), - Then reload the fonts:
M-x doom/reload-font
.
Your changes should take effect immediately.
- 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.
You can update Doom one of two ways:
- The correct way: by running
$ doom upgrade
in the shell and restarting Emacs. - 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.
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.
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
Doom uses the doom-package:display-line-numbers package, which is included with Emacs 26+.
;;; 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 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).
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
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.
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
orautoload/*.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
.
-!
or --force
are the universal “suppress all prompts” switch for most
doom
commands.
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.
Delete $EMACSDIR/.local/straight
and run $ doom sync
.
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)
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.
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 aninit.el
file with adoom!
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.
The three most common causes for $PATH
issues in Doom are:
- 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. - 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.
- 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.
- Make sure you don’t have both
~/.doom.d
and~/.config/doom
directories. Doom will ignore the first if the second exists. - Remember to run
$ doom sync
after making certain changes to your config. Run$ doom help sync
to know exactly when you should use it. - 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.
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
ordoom-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.
You’ll find solutions on the emacswiki.
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:
- 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
- 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++
- 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. - 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.
If you’re getting this error you must reset the owner of
C:\Users\USERNAME\.emacs.d
to your own account:
- Right-click the
~/.emacs.d/server
directory in Windows Explorer, - Click Properties,
- Select the “Security” tab,
- Click the “Advanced” button,
- Select the “Owner” tab,
- Change the owner to your account name.
(source)
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.
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/orgzip
are not installed on your system. Warning macOS and *BSD distro users: you likely have BSD variants of
tar
andgzip
installed by default. Emacs requires the GNU variants! tar
and/orgzip
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.
For folks who want to report bugs and submit pull requests.Our contributor’s manual covers a bunch of ways you can help or support the project.
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
orDockerfile
to do so (if applicable).
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).
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.
Our contributing guide offers a few techniques.
For the generous folks who want to sponsor the project and its author. 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.
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!
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.
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.
Feel free to DM me (Henrik#0666) on Discord, ask on Discourse, or email me at contact@henrik.io.
For questions regarding Doom’s code design, defaults, or conventions.#'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.
This post is a work in progress! However, there’s a post on our Discourse that outlines some of our older techniques.
This post is a work in progress!
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.
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 thatCustomize
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 whereCustomize
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 ofdescribe-*
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.
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)
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:
- 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 (likepyenv
ornvm
) or config framework (likeoh-my-zsh
) could all our startup optimizations in one fell swoop. - 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))
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.