diff --git a/core/autoload/config.el b/core/autoload/config.el index 02d78d725..2dcd6eee6 100644 --- a/core/autoload/config.el +++ b/core/autoload/config.el @@ -111,7 +111,7 @@ line." (require 'core-cli) (require 'core-packages) (doom-initialize-packages) - (doom-cli-reload-autoloads)) + (doom-autoloads-reload)) ;;;###autoload (defun doom/reload-env (&optional arg) diff --git a/core/cli/autoloads.el b/core/cli/autoloads.el index 09e161919..83077cc50 100644 --- a/core/cli/autoloads.el +++ b/core/cli/autoloads.el @@ -1,129 +1,103 @@ ;;; core/cli/autoloads.el -*- lexical-binding: t; -*- -(defvar doom-autoload-excluded-packages '("gh") +(defvar doom-autoloads-excluded-packages '("gh") "What packages whose autoloads file we won't index. These packages have silly or destructive autoload files that try to load everyone in the universe and their dog, causing errors that make babies cry. No one wants that.") -(defvar doom-autoload-cached-vars - '(load-path +(defvar doom-autoloads-cached-vars + '(doom-modules + doom-disabled-packages + load-path auto-mode-alist interpreter-mode-alist - Info-directory-list - doom-disabled-packages) - "A list of variables to be cached in `doom-package-autoload-file'.") - -;; externs -(defvar autoload-timestamps) -(defvar generated-autoload-load-name) - -(defun doom-cli-reload-autoloads () - "Reloads `doom-autoload-file' and `doom-package-autoload-file' files." - (doom-cli-reload-core-autoloads) - (doom-cli-reload-package-autoloads)) - -(defun doom-cli-reload-core-autoloads (&optional file) - (print! (start "(Re)generating core autoloads...")) - (print-group! - (let ((file (or file doom-autoload-file)) - doom-autoload-cached-vars) - (cl-check-type file string) - (and (print! (start "Generating core autoloads...")) - (doom-cli--write-autoloads - file - (doom-cli--generate-emacs-version-check) - (doom-cli--generate-autoloads - (cl-loop for dir - in (append (list doom-core-dir) - (cdr (doom-module-load-path 'all-p)) - (list doom-private-dir)) - if (doom-glob dir "autoload.el") collect it - if (doom-glob dir "autoload/*.el") append it) - 'scan)) - (print! (start "Byte-compiling core autoloads file...")) - (doom-cli--byte-compile-file file) - (print! (success "Generated %s") - (relpath (byte-compile-dest-file file) - doom-emacs-dir)))))) - -(defun doom-cli-reload-package-autoloads (&optional file) - (print! (start "(Re)generating package autoloads...")) - (print-group! - (doom-initialize-packages) - (let ((file (or file doom-package-autoload-file))) - (cl-check-type file string) - (and (print! (start "Generating package autoloads...")) - (doom-cli--write-autoloads - file - (doom-cli--generate-var-cache doom-autoload-cached-vars) - (doom-cli--generate-autoloads - (mapcar #'straight--autoloads-file - (cl-set-difference (hash-table-keys straight--build-cache) - doom-autoload-excluded-packages - :test #'string=)))) - (print! (start "Byte-compiling package autoloads file...")) - (doom-cli--byte-compile-file file) - (print! (success "Generated %s") - (relpath (byte-compile-dest-file file) - doom-emacs-dir)))))) + Info-directory-list) + "A list of variables to be cached in `doom-autoload-file'.") ;; -;;; Helpers +;;; Library -(defun doom-cli--write-autoloads (file &rest forms) +(defun doom-autoloads-reload (&optional file) + "Regenerates Doom's autoloads and writes them to FILE." + (unless file + (setq file doom-autoload-file)) + (print! (start "(Re)generating autoloads file...")) + (print-group! + (cl-check-type file string) + (doom-initialize-packages) + (and (print! (start "Generating autoloads file...")) + (doom-autoloads--write + file + `((unless (equal emacs-major-version ,emacs-major-version) + (signal 'doom-error + (list "The installed version of Emacs has changed since last 'doom sync' ran" + "Run 'doom sync && doom build' to bring Doom up to speed"))) + (unless (equal doom-version ,doom-version) + (signal 'doom-error + (list "The installed version of Doom has changed since last 'doom sync' ran" + "Run 'doom sync' to bring Doom up to speed")))) + (mapcar (lambda (var) `(set ',var ',(symbol-value var))) + doom-autoloads-cached-vars) + (doom-autoloads--scan + (cl-loop for dir + in (append (list doom-core-dir) + (cdr (doom-module-load-path 'all-p)) + (list doom-private-dir)) + if (doom-glob dir "autoload.el") collect it + if (doom-glob dir "autoload/*.el") append it)) + (doom-autoloads--scan + (mapcar #'straight--autoloads-file + (cl-set-difference (hash-table-keys straight--build-cache) + doom-autoloads-excluded-packages + :test #'equal)) + 'literal)) + (print! (start "Byte-compiling autoloads file...")) + (doom-autoloads--compile-file file) + (print! (success "Generated %s") + (relpath (byte-compile-dest-file file) + doom-emacs-dir))))) + +(defun doom-autoloads--write (file &rest forms) (make-directory (file-name-directory file) 'parents) (condition-case-unless-debug e (with-temp-file file + (setq-local coding-system-for-write 'utf-8) (let ((standard-output (current-buffer)) (print-quoted t) (print-level nil) (print-length nil)) - (insert ";; -*- lexical-binding: t; -*-\n" - ";; This file is autogenerated by Doom, DO NOT EDIT IT!!\n") + (insert ";; -*- lexical-binding: t; coding: utf-8; -*-\n" + ";; This file is autogenerated by 'doom sync', DO NOT EDIT IT!!\n") (dolist (form (delq nil forms)) - (mapc #'print form)) + (mapc #'prin1 form)) t)) (error (delete-file file) (signal 'doom-autoload-error (list file e))))) -(defun doom-cli--byte-compile-file (file) +(defun doom-autoloads--compile-file (file) (condition-case-unless-debug e - (let ((byte-compile-warnings (if doom-debug-p byte-compile-warnings)) - (byte-compile-dynamic-docstrings t)) + (let ((byte-compile-warnings (if doom-debug-p byte-compile-warnings))) (when (byte-compile-file file) (unless doom-interactive-p - (add-hook 'doom-cli-post-success-execute-hook #'doom-cli--warn-refresh-session-h)) + (add-hook 'kill-emacs-hook #'doom-cli--warn-refresh-session-h)) (load (byte-compile-dest-file file) nil t))) (error (delete-file (byte-compile-dest-file file)) (signal 'doom-autoload-error (list file e))))) (defun doom-cli--warn-refresh-session-h () - (print! "Restart or reload Doom Emacs for changes to take effect:") - (print-group! (print! "M-x doom/restart-and-restore") - (print! "M-x doom/restart") - (print! "M-x doom/reload"))) + (print! (info "Restart or 'M-x doom/reload' Doom Emacs for changes to take effect"))) -(defun doom-cli--generate-emacs-version-check () - `((unless (equal emacs-major-version (eval-when-compile emacs-major-version)) - (signal 'doom-error - (list "Your installed (major) version of Emacs has changed" - "Run 'doom sync && doom build' to bring Doom up to speed"))))) - -(defun doom-cli--generate-var-cache (vars) - `((setq ,@(cl-loop for var in vars - append `(,var ',(symbol-value var)))))) - -(defun doom-cli--filter-form (form &optional expand) +(defun doom-autoloads--cleanup-form (form &optional expand) (let ((func (car-safe form))) (cond ((memq func '(provide custom-autoload)) nil) ((and (eq func 'add-to-list) (memq (doom-unquote (cadr form)) - doom-autoload-cached-vars)) + doom-autoloads-cached-vars)) nil) ((not (eq func 'autoload)) form) @@ -141,7 +115,7 @@ one wants that.") form) (form)))) -(defun doom-cli--generate-autoloads-autodefs (file buffer module &optional module-enabled-p) +(defun doom-autoloads--scan-autodefs (file buffer module &optional module-enabled-p) (with-temp-buffer (insert-file-contents file) (while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t) @@ -190,7 +164,9 @@ one wants that.") (print `(defalias ',symbol #',(doom-unquote target) ,docstring)))) (module-enabled-p (print form))))))) -(defun doom-cli--generate-autoloads-buffer (file) +(defvar autoload-timestamps) +(defvar generated-autoload-load-name) +(defun doom-autoloads--scan-file (file) (let* (;; Prevent `autoload-find-file' from firing file hooks, e.g. adding ;; to recentf. find-file-hook @@ -214,10 +190,10 @@ one wants that.") (save-excursion (when module-enabled-p (quiet! (autoload-generate-file-autoloads file target-buffer))) - (doom-cli--generate-autoloads-autodefs + (doom-autoloads--scan-autodefs file target-buffer module module-enabled-p)))) -(defun doom-cli--generate-autoloads (files &optional scan) +(defun doom-autoloads--scan (files &optional literal) (require 'autoload) (let (autoloads) (dolist (file @@ -225,9 +201,9 @@ one wants that.") (nreverse (delq nil autoloads))) (with-temp-buffer (print! (debug "- Scanning %s") (relpath file doom-emacs-dir)) - (if scan - (doom-cli--generate-autoloads-buffer file) - (insert-file-contents file)) + (if literal + (insert-file-contents file) + (doom-autoloads--scan-file file)) (save-excursion (let ((filestr (prin1-to-string file))) (while (re-search-forward "\\_" nil t) @@ -245,7 +221,7 @@ one wants that.") load-path))) (condition-case _ (while t - (push (doom-cli--filter-form (read (current-buffer)) - scan) + (push (doom-autoloads--cleanup-form (read (current-buffer)) + (not literal)) autoloads)) (end-of-file))))))) diff --git a/core/cli/install.el b/core/cli/install.el index f5082d698..ef4bc5614 100644 --- a/core/cli/install.el +++ b/core/cli/install.el @@ -83,7 +83,7 @@ DOOMDIR environment variable. e.g. (doom-cli-packages-install)) (print! "Regenerating autoloads files") - (doom-cli-reload-autoloads) + (doom-autoloads-reload) (cond (nofonts-p) (IS-WINDOWS diff --git a/core/cli/packages.el b/core/cli/packages.el index dd15c4d12..c6c9e69f1 100644 --- a/core/cli/packages.el +++ b/core/cli/packages.el @@ -12,9 +12,8 @@ This excludes packages whose `package!' declaration contains a non-nil :freeze or :ignore property." (straight-check-all) (let ((doom-auto-discard discard-p)) - (doom-cli-reload-core-autoloads) (when (doom-cli-packages-update) - (doom-cli-reload-package-autoloads)) + (doom-autoloads-reload)) t)) (defcli! (build b) @@ -25,7 +24,7 @@ This ensures that all needed files are symlinked from their package repo and their elisp files are byte-compiled. This is especially necessary if you upgrade Emacs (as byte-code is generally not forward-compatible)." (when (doom-cli-packages-build (not rebuild-p)) - (doom-cli-reload-package-autoloads)) + (doom-autoloads-reload)) t) (defcli! (purge p) @@ -48,7 +47,7 @@ list remains lean." (not norepos-p) (not nobuilds-p) regraft-p) - (doom-cli-reload-package-autoloads)) + (doom-autoloads-reload)) t) ;; (defcli! rollback () ; TODO doom rollback diff --git a/core/cli/upgrade.el b/core/cli/upgrade.el index 5fa4aa17c..5c592dc4c 100644 --- a/core/cli/upgrade.el +++ b/core/cli/upgrade.el @@ -21,7 +21,7 @@ following shell commands: (doom-cli-upgrade doom-auto-accept doom-auto-discard)) (doom-cli-execute "sync") (when (doom-cli-packages-update) - (doom-cli-reload-package-autoloads) + (doom-autoloads-reload) t))) (print! (success "Done! Restart Emacs for changes to take effect.")) (print! "Nothing to do. Doom is up-to-date!")))) diff --git a/core/core-cli.el b/core/core-cli.el index fd66362ec..ea7337b58 100644 --- a/core/core-cli.el +++ b/core/core-cli.el @@ -371,16 +371,16 @@ installed, autoloads files are up-to-date and no byte-compiled files have gone stale." (print! (start "Synchronizing your config with Doom Emacs...")) (print-group! - (and (not inhibit-envvar-p) - (file-exists-p doom-env-file) - (doom-cli-reload-env-file 'force)) - (doom-cli-reload-core-autoloads) + (delete-file doom-autoload-file) + (when (and (not inhibit-envvar-p) + (file-exists-p doom-env-file)) + (doom-cli-reload-env-file 'force)) (doom-cli-packages-install) (doom-cli-packages-build) (when update-p (doom-cli-packages-update)) (doom-cli-packages-purge prune-p 'builds-p prune-p prune-p) - (doom-cli-reload-package-autoloads) + (doom-autoloads-reload) t)) (load! "cli/env") diff --git a/core/core-lib.el b/core/core-lib.el index 1f44c06ff..b505a9070 100644 --- a/core/core-lib.el +++ b/core/core-lib.el @@ -93,20 +93,6 @@ Meant to be used with `run-hook-wrapped'." ;; return nil so `run-hook-wrapped' won't short circuit nil) -(defun doom-load-autoloads-file (file &optional noerror) - "Tries to load FILE (an autoloads file). -Return t on success, nil otherwise (but logs a warning)." - (condition-case e - ;; Avoid `file-name-sans-extension' for premature optimization reasons. - ;; `string-remove-suffix' is much cheaper (because it does no file sanity - ;; checks during or after; just plain ol' string manipulation). - (load (string-remove-suffix ".el" file) noerror 'nomessage) - (doom-error - (signal (car e) (cdr e))) - ((debug error) - (message "Autoload file error: %s -> %s" (file-name-nondirectory file) e) - nil))) - (defun doom-load-envvars-file (file &optional noerror) "Read and set envvars from FILE. If NOERROR is non-nil, don't throw an error if the file doesn't exist or is diff --git a/core/core.el b/core/core.el index aa910d235..e36d9e22a 100644 --- a/core/core.el +++ b/core/core.el @@ -127,12 +127,6 @@ whichever is found first. Must end in a slash.") This file is responsible for informing Emacs where to find all of Doom's autoloaded core functions (in core/autoload/*.el).") -(defconst doom-package-autoload-file (concat doom-local-dir "autoloads.pkg.el") - "Where `doom-reload-package-autoloads' stores its package autoloads. - -This file is compiled from the autoloads files of all installed packages -combined.") - (defconst doom-env-file (concat doom-local-dir "env") "The location of your envvar file, generated by `doom env`. @@ -487,23 +481,23 @@ to least)." load-path doom--initial-load-path process-environment doom--initial-process-environment) - (or (and - ;; `doom-autoload-file' tells Emacs where to load all its functions - ;; from. This includes everything in core/autoload/*.el and - ;; autoload files in enabled modules. - (or (doom-load-autoloads-file doom-autoload-file) - (ignore (warn "Doom's core autoloads file is missing"))) - ;; Loads `doom-package-autoload-file', which loads a concatenated - ;; package autoloads file which caches `load-path', - ;; `auto-mode-alist', `Info-directory-list', and - ;; `doom-disabled-packages'. A big reduction in startup time. - (or (doom-load-autoloads-file doom-package-autoload-file) - (ignore (warn "Doom's package autoloads file is missing")))) - ;; If neither autoloads file loads, then the user forgot to sync, or - ;; aborted a doom command midway! - (signal 'doom-error - (list "Doom is in an incomplete state" - "run 'bin/doom sync' on the command line to repair it"))) + ;; Doom caches a lot of information in `doom-autoload-file'. Module and + ;; package autoloads, autodefs like `set-company-backend!', and variables + ;; like `doom-modules', `doom-disabled-packages', `load-path', + ;; `auto-mode-alist', and `Info-directory-list'. etc. Compiling them into + ;; one place is a big reduction in startup time. + (condition-case e + ;; Avoid `file-name-sans-extension' for premature optimization reasons. + ;; `string-remove-suffix' is cheaper because it performs no file sanity + ;; checks; just plain ol' string manipulation. + (load (string-remove-suffix ".el" doom-autoload-file) + nil 'nomessage) + (file-missing + ;; If the autoloads file fails to load then the user forgot to sync, or + ;; aborted a doom command midway! + (signal 'doom-error + (list "Doom is in an incomplete state" + "run 'bin/doom sync' on the command line to repair it")))) ;; Load shell environment, optionally generated from 'doom env'. No need ;; to do so if we're in terminal Emacs, where Emacs correctly inherits