This commit adds bin/doom, which acts as the middle man that make once was (and will stay for a while, though the documentation will shift away from using it). It does everything the previous make interface did, but is faster and more flexible. bin/doom should eventually replace the makefile. bin/doom also makes it easier to run Doom outside of ~/.emacs.d and ~/.doom.d with, for example: bin/doom run -p ~/.other.doom.d/ -e ~/.other.emacs.d bin/doom.cmd is included for Windows users, but I don't recommend using it yet. It hasn't been tested nor have I ever written a batch script before. Also update init.example.el with new defaults.
287 lines
13 KiB
EmacsLisp
287 lines
13 KiB
EmacsLisp
;;; core/autoload/modules.el -*- lexical-binding: t; -*-
|
|
|
|
;;;###autoload
|
|
(defun doom//reload ()
|
|
"Reload your private Doom config. Experimental!"
|
|
(interactive)
|
|
(let ((load-prefer-newer t))
|
|
(message "Reloading your private config...")
|
|
(setq doom-modules (make-hash-table :test #'equal :size 100 :rehash-threshold 1.0))
|
|
(doom-initialize t)
|
|
(doom//reload-autoloads))
|
|
(message "✓ Done!"))
|
|
|
|
;;;###autoload
|
|
(defun doom//reload-load-path ()
|
|
"Reload `load-path' and recompile files (if necessary).
|
|
|
|
Use this when `load-path' is out of sync with your plugins. This should only
|
|
happen if you manually modify/update/install packages from outside Emacs, while
|
|
an Emacs session is running.
|
|
|
|
This isn't necessary if you use Doom's package management commands because they
|
|
call `doom//reload-load-path' remotely (through emacsclient)."
|
|
(interactive)
|
|
(unless doom--inhibit-reload
|
|
(when (file-exists-p doom-packages-file)
|
|
(delete-file doom-packages-file))
|
|
(cond ((and noninteractive (not (daemonp)))
|
|
(require 'server)
|
|
(when (server-running-p)
|
|
(message "Reloading active Emacs session...")
|
|
(server-eval-at server-name '(doom//reload-load-path))))
|
|
(t
|
|
(doom-initialize t)
|
|
(message "%d packages reloaded" (length package-alist))
|
|
(run-hooks 'doom-reload-hook)))))
|
|
|
|
(defvar generated-autoload-load-name)
|
|
;;;###autoload
|
|
(defun doom//reload-autoloads (&optional force)
|
|
"Refreshes the autoloads.el file, specified by `doom-autoload-file'.
|
|
|
|
It scans and reads core/autoload/*.el, modules/*/*/autoload.el and
|
|
modules/*/*/autoload/*.el, and generates an autoloads file at the path specified
|
|
by `doom-autoload-file'. This file tells Emacs where to find lazy-loaded
|
|
functions.
|
|
|
|
This should be run whenever init.el or an autoload file is modified. Running
|
|
'make autoloads' from the commandline executes this command."
|
|
(interactive)
|
|
;; This function must not use autoloaded functions or external dependencies.
|
|
;; It must assume nothing is set up!
|
|
(let ((default-directory doom-emacs-dir)
|
|
(targets
|
|
(file-expand-wildcards
|
|
(expand-file-name "autoload/*.el" doom-core-dir)))
|
|
(generate-autoload-section-continuation "")
|
|
(generate-autoload-section-header "")
|
|
(generate-autoload-section-trailer "")
|
|
(doom--stage 'autoloads)
|
|
outdated)
|
|
(dolist (path (doom-module-load-path))
|
|
(let ((auto-dir (expand-file-name "autoload" path))
|
|
(auto-file (expand-file-name "autoload.el" path)))
|
|
(when (file-exists-p auto-file)
|
|
(push auto-file targets))
|
|
(when (file-directory-p auto-dir)
|
|
(dolist (file (doom-files-under auto-dir :match "\\.el$"))
|
|
(push file targets)))))
|
|
(when (file-exists-p doom-autoload-file)
|
|
(delete-file doom-autoload-file)
|
|
(ignore-errors (delete-file (byte-compile-dest-file doom-autoload-file)))
|
|
(message "Deleted old autoloads.el"))
|
|
(message "Generating new autoloads.el")
|
|
(dolist (file (mapcar #'file-truename (reverse targets)))
|
|
(let ((generated-autoload-load-name (file-name-sans-extension file)))
|
|
(message
|
|
(cond ((not (doom-file-cookie-p file))
|
|
"⚠ Ignoring %s")
|
|
((update-file-autoloads file nil doom-autoload-file)
|
|
"✕ Nothing in %s")
|
|
("✓ Scanned %s"))
|
|
(if (file-in-directory-p file default-directory)
|
|
(file-relative-name file)
|
|
(abbreviate-file-name file)))))
|
|
(make-directory (file-name-directory doom-autoload-file) t)
|
|
(let ((buf (find-file-noselect doom-autoload-file t))
|
|
(load-path (append doom-psuedo-module-dirs
|
|
doom-modules-dirs
|
|
load-path))
|
|
case-fold-search)
|
|
;; FIXME Make me faster
|
|
(unwind-protect
|
|
(with-current-buffer buf
|
|
(goto-char (point-min))
|
|
(insert ";;; -*- lexical-binding:t -*-\n"
|
|
";; This file is autogenerated by `doom//reload-autoloads', DO NOT EDIT !!\n\n")
|
|
|
|
;; Replace autoload paths (only for module autoloads) with
|
|
;; absolute paths for faster resolution during load and simpler
|
|
;; `load-path'
|
|
(save-excursion
|
|
(let (cache)
|
|
(while (re-search-forward "^\\s-*(autoload\\s-+'[^ ]+\\s-+\"\\([^\"]*\\)\"" nil t)
|
|
(let ((path (match-string 1)))
|
|
(replace-match
|
|
(or (cdr (assoc path cache))
|
|
(when-let* ((libpath (locate-library path))
|
|
(libpath (file-name-sans-extension libpath)))
|
|
(push (cons path (abbreviate-file-name libpath)) cache)
|
|
libpath)
|
|
(progn
|
|
(warn "Couldn't find absolute path for: %s" path)
|
|
path))
|
|
t t nil 1))))
|
|
(message "✓ Autoload paths expanded"))
|
|
|
|
;; insert package autoloads
|
|
(save-excursion
|
|
(dolist (spec package-alist)
|
|
(let ((pkg (car spec)))
|
|
(unless (memq pkg doom-autoload-excluded-packages)
|
|
(let ((file
|
|
(abbreviate-file-name
|
|
(concat (package--autoloads-file-name (cadr spec)) ".el"))))
|
|
(insert "(let ((load-file-name " (prin1-to-string file) "))\n")
|
|
(insert-file-contents file)
|
|
(while (re-search-forward "^\\(?:;;\\(.*\n\\)\\|\n\\)" nil t)
|
|
(unless (nth 8 (syntax-ppss))
|
|
(replace-match "" t t)))
|
|
(unless (bolp) (insert "\n"))
|
|
(insert ")\n")))))
|
|
(message "✓ Package autoloads included"))
|
|
|
|
;; Remove `load-path' and `auto-mode-alist' modifications (most
|
|
;; of them, at least); they are cached elsewhere, so these are
|
|
;; unnecessary overhead.
|
|
(while (re-search-forward (concat "^\\s-*(\\(add-to-list\\s-+'\\(?:load-path\\|auto-mode-alist\\)\\)")
|
|
nil t)
|
|
(beginning-of-line)
|
|
(skip-chars-forward " \t")
|
|
(kill-sexp))
|
|
(message "✓ load-path/auto-mode-alist entries removed")
|
|
|
|
;; Remove byte-compile inhibiting file variables so we can
|
|
;; byte-compile the file.
|
|
(when (re-search-forward "^;; no-byte-compile: t\n$" nil t)
|
|
(replace-match "" t t))
|
|
(save-buffer)
|
|
|
|
;; Byte compile it to give the file a chance to reveal errors.
|
|
(condition-case-unless-debug ex
|
|
(quiet! (byte-compile-file doom-autoload-file 'load))
|
|
('error
|
|
(delete-file doom-autoload-file)
|
|
(message "Deleting autoloads file!")
|
|
(error "Error in autoloads.el: %s -- %s"
|
|
(car ex) (error-message-string ex))))
|
|
(message "Done!"))
|
|
(kill-buffer buf)))))
|
|
|
|
;;;###autoload
|
|
(defun doom//byte-compile (&optional modules recompile-p)
|
|
"Byte compiles your emacs configuration.
|
|
|
|
init.el is always byte-compiled by this.
|
|
|
|
If MODULES is specified (a list of module strings, e.g. \"lang/php\"), those are
|
|
byte-compiled. Otherwise, all enabled modules are byte-compiled, including Doom
|
|
core. It always ignores unit tests and files with `no-byte-compile' enabled.
|
|
|
|
Doom was designed to benefit from byte-compilation, but the process may take a
|
|
while. Also, while your config files are byte-compiled, changes to them will not
|
|
take effect! Use `doom//clean-byte-compiled-files' or `make clean' to remove
|
|
these files.
|
|
|
|
If RECOMPILE-P is non-nil, only recompile out-of-date files."
|
|
(interactive
|
|
(list nil current-prefix-arg))
|
|
(let ((default-directory doom-emacs-dir)
|
|
(recompile-p (or recompile-p (and (member "-r" (cdr argv)) t)))
|
|
(argv (delete "-r" argv)))
|
|
(unless recompile-p
|
|
(doom//clean-byte-compiled-files))
|
|
(let ((total-ok 0)
|
|
(total-fail 0)
|
|
(total-noop 0)
|
|
(modules (or modules (cdr argv)))
|
|
compile-plugins
|
|
compile-targets)
|
|
;; Ensure that Doom has been fully loaded, some of its state may be
|
|
;; pertinent to files compiled later.
|
|
(let ((doom--stage 'compile)
|
|
noninteractive)
|
|
;; Core libraries aren't fully loaded in a noninteractive session, so we
|
|
;; pretend to be interactive and reinitialize
|
|
(doom-initialize))
|
|
;; Assemble el files we want to compile; taking into account that MODULES
|
|
;; may be a list of MODULE/SUBMODULE strings from the command line.
|
|
(setq
|
|
modules (or modules (append (list doom-core-dir) (doom-module-load-path)))
|
|
compile-targets
|
|
(cl-loop for target in modules
|
|
if (equal target ":core")
|
|
nconc (nreverse (doom-files-under doom-core-dir :match "\\.el$"))
|
|
and collect (expand-file-name "init.el" doom-private-dir)
|
|
if (equal target ":private")
|
|
nconc (nreverse (doom-files-under doom-private-dir :match "\\.el$"))
|
|
if (equal target ":plugins")
|
|
do (setq compile-plugins t)
|
|
else if (file-directory-p target)
|
|
nconc (nreverse (doom-files-under target :match "\\.el$"))
|
|
else if (cl-member target doom-psuedo-module-dirs :test #'file-in-directory-p)
|
|
nconc (nreverse (doom-files-under it :match "\\.el$"))
|
|
else if (string-match "^\\([^/]+\\)/\\([^/]+\\)$" target)
|
|
nconc (nreverse (doom-files-under
|
|
(doom-module-locate-path
|
|
(intern (format ":%s" (match-string 1 target)))
|
|
(intern (match-string 2 target)))
|
|
:match "\\.el$"))
|
|
else if (file-exists-p target)
|
|
collect target
|
|
finally do (setq argv nil)))
|
|
(if compile-plugins
|
|
(byte-recompile-directory package-user-dir 0 t)
|
|
(if (not compile-targets)
|
|
(message "No targets to compile")
|
|
(condition-case ex
|
|
(let ((use-package-expand-minimally t))
|
|
(push (expand-file-name "init.el" doom-emacs-dir) compile-targets)
|
|
(dolist (target (cl-delete-duplicates (mapcar #'file-truename compile-targets) :test #'equal))
|
|
(when (or (not recompile-p)
|
|
(let ((elc-file (byte-compile-dest-file target)))
|
|
(and (file-exists-p elc-file)
|
|
(file-newer-than-file-p target elc-file))))
|
|
(let ((result (cond ((string-match-p "/\\(packages\\|doctor\\)\\.el$" target)
|
|
'no-byte-compile)
|
|
((doom-file-cookie-p target)
|
|
(byte-compile-file target))
|
|
('no-byte-compile)))
|
|
(short-name (if (file-in-directory-p target doom-emacs-dir)
|
|
(file-relative-name target doom-emacs-dir)
|
|
(abbreviate-file-name target))))
|
|
(cl-incf
|
|
(cond ((eq result 'no-byte-compile)
|
|
(print! (dark (white "⚠ Ignored %s" short-name)))
|
|
total-noop)
|
|
((null result)
|
|
(print! (red "✕ Failed to compile %s" short-name))
|
|
total-fail)
|
|
(t
|
|
(print! (green "✓ Compiled %s" short-name))
|
|
(quiet! (load target t t))
|
|
total-ok))))))
|
|
(print!
|
|
(bold
|
|
(color (if (= total-fail 0) 'green 'red)
|
|
"%s %d/%d file(s) (%d ignored)"
|
|
(if recompile-p "Recompiled" "Compiled")
|
|
total-ok (- (length compile-targets) total-noop)
|
|
total-noop))))
|
|
(error
|
|
(print! (red "\n%%s\n\n%%s\n\n%%s")
|
|
"There were breaking errors."
|
|
(error-message-string ex)
|
|
"Reverting changes...")
|
|
(quiet! (doom//clean-byte-compiled-files))
|
|
(print! (green "Finished (nothing was byte-compiled)")))))))))
|
|
|
|
;;;###autoload
|
|
(defun doom//clean-byte-compiled-files ()
|
|
"Delete all the compiled elc files in your Emacs configuration. This excludes
|
|
compiled packages.'"
|
|
(interactive)
|
|
(cl-loop with default-directory = doom-emacs-dir
|
|
for path in (append (doom-files-in doom-emacs-dir :match "\\.elc$")
|
|
(doom-files-in doom-psuedo-module-dirs :match "\\.elc$" :full t)
|
|
(doom-files-under doom-core-dir :match "\\.elc$")
|
|
(doom-files-under doom-modules-dirs :match "\\.elc$"))
|
|
for truepath = (file-truename path)
|
|
do (delete-file path)
|
|
and do
|
|
(message "✓ Deleted %s"
|
|
(if (file-in-directory-p truepath default-directory)
|
|
(file-relative-name truepath)
|
|
(abbreviate-file-name path)))
|
|
finally do (message "Everything is clean")))
|