diff --git a/Makefile b/Makefile index 669ba1a05..a55b469a2 100644 --- a/Makefile +++ b/Makefile @@ -18,16 +18,16 @@ ce: compile-elpa ## Package management install: init.el .local/autoloads.el - @$(EMACS) -f doom/packages-install + @$(EMACS) -f doom//packages-install update: init.el .local/autoloads.el - @$(EMACS) -f doom/packages-update + @$(EMACS) -f doom//packages-update autoremove: init.el .local/autoloads.el - @$(EMACS) -f doom/packages-autoremove + @$(EMACS) -f doom//packages-autoremove autoloads: init.el - @$(EMACS) -f doom/reload-autoloads + @$(EMACS) -f doom//reload-autoloads ## Byte compilation @@ -36,29 +36,22 @@ autoloads: init.el # compile-module # compile-module/submodule compile: init.el clean - @$(EMACS) -f doom/compile + @$(EMACS) -f doom//byte-compile compile-core: init.el clean - @$(EMACS) -f doom/compile -- init.el core + @$(EMACS) -f doom//byte-compile-core compile-elpa: init.el - @$(EMACS) -f doom/recompile-packages + @$(EMACS) -f doom//byte-recompile-plugins $(patsubst %, compile-%, $(MODULES)): init.el .local/autoloads.el - @rm -fv $(shell find $(patsubst compile-%, modules/%, $@) -type f -name '*.elc') - @$(EMACS) -f doom/compile -- $(patsubst compile-%, modules/%, $@) + @$(EMACS) -f doom//byte-compile $(patsubst compile-%, %, $@) recompile: init.el - @$(EMACS) -f doom/recompile + @$(EMACS) -f doom//byte-compile -r clean: - @$(EMACS) -f doom/clean-compiled-files - -clean-pcache: - @$(EMACS) -l persistent-soft --eval '(delete-directory pcache-directory t)' - -reset: - @$(EMACS) -f doom/reset + @$(EMACS) -f doom//clean-byte-compiled-files ## Unit tests @@ -67,14 +60,14 @@ reset: # test-module # test-module/submodule test: init.el .local/autoloads.el - @$(EMACS) -f doom-run-tests + @$(EMACS) -f doom//run-tests test-core $(patsubst %, test-%, $(MODULES)): init.el .local/autoloads.el - @$(EMACS) -f doom-run-tests -- $(subst test-, , $@) + @$(EMACS) -f doom//run-tests -- $(subst test-, , $@) # run tests interactively testi: init.el .local/autoloads.el - @$(EMACSI) -f doom-run-tests -f ert + @$(EMACSI) -f doom//run-tests -f ert ## Utility tasks @@ -93,7 +86,4 @@ init.el: .local/autoloads.el: @$(EMACS) -f doom-initialize-autoloads -%.elc: %.el - @$(EMACS) -f doom/compile -- $< - -.PHONY: all compile test testi +.PHONY: all compile test testi clean diff --git a/core/autoload/packages.el b/core/autoload/packages.el index 413e21c66..140671e0c 100644 --- a/core/autoload/packages.el +++ b/core/autoload/packages.el @@ -303,7 +303,7 @@ package.el as appropriate." ;; ;;;###autoload -(defun doom/packages-install () +(defun doom//packages-install () "Interactive command for installing missing packages." (interactive) (let ((packages (doom-get-missing-packages))) @@ -341,10 +341,10 @@ package.el as appropriate." ""))))) (message! (bold (green "Finished!"))) - (doom/reload-load-path)))) + (doom//reload-load-path)))) ;;;###autoload -(defun doom/packages-update () +(defun doom//packages-update () "Interactive command for updating packages." (interactive) (doom-refresh-packages doom-debug-mode) @@ -382,10 +382,10 @@ package.el as appropriate." (if result "DONE" "FAILED")))))) (message! (bold (green "Finished!"))) - (doom/reload-load-path))))) + (doom//reload-load-path))))) ;;;###autoload -(defun doom/packages-autoremove () +(defun doom//packages-autoremove () "Interactive command for auto-removing orphaned packages." (interactive) (let ((packages (doom-get-orphaned-packages))) @@ -415,7 +415,7 @@ package.el as appropriate." pkg))))) (message! (bold (green "Finished!"))) - (doom/reload-load-path))))) + (doom//reload-load-path))))) ;;;###autoload (defalias 'doom/install-package #'package-install) diff --git a/core/autoload/test.el b/core/autoload/test.el index 2c1b948d1..a49bffc1b 100644 --- a/core/autoload/test.el +++ b/core/autoload/test.el @@ -1,7 +1,7 @@ -;;; core/autoload/test.el -*- lexical-binding: t; -*- +;;; core/autoload/test.el -*- lexical-binding: t; no-byte-compile: t; -*- ;;;###autoload -(defun doom-run-tests (&optional modules) +(defun doom//run-tests (&optional modules) "Run all loaded tests, specified by MODULES (a list of module cons cells) or command line args following a double dash (each arg should be in the 'module/submodule' format). diff --git a/core/autoload/ui.el b/core/autoload/ui.el index 2336d5fbe..bec5426bb 100644 --- a/core/autoload/ui.el +++ b/core/autoload/ui.el @@ -68,17 +68,6 @@ window changes before then, the undo expires." (delete-frame)) (save-buffers-kill-emacs))) -;;;###autoload -(defun doom/reload-theme () - "Reset the color theme currently in use." - (interactive) - (let ((theme (or (car-safe custom-enabled-themes) doom-theme))) - (when theme - (mapc #'disable-theme custom-enabled-themes)) - (run-hooks 'doom-pre-reload-theme-hook) - (doom|init-ui) - (run-hooks 'doom-post-reload-theme-hook))) - ;;;###autoload (define-minor-mode doom-big-font-mode "A global mode that resizes the font, for streams, screen-sharing and @@ -91,3 +80,14 @@ presentations." (if doom-big-font-mode (set-frame-font doom-big-font t t) (set-frame-font doom-font t t))) + +;;;###autoload +(defun doom//reload-theme () + "Reset the color theme currently in use." + (interactive) + (let ((theme (or (car-safe custom-enabled-themes) doom-theme))) + (when theme + (mapc #'disable-theme custom-enabled-themes)) + (run-hooks 'doom-pre-reload-theme-hook) + (doom|init-ui) + (run-hooks 'doom-post-reload-theme-hook))) diff --git a/core/core-packages.el b/core/core-packages.el index 65e21ac63..b4af9f0a6 100644 --- a/core/core-packages.el +++ b/core/core-packages.el @@ -181,7 +181,7 @@ startup." "Ensures that `doom-autoload-file' exists and is loaded. Otherwise run `doom/reload-autoloads' to generate it." (unless (file-exists-p doom-autoload-file) - (quiet! (doom/reload-autoloads)))) + (quiet! (doom//reload-autoloads)))) (defun doom-initialize-packages (&optional force-p load-p) "Crawls across your emacs.d to fill `doom-modules' (from init.el) and @@ -191,33 +191,38 @@ If FORCE-P is non-nil, do it even if they are. This aggressively reloads core autoload files." (doom-initialize force-p) - (let ((noninteractive t) - (load-prefer-newer t) - (load-fn - (lambda (file &optional noerror) - (condition-case-unless-debug ex - (load file noerror :nomessage :nosuffix) - ('error - (error (format "(doom-initialize-packages) %s in %s: %s" - (car ex) - (file-relative-name file doom-emacs-dir) - (error-message-string ex)) - :error)))))) - (when (or force-p (not doom-modules)) - (setq doom-modules nil) - (funcall load-fn (expand-file-name "init.el" doom-emacs-dir)) - (when load-p + (with-temp-buffer ; prevent buffer-local settings from propagating + (let ((noninteractive t) + (load-prefer-newer t) + (load-fn + (lambda (file &optional noerror) + (condition-case-unless-debug ex + (load file noerror :nomessage :nosuffix) + ('error + (error (format "(doom-initialize-packages) %s in %s: %s" + (car ex) + (file-relative-name file doom-emacs-dir) + (error-message-string ex)) + :error)))))) + (when (or force-p (not doom-modules)) + (setq doom-modules nil) (let (noninteractive) - (funcall load-fn (doom-module-path :private user-login-name "init.el") t) - (funcall load-fn (expand-file-name "core.el" doom-core-dir))) - (mapc load-fn (file-expand-wildcards (expand-file-name "autoload/*.el" doom-core-dir)))) - (doom|finalize)) - (when (or force-p (not doom-packages)) - (setq doom-packages nil) - (funcall load-fn (expand-file-name "packages.el" doom-core-dir)) - (cl-loop for (module . submodule) in (doom--module-pairs) - for path = (doom-module-path module submodule "packages.el") - do (funcall load-fn path t))))) + (load (concat doom-core-dir "core.el") nil t)) + (funcall load-fn (expand-file-name "init.el" doom-emacs-dir)) + (when load-p + (let (noninteractive) + (funcall load-fn (doom-module-path :private user-login-name "init.el") t)) + (mapc load-fn (file-expand-wildcards (expand-file-name "autoload/*.el" doom-core-dir))) + (cl-loop for (module . submodule) in (doom--module-pairs) + for path = (doom-module-path module submodule "config.el") + do (funcall load-fn path t)))) + (when (or force-p (not doom-packages)) + (setq doom-packages nil) + (funcall load-fn (expand-file-name "packages.el" doom-core-dir)) + (cl-loop for (module . submodule) in (doom--module-pairs) + for path = (doom-module-path module submodule "packages.el") + do (funcall load-fn path t))))) + (doom|finalize)) (defun doom-initialize-modules (modules) "Adds MODULES to `doom-modules'. MODULES must be in mplist format. @@ -486,7 +491,15 @@ loads MODULE SUBMODULE's packages.el file." ;; Commands ;; -(defun doom/reload-load-path () +(defsubst doom--read-cookie-pred (file) + "Returns the value of the ;;;###if predicate form in FILE." + (with-temp-buffer + (insert-file-contents-literally file nil 0 256) + (if (re-search-forward "^;;;###if " nil t) + (eval (sexp-at-point)) + t))) + +(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 @@ -496,20 +509,19 @@ 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) + (byte-recompile-file (expand-file-name "core.el" doom-core-dir) t) (cond (noninteractive (message "Reloading...") (require 'server) - (unless (ignore-errors (server-eval-at "server" '(doom/reload-load-path))) - (message "Recompiling") - (doom/recompile))) + (when (file-exists-p (if server-use-tcp server-auth-dir server-socket-dir)) + (server-eval-at "server" '(doom//reload-load-path)))) (t (doom-initialize t) - (doom/recompile) (message "Reloaded %d packages" (length doom--package-load-path)) (run-with-timer 1 nil #'redraw-display) (run-hooks 'doom-reload-hook)))) -(defun doom/reload-autoloads () +(defun doom//reload-autoloads () "Refreshes the autoloads.el file, specified by `doom-autoload-file'. It scans and reads core/autoload/*.el, modules/*/*/autoload.el and @@ -523,21 +535,20 @@ This should be run whenever init.el or an autoload file is modified. Running ;; This function must not use autoloaded functions or external dependencies. ;; It must assume nothing is set up! (doom-initialize-packages (not noninteractive)) - (let ((evil-p (doom-module-loaded-p :feature 'evil)) - (targets + (let ((targets (file-expand-wildcards (expand-file-name "autoload/*.el" doom-core-dir)))) (dolist (path (doom--module-paths)) (let ((auto-dir (expand-file-name "autoload" path)) (auto-file (expand-file-name "autoload.el" path))) - (when (file-exists-p auto-file) + (when (and (file-exists-p auto-file) + (doom--read-cookie-pred auto-file)) (push auto-file targets)) (when (file-directory-p auto-dir) (dolist (file (file-expand-wildcards (expand-file-name "*.el" auto-dir) t)) ;; Make evil*.el autoload files a special case; don't load ;; them unless evil is enabled. - (unless (and (string-prefix-p "evil" (file-name-nondirectory file)) - (not evil-p)) + (when (doom--read-cookie-pred file) (push file targets)))))) (when (file-exists-p doom-autoload-file) (delete-file doom-autoload-file) @@ -569,109 +580,108 @@ This should be run whenever init.el or an autoload file is modified. Running (car ex) (error-message-string ex)))) (kill-buffer buf))))) -(defun doom/compile (&optional lite-p only-recompile-p) +(defun doom//byte-compile (&optional modules recompile-p) "Byte compiles your emacs configuration. -Specifically, this byte-compiles init.el, core/*.el, core/autoload/*.el & -modules/*/*/**.el. It ignores unit tests and files with `no-byte-compile' -enabled. +init.el is always byte-compiled by this. -DOOM Emacs 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-compiled' or `make clean' to undo -byte-compilation. +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. -If LITE-P is non-nil, only compile the core DOOM files (init.el & core/**/*.el). +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 ONLY-RECOMPILE-P is non-nil, only recompile out-of-date 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" command-line-args) t)))) + (if (not noninteractive) + (let ((compilation-filter-hook + (list (lambda () (ansi-color-apply-on-region compilation-filter-start (point)))))) + (compile (format "%s --batch -l core/core.el -f doom//byte-compile %s %s" + (executable-find "emacs") + (if recompile-p "-r" "") + (if modules (string-join modules " ") "")))) + (let ((total-ok 0) + (total-fail 0) + (total-noop 0) + (modules (or modules command-line-args-left)) + compile-targets) + (doom-initialize-packages t t) + (setq compile-targets + (cl-loop for target + in (or modules (append (list doom-core-dir) (doom--module-paths))) + if (equal target "core") + nconc (nreverse (directory-files-recursively doom-core-dir "\\.el$")) + else if (file-directory-p target) + nconc (nreverse (directory-files-recursively target "\\.el$")) + else if (file-directory-p (expand-file-name target doom-modules-dir)) + nconc (nreverse (directory-files-recursively (expand-file-name target doom-modules-dir) "\\.el$")) + else if (file-exists-p target) + collect target + finally do (setq command-line-args-left nil))) + (unless compile-targets + (error "No targets to compile")) + (let ((use-package-expand-minimally t)) + (push (expand-file-name "init.el" doom-emacs-dir) compile-targets) + (dolist (target compile-targets) + (when (or (not recompile-p) + (let ((elc-file (byte-compile-dest-file target))) + (and (file-exists-p elc-file) + (file-newer-than-file-p file elc-file)))) + (let ((result (if (and (string-match-p "/autoload/.*\\.el$" target) + (not (doom--read-cookie-pred target))) + 'no-byte-compile + (byte-compile-file target))) + (short-name (file-relative-name target doom-emacs-dir))) + (cl-incf + (cond ((eq result 'no-byte-compile) + (message! (dark (white "Ignored %s" short-name))) + total-noop) + ((null result) + (message! (red "Failed to compile %s" short-name)) + total-fail) + (t + (message! (green "Compiled %s" short-name)) + (quiet! (load target t t)) + total-ok)))))) + (message! + (bold + (color (if (= total-fail 0) 'green 'red) + "%s %s file(s) %s" + (if recompile-p "Recompiled" "Compiled") + (format "%d/%d" total-ok (- (length compile-targets) total-noop)) + (format "(%s ignored)" total-noop))))))))) + +(defun doom//byte-compile-core (&optional recompile-p) + "" (interactive "P") - ;; Ensure all relevant config files are loaded and up-to-date. This way we - ;; don't need eval-when-compile and require blocks scattered all over. - (doom-initialize-packages t noninteractive) - (let ((targets - (cond ((equal (car command-line-args-left) "--") - (cl-loop for file in (cdr command-line-args-left) - if (file-exists-p file) - collect (expand-file-name file) - finally do (setq command-line-args-left nil)) ) - (t - (append (list (expand-file-name "init.el" doom-emacs-dir) - doom-core-dir) - (unless lite-p (doom--module-paths)))))) - (total-success 0) - (total-fail 0) - (total-nocomp 0) - (use-package-expand-minimally t)) - (let ((el-files (cl-loop for path in targets - if (file-directory-p path) - nconc (nreverse (directory-files-recursively path "\\.el$")) - else if (file-exists-p path) - collect path))) - (dolist (file el-files) - (when (or (not only-recompile-p) - (let ((elc-file (byte-compile-dest-file file))) - (and (file-exists-p elc-file) - (file-newer-than-file-p file elc-file)))) - (let ((result (if (string-match-p "/test/.+\\.el$" file) - 'no-byte-compile - (byte-compile-file file))) - (short-name (file-relative-name file doom-emacs-dir))) - (cl-incf - (cond ((eq result 'no-byte-compile) - (message! (dark (white "Ignored %s" short-name))) - total-nocomp) - ((null result) - (message! (red "Failed to compile %s" short-name)) - total-fail) - (t - (message! (green "Compiled %s" short-name)) - (quiet! (load file t t)) - total-success)))))) - (message! - (bold - (color (if (= total-fail 0) 'green 'red) - "%s %s file(s) %s" - (if only-recompile-p "Recompiled" "Compiled") - (format (if el-files "%d/%d" "%d") - total-success - (- (length el-files) total-nocomp)) - (format "(%s ignored)" total-nocomp))))))) + (doom//byte-compile (list "core") recompile-p)) -(defun doom/recompile () - "Recompile any out-of-date compiled *.el files in your Emacs configuration." - (interactive) - (doom/compile nil :recompile) - ;; Forcibly recompile core.el in case `load-path' has changed - (byte-recompile-file (expand-file-name "core.el" doom-core-dir) t)) - -(defun doom/recompile-packages () - "Recompile all installed elpa packages. If you're getting odd errors after -upgrading Emacs, this may fix it." +(defun doom//byte-recompile-plugins () + "Recompile all installed plugins. If you're getting odd errors after upgrading +(or downgrading) Emacs, this may fix it." (interactive) (byte-recompile-directory package-user-dir 0 t)) -(defun doom/reset () - "Clear the local cache completely (in `doom-cache-dir'). +(defun doom//clean-byte-compiled-files () + "Delete all the compiled elc files in your Emacs configuration. -This resets Emacs to a blank slate. You must restart Emacs for some components -to feel its effects." - (interactive) - (delete-directory doom-cache-dir t) - (make-directory doom-cache-dir t)) - -(defun doom/clean-compiled-files () - "Delete all compiled elc files in your Emacs configuration. - -This excludes compiled packages in `doom-packages-dir'." +This excludes compiled packages in `doom-packages-dir'.'" (interactive) (let ((targets (append (list (expand-file-name "init.elc" doom-emacs-dir)) (directory-files-recursively doom-core-dir "\\.elc$") (directory-files-recursively doom-modules-dir "\\.elc$")))) (unless (cl-loop for path in targets if (file-exists-p path) - collect path - and do (delete-file path) - and do (message "Deleted %s" (file-relative-name path))) + collect path + and do (delete-file path) + and do (message "Deleted %s" (file-relative-name path))) (message "Everything is clean")))) diff --git a/core/core-projects.el b/core/core-projects.el index a73c76840..f9eee1431 100644 --- a/core/core-projects.el +++ b/core/core-projects.el @@ -48,7 +48,7 @@ state are passed in.") ;; Library ;; -(defun doom/reload-project () +(defun doom//reload-project () "Reload the project root cache." (interactive) (projectile-invalidate-cache nil) diff --git a/core/core-ui.el b/core/core-ui.el index 9913c9db0..7d965686e 100644 --- a/core/core-ui.el +++ b/core/core-ui.el @@ -29,7 +29,7 @@ shorter major mode name in the mode-line. See `doom|set-mode-name'.") ;; Hook(s) (defvar doom-init-ui-hook nil "List of hooks to run when the theme and font is initialized (or reloaded with -`doom/reload-theme').") +`doom//reload-theme').") ;; Settings diff --git a/core/core.el b/core/core.el index 0c083454b..c1825ba06 100644 --- a/core/core.el +++ b/core/core.el @@ -5,6 +5,7 @@ ;; doom-... public variables or non-interactive functions ;; doom--... private anything (non-interactive), not safe for direct use ;; doom/... an interactive function; safe for M-x or keybinding +;; doom//... an interactive function for managing/maintaining Doom itself ;; doom:... an evil operator, motion or command ;; doom|... hook function ;; doom*... advising functions