doomemacs/modules
Brandon Orther e07972cffb Gracefully handle +ivy-tasks match errors
When trying to use +ivy-tasks in one of my projects it was failing w/ error:
`(Stack overflow in regexp matcher)`. This was due to ripgrep searching a folder
in the project root containing a minified bootstrap CSS source map file (which
had a `TODO:` in it). Since that file was a single line of text concatenated
together, the regex was getting passed ~540KB of text.

To make it easier to recognize what is causing +ivy-tasks to fail I wrapped the
failing code in `condition-case-unless-debug` and report the error and the file
causing the error using `message!`. So now if there is a failure during the
extraction of task from the search cmd's results it moves onto the next and
alerts the user in separate pop-up.

To avoid including the bootstrap file in the ripgrep search result, I added a
`.ignore` file to the project that tells `rg` to ignore it.

NOTE: I was surprised that this problem file was include in the ivy-tasks search
because I expected the search to respect projectile ignore settings. Respecting
projectile's ignored/unignored files and directories wouldn't be too difficult
considering projectile provides a robust collection of functions to help support
this. Also projectile's `projectile-ag` function is a great reference.
2017-08-15 00:37:24 -07:00
..
app Add: app/irc: (=irc) if irc workspace exists switch to that 2017-08-06 17:01:32 +02:00
completion Gracefully handle +ivy-tasks match errors 2017-08-15 00:37:24 -07:00
feature Check if the hydra feature is enabled before opening smerge hydra 2017-08-09 11:56:12 -04:00
lang lang/ocaml: adding ml4, mli, mlp to recognized extensions 2017-07-27 11:33:10 -07:00
org Refactor line number implementation 2017-07-19 00:25:05 +02:00
private Fix projectile-find-file not respecting default-directory 2017-07-27 20:22:10 +02:00
tools Fix: tools/eshell: get rid of compile warnings in quit-or-delete-char 2017-07-22 00:15:01 +02:00
ui Rix 'reload last session' button on dashboard 2017-07-26 15:45:01 +02:00
README.org Rename doom/clean-cache => doom/reset (+ make reset) 2017-07-09 22:51:36 +02:00

DOOM modules

Overview

DOOM is comprised of its core files and then its modules. A small list of macros are used to manage and configure plugins, other modules and DOOM Emacs itself.

These macros are:

  • Package management

    • (featurep! MODULE SUBMODULE): returns t if :module submodule is activated.
    • (load! NAME): loads NAME.el, relative to the current file.
    • (require! MODULE SUBMODULE &optional RELOAD-P): activates a module & loads its config.el, if it isn't already loaded.
    • (package! NAME &key recipe pin): declares a package to be installed and where to get it.
    • (depends-on! MODULE SUBMODULE): loads a module's packages.el.
  • Configuration

    • (set! SETTING &rest ARGS): safely cross-configure other modules. Use M-x doom/describe-setting to see what's available.
    • (def-package! NAME &rest PLIST): configure a package (wrapper around use-package).
    • (def-setting! SETTING &rest ARGS): defines a setting other modules can set!.

The TL;DR of this document is:

  • Modules are comprised of: config.el, packages.el, either autoload.el or autoload/*.el, and +*.el files; these are all optional.
  • config.el is the only file loaded when a module is activated, and is where you configure the module and its plugins.
  • packages.el files inform DOOM what plugins to install and where from, using the package! macro. This macro accepts a MELPA-style recipe plist to specify a location other than the ELPA for fetching plugins.
  • Use set! to safely cross-configure modules; doom/describe-setting can help you discover what settings are available.
  • Packages are deferred by default; add :demand t to their def-package! declaration to load them immediately.
  • The private/{user-login-name} module is automatically loaded. It is harmless to keep :private {user-login-name} in your init.el however.
  • private/{user-login-name}/init.el is a special file that is automatically loaded after DOOM core files, but before modules are loaded. Use it to configure DOOM.

Module overview

These modules are in their ideal load order.

:feature
Broad modules that bring essential functionality to Emacs as an editor.
:completion
Swappable completion modules for narrowing down candidate lists quickly.
:ui
Aesthetic modules that affect the Emacs interface or user experience.
:tools
Small modules that add specific, non-essential functionality to Emacs.
:lang
Modules that bring support for a language or group of languages to Emacs.
:org
Modules that affect and extend org-mode.
:app
Large, opinionated modules that transform Emacs' UI to serve a specific purpose.
:private
Private configuration modules that are untracked by version control (except for my personal one; use it as a reference).

Change the doom! block in your init.el file to enable/disable modules on startup. You'll need to restart Emacs.

Don't forget to run make afterwards to ensure that the needed packages are installed (and unneeded ones are uninstalled).

Remember: if you've byte-compiled your config, your changes won't take effect until you recompile or delete the \*.elc files.

The structure of a module

Modules are made up of five optional parts:

config.el
The heart of a module; loaded when the module is activated.
packages.el
Tells DOOM what packages to install and where from. Isn't loaded until package management commands are used.
autoload.el (or autoload/*.el)
Lazily-loaded functions for that module.
+*.el
Additional config files; not automatically loaded.
test/*.el
unit tests for that module, if any.

config.el

config.el is loaded immediately. It is the only file proactively loaded by the DOOM module system. Additional files must be explicitly loaded using load!.

It should expect dependencies (in packages.el) to be installed and available, but shouldn't make assumptions about what modules are activated (use featurep! for this).

Packages should be configured using after! or def-package! (an alias for use-package).

;; from modules/completion/company/config.el
(def-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)
   [...])
  • Packages are deferred by default: add :demand t to def-package! blocks to load them immediately.
  • Use featurep! to test DOOM module availability for conditional packages.
  • Use set! to cross-configure modules safely, e.g. company backends:

    ;; from modules/lang/python/config.el
    (set! :company-backend 'python-mode '(company-anaconda))

packages.el

This file isn't loaded until you use DOOM's package management commands.

Evaluating them should be deterministic, idempotent, and without side-effects (besides updating doom-modules and doom-packages).

Packages are declared with the package! macro, e.g.

;; from modules/lang/org/packages.el
(package! org-bullets)

;; from modules/tools/rotate-text/packages.el
(package! rotate-text :recipe (:fetcher github :repo "debug-ito/rotate-text.el"))

The packages.el of another module can loaded with depends-on!:

;; from modules/feature/file-templates/packages.el
(depends-on! :feature snippets)

autoload.el OR autoload/*.el

Functions in these files are lazily loaded. doom/reload-autoloads will scan these and produce an autoloads.el file, which tells Emacs where to find these functions.

For example:

;; from modules/lang/org/autoload/org.el
;;;###autoload
(defun +org/toggle-checkbox ()
  (interactive)
  [...])

;; from modules/lang/org/autoload/evil.el
;;;###autoload (autoload '+org:attach "lang/org/autoload/evil" nil t)
(evil-define-command +org:attach (&optional uri)
  (interactive "<a>")
  [...])

Autoload files named evil*.el will be ignored if :feature evil isn't loaded.

Additional files

The only convention is to prefix additional elisp files with a +, e.g. modules/feature/version-control/+git.el.

These are not loaded automatically. Use load! to do so.

;; from modules/feature/version-control/config.el
(load +git)

Appendix

  • Macros

    • (featurep! CATEGORY MODULE)
    • (load! NAME)
    • (package! NAME &key recipe pin)
    • (require! CATEGORY MODULE &optional RELOAD-P)
    • (def-package! NAME &rest PLIST)
    • (set! SETTING &rest ARGS)
    • (def-setting! NAME ARGLIST &rest BODY)
  • Commands

    • doom/reload
    • doom/reload-autoloads
    • doom/compile
    • doom/recompile
    • doom/reset
    • doom/clean-compiled