fix: add :depth field to modules

This introduces a depth field for modules so that they may dictate their
load order explicitly, it also treats depths <= -100 or >= 100 as
special depths, which will be loaded early, before their respective
doom-{before,after}-module-{init,config}-hook. This permits psuedo
modules like :core and :user modules to be treated as normal modules
without too many special cases.

This also fixes a module load order issue on Emacs 29 (#6813), caused by
emacs-mirror/emacs@4311bd0bd7, which changed the return value order of
hash-table-{keys,values} causing modules to be loaded in reverse order;
resulting in the loss of evil keybinds, among other things.

Other notable changes:
- Changes the data structure for module data caches from a list to a
  vector. Uses less memory and permits faster lookups. Also adds two
  depth fields to the front of it.
- Changes the signature of doom-module-list and doom-package-list.
- Renames doom--read-packages -> doom-packages--read for consistency
  with naming convention.
- Add doom-module-depth function.
- Adds a temporary doom-core-dir/init.el file, which is responsible for
  loading doom-*.el.

Fix: #6813
Ref: emacs-mirror/emacs@4311bd0bd7
This commit is contained in:
Henrik Lissner 2022-09-23 18:55:20 +02:00
parent 772f9f26d9
commit 5a5195b84d
No known key found for this signature in database
GPG key ID: B60957CA074D39A3
9 changed files with 250 additions and 178 deletions

View file

@ -302,14 +302,12 @@ SEE ALSO:
;; (load! "test" dir)
)
(let ((cli-file "cli"))
(let ((cli-file "cli.el"))
(defcli-group! "Module commands"
(dolist (key (doom-module-list))
(when-let (path (doom-module-expand-path (car key) (cdr key) cli-file))
(defcli-group! :prefix (format "+%s" (cdr key))
(doom-load path t)))))
(load! cli-file doom-user-dir t))
(when-let (path (doom-module-locate-path (car key) (cdr key) cli-file))
(defcli-group! :prefix (if (cdr key) (format "+%s" (cdr key)))
(doom-load (file-name-sans-extension path)))))))
;; Allow per-project Doom settings in .doom files.
(let (doomrc)

View file

@ -236,41 +236,40 @@ in."
(when doom-modules
(print! (start "Checking your enabled modules..."))
(advice-add #'require :around #'doom-shut-up-a)
(maphash (lambda (key plist)
(let (doom-local-errors
doom-local-warnings)
(let (doom-doctor--errors
doom-doctor--warnings)
(condition-case-unless-debug ex
(let ((doom--current-module key)
(doom--current-flags (plist-get plist :flags))
(doctor-file (doom-module-expand-path (car key) (cdr key) "doctor.el"))
(packages-file (doom-module-expand-path (car key) (cdr key) "packages.el")))
(cl-loop with doom-output-indent = 6
for name in (let* (doom-packages
doom-disabled-packages)
(load packages-file 'noerror 'nomessage)
(mapcar #'car doom-packages))
unless (or (doom-package-get name :disable)
(eval (doom-package-get name :ignore))
(plist-member (doom-package-get name :recipe) :local-repo)
(locate-library (symbol-name name))
(doom-package-built-in-p name)
(doom-package-installed-p name))
do (print! (error "Missing emacs package: %S") name))
(let ((inhibit-message t))
(load doctor-file 'noerror 'nomessage)))
(file-missing (error! "%s" (error-message-string ex)))
(error (error! "Syntax error: %s" ex)))
(when (or doom-doctor--errors doom-doctor--warnings)
(print-group!
(print! (start (bold "%s %s")) (car key) (cdr key))
(print! "%s" (string-join (append doom-doctor--errors doom-doctor--warnings) "\n")))
(setq doom-local-errors doom-doctor--errors
doom-local-warnings doom-doctor--warnings)))
(appendq! doom-doctor--errors doom-local-errors)
(appendq! doom-doctor--warnings doom-local-warnings)))
doom-modules)))
(pcase-dolist (`(,group . ,name) (doom-module-list))
(let (doom-local-errors
doom-local-warnings)
(let (doom-doctor--errors
doom-doctor--warnings)
(condition-case-unless-debug ex
(let ((doom--current-module key)
(doom--current-flags (plist-get plist :flags))
(doctor-file (doom-module-expand-path (car key) (cdr key) "doctor.el"))
(packages-file (doom-module-expand-path (car key) (cdr key) "packages.el")))
(cl-loop with doom-output-indent = 6
for name in (let* (doom-packages
doom-disabled-packages)
(load packages-file 'noerror 'nomessage)
(mapcar #'car doom-packages))
unless (or (doom-package-get name :disable)
(eval (doom-package-get name :ignore))
(plist-member (doom-package-get name :recipe) :local-repo)
(locate-library (symbol-name name))
(doom-package-built-in-p name)
(doom-package-installed-p name))
do (print! (error "Missing emacs package: %S") name)))
(let ((inhibit-message t))
(load doctor-file 'noerror 'nomessage))
(file-missing (error! "%s" (error-message-string ex)))
(error (error! "Syntax error: %s" ex)))
(when (or doom-doctor--errors doom-doctor--warnings)
(print-group!
(print! (start (bold "%s %s")) (car key) (cdr key))
(print! "%s" (string-join (append doom-doctor--errors doom-doctor--warnings) "\n")))
(setq doom-local-errors doom-doctor--errors
doom-local-warnings doom-doctor--warnings)))
(appendq! doom-doctor--errors doom-local-errors)
(appendq! doom-doctor--warnings doom-local-warnings)))))
(error
(warn! "Attempt to load DOOM failed\n %s\n"
(or (cdr-safe ex) (car ex)))

View file

@ -107,6 +107,18 @@ your `doom!' block, a warning is emitted before replacing it with :emacs vc and
(and (memq flag (plist-get plist :flags))
t))))
(defun doom-module-depth (category module &optional initdepth?)
"Return the depth of CATEGORY MODULE.
If INITDEPTH? is non-nil, use the CAR if a module was given two depths (see
`doom-module-set')."
(if-let (depth (doom-module-get category module :depth))
(or (if initdepth?
(car-safe depth)
(cdr-safe depth))
depth)
0))
(defun doom-module-get (category module &optional property)
"Returns the plist for CATEGORY MODULE. Gets PROPERTY, specifically, if set."
(declare (pure t) (side-effect-free t))
@ -138,24 +150,76 @@ of PROPERTY and VALUEs.
CATEGORY is a keyword, module is a symbol, PLIST is a plist that accepts the
following properties:
:flags [SYMBOL LIST] list of enabled category flags
:path [STRING] path to category root directory
:path STRING
Path to the directory where this module lives.
:depth INT|(INITDEPTH . CONFIGDEPTH)
Determines module load order. If a cons cell, INITDEPTH determines the load
order of the module's init.el, while CONFIGDEPTH determines the same for all
other config files (config.el, packages.el, doctor.el, etc).
:flags (SYMBOL...)
A list of activated flags for this module.
:features (SYMBOL...)
A list of active features, determined from module's metadata. NOT
IMPLEMENTED YET.
If PLIST consists of a single nil, unset and disable CATEGORY MODULE.
Example:
(doom-module-set :lang 'haskell :flags '(+lsp))"
If PLIST consists of a single nil, the module is purged from memory instead."
(if (car plist)
(progn
;; Doom caches flags and features using symbol plists for fast lookups in
;; `modulep!'. plists lack the overhead, and are much faster for datasets this
;; small. The format of this case is (cons FEATURES FLAGS)
(put category module (cons t (plist-get plist :flags)))
;; PERF: Doom caches module index, flags, and features in symbol plists
;; for fast lookups in `modulep!' and elsewhere. plists are lighter
;; and faster than hash tables for datasets this size, and this
;; information is looked up *very* often.
(put category module
(let ((depth (ensure-list (or (plist-get plist :depth) 0))))
(cl-destructuring-bind (i j)
(with-memoization (get 'doom-modules depth) '(0 0))
(dolist (n (list i j))
(when (> n 999)
;; No one will have more than 999 modules at any single
;; depth enabled, right? ...Right?
(signal 'doom-module-error
(list (cons category module) "Over 999 module limit" n))))
(put 'doom-modules depth (list (1+ i) (1+ j)))
(vector (+ (* (or (cdr depth) (car depth)) 1000) j)
(+ (* (car depth) 1000) i)
(plist-get plist :flags)
(plist-get plist :features)))))
;; But the hash table will always been Doom's formal storage for modules.
(puthash (cons category module) plist doom-modules))
(remhash (cons category module) doom-modules)
(cl-remf (symbol-plist category) module)))
(defun doom-module-list (&optional paths-or-all initorder?)
"Return a list of (:group . name) module keys in order of their :depth.
PATHS-OR-ALL can either be a non-nil value or a list of directories. If given a
list of directories, return a list of module keys for all modules present
underneath it. If non-nil, return the same, but search `doom-modules-dirs'
(includes :core and :user). Modules that are enabled are sorted first by their
:depth, followed by disabled modules in lexicographical order (unless a :depth
is specified in their .doommodule).
If INITORDER? is non-nil, sort modules by their initdepth, rather than their
configdepth. See `doom-module-set' for details."
(sort (if paths-or-all
(delete-dups
(append (seq-remove #'cdr (doom-module-list nil initorder?))
(doom-files-in (if (listp paths-or-all)
paths-or-all
doom-modules-dirs)
:map #'doom-module-from-path
:type 'dirs
:mindepth 1
:depth 1)))
(hash-table-keys doom-modules))
(let ((idx (if initorder? 1 0)))
(lambda! ((groupa . namea) (groupb . nameb))
(let ((a (get groupa namea))
(b (get groupb nameb)))
(or (null b)
(if a (< (aref a idx)
(aref b idx)))))))))
(defun doom-module-expand-path (category module &optional file)
"Expands a path to FILE relative to CATEGORY and MODULE.
@ -223,17 +287,8 @@ The list is in no particular order and its file paths are absolute. If
MODULE-DIRS is non-nil, include all modules (even disabled ones) available in
those directories."
(declare (pure t) (side-effect-free t))
(if module-dirs
(mapcar (lambda (m) (doom-module-locate-path (car m) (cdr m)))
(delete-dups
(doom-files-in module-dirs
:map #'doom-module-from-path
:type 'dirs
:mindepth 1
:depth 1)))
(delq
nil (cl-loop for (cat . mod) in (cddr (doom-module-list))
collect (doom-module-get cat mod :path)))))
(cl-loop for (cat . mod) in (doom-module-list module-dirs)
collect (doom-module-locate-path cat mod)))
(defun doom-module-mplist-map (fn mplist)
"Apply FN to each module in MPLIST."
@ -289,17 +344,6 @@ those directories."
(setq doom-inhibit-module-warnings t))
(nreverse results)))
(defun doom-module-list (&optional all-p)
"Return modules as a list of (:CATEGORY . MODULE) in their enabled order.
If ALL-P, return a list of *all* available modules instead, whether or not
they're enabled, and in lexicographical order.
If ALL-P is `real', only return *real"
(if all-p
(mapcar #'doom-module-from-path (doom-module-load-path doom-modules-dirs))
(hash-table-keys doom-modules)))
;;
;;; Use-package modifications
@ -516,6 +560,7 @@ WARNINGS:
;; DEPRECATED Remove in 3.0
(define-obsolete-function-alias 'featurep! 'modulep! "3.0.0")
(defvar doom--empty-module [nil nil nil nil])
(defmacro modulep! (category &optional module flag)
"Return t if :CATEGORY MODULE (and +FLAGS) are enabled.
@ -529,14 +574,22 @@ source (except your DOOMDIR, which is a special module). Like so:
(modulep! +flag)
For more about modules and flags, see `doom!'."
(and (cond (flag (memq flag (cdr (get category module))))
;; PERF: This macro bypasses the module API to spare startup their runtime
;; cost, as `modulep!' gets called *a lot* during startup. In the future,
;; Doom will byte-compile its core files. At that time, we can use it again.
(and (cond (flag (memq flag (aref (or (get category module) doom--empty-module) 2)))
(module (get category module))
(doom--current-flags (memq category doom--current-flags))
(doom--current-module
(memq category (cdr (get (car doom--current-module)
(cdr doom--current-module)))))
(memq category
(aref (or (get (car doom--current-module)
(cdr doom--current-module))
doom--empty-module)
2)))
((if-let (module (doom-module-from-path (macroexpand '(file!))))
(memq category (cdr (get (car module) (cdr module))))
(memq category (aref (or (get (car module) (cdr module))
doom--empty-module)
2))
(error "(modulep! %s %s %s) couldn't figure out what module it was called from (in %s)"
category module flag (file!)))))
t))
@ -547,8 +600,8 @@ For more about modules and flags, see `doom!'."
;; Register Doom's two virtual module categories, representing Doom's core and
;; the user's config; which are always enabled.
(doom-module-set :core nil :path doom-core-dir)
(doom-module-set :user nil :path doom-user-dir)
(doom-module-set :core nil :path doom-core-dir :depth -110)
(doom-module-set :user nil :path doom-user-dir :depth '(-105 . 105))
(provide 'doom-modules)
;;; doom-modules.el ends here

View file

@ -251,11 +251,13 @@ uses a straight or package.el command directly).")
"Ensure `straight' is installed and was compiled with this version of Emacs."
(when (or force-p (null (bound-and-true-p straight-recipe-repositories)))
(doom-log "Initializing straight")
(let ((packages (doom-package-list nil 'core)))
(let ((packages (doom-package-list '((:core)))))
(cl-destructuring-bind (&key recipe pin &allow-other-keys)
(alist-get 'straight packages)
(doom--ensure-straight recipe pin))
(doom--ensure-core-packages packages))))
(doom--ensure-core-packages
(seq-filter (fn! (eq (plist-get % :type) 'core))
packages)))))
(defun doom-initialize-packages (&optional force-p)
"Process all packages, essential and otherwise, if they haven't already been.
@ -407,29 +409,34 @@ installed."
;;; Package getters
(defun doom--read-packages (file &optional noeval noerror)
(defun doom-packages--read (file &optional noeval noerror)
(condition-case-unless-debug e
(with-temp-buffer ; prevent buffer-local state from propagating
(if (not noeval)
(load file noerror 'nomessage 'nosuffix)
(when (file-exists-p file)
(insert-file-contents file)
(let (emacs-lisp-mode) (emacs-lisp-mode))
;; Scrape `package!' blocks from FILE for a comprehensive listing of
;; packages used by this module.
(while (search-forward "(package!" nil t)
(let ((ppss (save-excursion (syntax-ppss))))
;; Don't collect packages in comments or strings
(unless (or (nth 3 ppss)
(nth 4 ppss))
(goto-char (match-beginning 0))
(cl-destructuring-bind (_ name . plist)
(read (current-buffer))
(push (cons
name (plist-put
plist :modules
(list (doom-module-from-path file))))
doom-packages))))))))
(let* ((doom--current-module (doom-module-from-path file))
(doom--current-flags
(doom-module-get (car doom--current-module)
(cdr doom--current-module)
:flags)))
(if (not noeval)
(load file noerror 'nomessage 'nosuffix)
(when (file-exists-p file)
(insert-file-contents file)
(let (emacs-lisp-mode) (emacs-lisp-mode))
;; Scrape `package!' blocks from FILE for a comprehensive listing of
;; packages used by this module.
(while (search-forward "(package!" nil t)
(let ((ppss (save-excursion (syntax-ppss))))
;; Don't collect packages in comments or strings
(unless (or (nth 3 ppss)
(nth 4 ppss))
(goto-char (match-beginning 0))
(cl-destructuring-bind (_ name . plist)
(read (current-buffer))
(push (cons
name (plist-put
plist :modules
(list doom--current-module)))
doom-packages)))))))))
(user-error
(user-error (error-message-string e)))
(error
@ -437,40 +444,32 @@ installed."
(list (doom-module-from-path file)
file e)))))
(defun doom-package-list (&optional all-p core-only-p)
"Retrieve a list of explicitly declared packages from enabled modules.
(defun doom-package-list (&optional module-list)
"Retrieve a list of explicitly declared packages from MODULE-LIST.
If ALL-P, gather packages unconditionally across all modules, including disabled
ones."
(let ((packages-file (concat doom-packages-file ".el"))
If MODULE-LIST is omitted, read enabled module list in configdepth order (see
`doom-module-set'). Otherwise, MODULE-LIST may be any symbol (or t) to mean read
all modules in `doom-modules-dir', including :core and :user. MODULE-LIST may
also be a list of module keys."
(let ((module-list (cond ((null module-list) (doom-module-list))
((symbolp module-list) (doom-module-list 'all))
(module-list)))
;; TODO: doom-module-context + doom-context
(packages-file "packages.el")
doom-disabled-packages
doom-packages)
(doom--read-packages
(doom-path doom-core-dir packages-file) all-p 'noerror)
(unless core-only-p
(let ((private-packages (doom-path doom-user-dir packages-file)))
(if all-p
(mapc #'doom--read-packages
(doom-files-in doom-modules-dir
:depth 2
:match "/packages\\.el$"))
;; We load the private packages file twice to populate
;; `doom-disabled-packages' disabled packages are seen ASAP, and a
;; second time to ensure privately overridden packages are properly
;; overwritten.
(let (doom-packages)
(doom--read-packages private-packages nil 'noerror))
(cl-loop for (cat . mod) in (doom-module-list)
for path = (doom-module-expand-path cat mod packages-file)
for doom--current-module = (cons cat mod)
for doom--current-flags = (doom-module-get cat mod :flags)
do (doom--read-packages path nil 'noerror)))
(doom--read-packages private-packages all-p 'noerror)))
(cl-remove-if-not
(if core-only-p
(lambda (pkg) (eq (plist-get (cdr pkg) :type) 'core))
#'identity)
(nreverse doom-packages))))
(when (assq :user module-list)
;; We load the private packages file twice to populate
;; `doom-disabled-packages' disabled packages are seen ASAP, and a
;; second time to ensure privately overridden packages are properly
;; overwritten.
(let (doom-packages)
(doom-packages--read (doom-module-expand-path :user nil packages-file)
nil 'noerror)))
(cl-loop for (cat . mod) in module-list
if (doom-module-locate-path cat mod packages-file)
do (doom-packages--read it nil 'noerror))
(nreverse doom-packages)))
(defun doom-package-pinned-list ()
"Return an alist mapping package names (strings) to pinned commits (strings)."

View file

@ -386,44 +386,53 @@ Defaults to the profile at `doom-profile-default'."
branch ,(if (zerop (car branch)) (cdr branch))))))))
(defun doom-profile--generate-load-modules ()
(let ((module-list (cddr (doom-module-list))))
;; FIX: Same as above (see `doom-profile--generate-init-vars').
`((unless doom-init-time
(set 'doom-disabled-packages ',doom-disabled-packages)
(set 'doom-modules ',doom-modules)
;; Cache module state and flags in symbol plists for quick lookup by
;; `modulep!' later.
,@(cl-loop for (category . modules) in (seq-group-by #'car (doom-module-list))
collect `(setplist ',category
(quote ,(cl-loop for (_ . module) in modules
nconc `(,module ,(get category module))))))
(doom-run-hooks 'doom-before-modules-init-hook)
;; TODO: Until these files are byte-compiler-ready, I must use `load'
;; instead of `require', as to not invite the byte-compiler to load them
;; while this init file is compiled.
(doom-load ,(doom-path doom-core-dir "doom-keybinds"))
(doom-load ,(doom-path doom-core-dir "doom-ui"))
(doom-load ,(doom-path doom-core-dir "doom-projects"))
(doom-load ,(doom-path doom-core-dir "doom-editor"))
,@(cl-loop for (cat . mod) in module-list
for dir = (doom-module-locate-path cat mod)
if (locate-file-internal doom-module-init-file (list dir) load-suffixes)
collect `(let ((doom--current-module '(,cat . ,mod))
(doom--current-flags ',(doom-module-get cat mod :flags)))
(doom-load ,it)))
(doom-run-hooks 'doom-after-modules-init-hook)
(doom-run-hooks 'doom-before-modules-config-hook)
,@(cl-loop for (cat . mod) in module-list
for dir = (doom-module-locate-path cat mod)
if (locate-file-internal doom-module-config-file (list dir) load-suffixes)
collect `(let ((doom--current-module '(,cat . ,mod))
(doom--current-flags ',(doom-module-get cat mod :flags)))
(doom-load ,it)))
(doom-run-hooks 'doom-after-modules-config-hook)
(let ((old-custom-file custom-file))
(doom-load ,(doom-path doom-user-dir doom-module-config-file) 'noerror)
(when (eq custom-file old-custom-file)
(doom-load custom-file 'noerror)))))))
(let* ((init-modules-list (doom-module-list nil t))
(config-modules-list (doom-module-list))
(pre-init-modules
(seq-filter (fn! (<= (doom-module-depth (car %) (cdr %) t) -100))
(remove '(:user) init-modules-list)))
(init-modules
(seq-filter (fn! (<= 0 (doom-module-depth (car %) (cdr %) t) 100))
init-modules-list))
(config-modules
(seq-filter (fn! (<= 0 (doom-module-depth (car %) (cdr %)) 100))
config-modules-list))
(post-config-modules
(seq-filter (fn! (>= (doom-module-depth (car %) (cdr %)) 100))
config-modules-list))
(init-file (concat doom-module-init-file ".el"))
(config-file (concat doom-module-config-file ".el")))
(letf! ((defun module-loader (group name file &optional noerror)
`(let ((doom--current-module '(,group . ,name))
(doom--current-flags ',(doom-module-get group name :flags)))
(doom-load ,(abbreviate-file-name file))))
(defun module-list-loader (modules file &optional noerror)
(cl-loop for (cat . mod) in modules
if (doom-module-locate-path cat mod file)
collect (module-loader cat mod it noerror))))
;; FIX: Same as above (see `doom-profile--generate-init-vars').
`((unless doom-init-time
(set 'doom-modules ',doom-modules)
(set 'doom-disabled-packages ',doom-disabled-packages)
;; Cache module state and flags in symbol plists for quick lookup by
;; `modulep!' later.
,@(cl-loop
for (category . modules) in (seq-group-by #'car config-modules-list)
collect
`(setplist ',category
(quote ,(cl-loop for (_ . module) in modules
nconc `(,module ,(get category module))))))
(let ((old-custom-file custom-file))
,@(module-list-loader pre-init-modules init-file)
(doom-run-hooks 'doom-before-modules-init-hook)
,@(module-list-loader init-modules init-file)
(doom-run-hooks 'doom-after-modules-init-hook)
(doom-run-hooks 'doom-before-modules-config-hook)
,@(module-list-loader config-modules config-file)
(doom-run-hooks 'doom-after-modules-config-hook)
,@(module-list-loader post-config-modules config-file t)
(when (eq custom-file old-custom-file)
(doom-load custom-file 'noerror))))))))
(defun doom-profile--generate-doom-autoloads ()
(doom-autoloads--scan

View file

@ -36,10 +36,10 @@
;; > $EMACSDIR/lisp/doom.el
;; - $EMACSDIR/lisp/doom-lib.el
;; > $EMACSDIR/lisp/doom-start.el
;; - $EMACSDIR/doom-{keybinds,ui,projects,editor}.el
;; - hook: `doom-before-init-hook'
;; - $DOOMDIR/init.el
;; > $XDG_DATA_HOME/doom/$PROFILE/@/curr/init.el (replaces $EMACSDIR/init.el)
;; > $XDG_DATA_HOME/doom/$PROFILE/@/$VERSION/init.el (replaces $EMACSDIR/init.el)
;; - $EMACSDIR/doom-{keybinds,ui,projects,editor}.el
;; - hook: `doom-before-modules-init-hook'
;; - {$DOOMDIR,$EMACSDIR}/modules/*/*/init.el
;; - hook: `doom-after-modules-init-hook'

16
lisp/init.el Normal file
View file

@ -0,0 +1,16 @@
;;; lisp/init.el -*- lexical-binding: t; -*-
;;; Commentary:
;;
;; :core is now treated like a normal module, and this is its (temporary) init
;; file, which will be removed once we've resolved our `use-package' dependency
;; (which will soon be moved to its own module), then these will be returned to
;; the profile init file.
;;
;;; Code:
(doom-require 'doom-keybinds)
(doom-require 'doom-ui)
(doom-require 'doom-projects)
(doom-require 'doom-editor)
;;; init.el ends here

View file

@ -306,7 +306,7 @@ ready to be pasted in a bug report on github."
collect var)))
(modules
,@(or (cl-loop with lastcat = nil
for (cat . mod) in (cddr (doom-module-list))
for (cat . mod) in (seq-filter #'cdr (doom-module-list))
if (or (not lastcat)
(not (eq lastcat cat)))
do (setq lastcat cat)

View file

@ -154,8 +154,7 @@ each package."
(if (listp m)
(format "%s %s" (car m) (cdr m))
(format "%s" m)))
(append '(:user :core)
(delete-dups (mapcar #'car modules))
(append (delete-dups (mapcar #'car modules))
modules)))
nil t nil nil))
(module (split-string module " " t)))
@ -173,8 +172,7 @@ each package."
(if module
(list (cons category module))
(cl-remove-if-not (lambda (m) (eq (car m) category))
(append '((:core) (:user))
(doom-module-list 'all))))))
(doom-module-list 'all)))))
;;;###autoload
(defun doom/bump-package (package)