Refactor autoload generator, plus autodef support
Soon, autodefs will replace settings (i.e. def-setting! & set!). This refactor prepares for it.
This commit is contained in:
parent
b2b6ff67f2
commit
f44ebbb7ed
1 changed files with 189 additions and 99 deletions
|
@ -330,6 +330,10 @@ one wants that.")
|
|||
it exists."
|
||||
(cl-check-type file string)
|
||||
(when (file-exists-p file)
|
||||
(when-let* ((buf (find-buffer-visiting doom-autoload-file)))
|
||||
(with-current-buffer buf
|
||||
(set-buffer-modified-p nil))
|
||||
(kill-buffer buf))
|
||||
(delete-file file)
|
||||
(ignore-errors (delete-file (byte-compile-dest-file file)))
|
||||
(message "Deleted old %s" (file-name-nondirectory file))))
|
||||
|
@ -372,7 +376,103 @@ even if it doesn't need reloading!"
|
|||
(doom//reload-doom-autoloads force-p)
|
||||
(doom//reload-package-autoloads force-p)))))
|
||||
|
||||
(defvar generated-autoload-load-name)
|
||||
|
||||
;;
|
||||
;; Doom autoloads
|
||||
;;
|
||||
|
||||
(defun doom--generate-header (func)
|
||||
(goto-char (point-min))
|
||||
(insert ";; -*- lexical-binding:t -*-\n"
|
||||
";; This file is autogenerated by `" (symbol-name func) "', DO NOT EDIT !!\n\n"))
|
||||
|
||||
(defun doom--generate-autoloads (targets)
|
||||
(require 'autoload)
|
||||
(dolist (file targets)
|
||||
(let* ((file (file-truename file))
|
||||
(generated-autoload-file doom-autoload-file)
|
||||
(generated-autoload-load-name (file-name-sans-extension file))
|
||||
(noninteractive (not doom-debug-mode))
|
||||
autoload-timestamps)
|
||||
(print!
|
||||
(cond ((not (doom-file-cookie-p file))
|
||||
"⚠ Ignoring %s")
|
||||
((autoload-generate-file-autoloads file (current-buffer))
|
||||
(yellow "✕ Nothing in %%s"))
|
||||
((green "✓ Scanned %%s")))
|
||||
(if (file-in-directory-p file default-directory)
|
||||
(file-relative-name file)
|
||||
(abbreviate-file-name file))))))
|
||||
|
||||
(defun doom--expand-autoloads ()
|
||||
(let ((load-path (append doom-modules-dirs load-path))
|
||||
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)
|
||||
path)
|
||||
t t nil 1)))))
|
||||
|
||||
(defun doom--generate-autodefs (targets enabled-targets)
|
||||
(goto-char (point-max))
|
||||
(search-backward ";;;***" nil t)
|
||||
(save-excursion (insert "\n"))
|
||||
(dolist (path targets)
|
||||
(insert
|
||||
(with-temp-buffer
|
||||
(insert-file-contents path)
|
||||
(let ((member-p (or (member path enabled-targets)
|
||||
(file-in-directory-p path doom-core-dir)))
|
||||
forms sexp cond)
|
||||
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
|
||||
(setq sexp (sexp-at-point)
|
||||
cond (match-string 1))
|
||||
(when cond
|
||||
(setq cond (read cond)))
|
||||
(let* ((type (car sexp))
|
||||
(name (nth 1 sexp))
|
||||
(arglist (nth 2 sexp))
|
||||
(docstring (format "(Actually defined in %s)\n\n%s"
|
||||
(abbreviate-file-name path)
|
||||
(if (stringp (nth 3 sexp)) (nth 3 sexp) "No docstring")))
|
||||
(body (cdddr (if (stringp (nth 3 sexp)) (cdr sexp) sexp))))
|
||||
(cond ((not (memq type '(defun defmacro cl-defun cl-defmacro)))
|
||||
(message "Ignoring invalid autodef %s (found %s)"
|
||||
name type))
|
||||
((and member-p
|
||||
(or (null cond)
|
||||
(eval cond t)))
|
||||
(push (if (memq type '(defmacro cl-defmacro))
|
||||
sexp
|
||||
(make-autoload sexp path))
|
||||
forms))
|
||||
(sexp
|
||||
(condition-case e
|
||||
(push (append (list 'defmacro name arglist docstring)
|
||||
(cl-loop for arg in arglist
|
||||
if (and (symbolp arg)
|
||||
(not (keywordp arg))
|
||||
(not (memq arg cl--lambda-list-keywords)))
|
||||
collect (list 'ignore arg)))
|
||||
forms)
|
||||
('error
|
||||
(message "Ignoring autodef %s (%s)"
|
||||
name e)))))))
|
||||
(if forms
|
||||
(concat (string-join (mapcar #'prin1-to-string forms) "\n")
|
||||
"\n")
|
||||
""))))))
|
||||
|
||||
(defun doom--cleanup-autoloads ()
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^;;\\(;[^\n]*\\| no-byte-compile: t\\)\n" nil t)
|
||||
(replace-match "" t t)))
|
||||
|
||||
(defun doom//reload-doom-autoloads (&optional force-p)
|
||||
"Refreshes the autoloads.el file, specified by `doom-autoload-file', if
|
||||
necessary (or if FORCE-P is non-nil).
|
||||
|
@ -384,18 +484,25 @@ Emacs where to find lazy-loaded functions.
|
|||
This should be run whenever your `doom!' block, or a module autoload file, is
|
||||
modified."
|
||||
(interactive)
|
||||
(let ((default-directory doom-emacs-dir)
|
||||
(targets
|
||||
(file-expand-wildcards
|
||||
(expand-file-name "autoload/*.el" doom-core-dir))))
|
||||
(dolist (path (doom-module-load-path))
|
||||
(let ((auto-dir (expand-file-name "autoload" path))
|
||||
(auto-file (expand-file-name "autoload.el" path)))
|
||||
(let* ((default-directory doom-emacs-dir)
|
||||
(doom-modules (doom-modules))
|
||||
(targets
|
||||
(file-expand-wildcards
|
||||
(expand-file-name "autoload/*.el" doom-core-dir)))
|
||||
(enabled-targets (copy-sequence targets))
|
||||
case-fold-search)
|
||||
(dolist (path (doom-module-load-path t))
|
||||
(let* ((auto-dir (expand-file-name "autoload" path))
|
||||
(auto-file (expand-file-name "autoload.el" path))
|
||||
(module (doom-module-from-path auto-file))
|
||||
(module-p (or (doom-module-p (car module) (cdr module))
|
||||
(file-equal-p path doom-private-dir))))
|
||||
(when (file-exists-p auto-file)
|
||||
(push auto-file targets))
|
||||
(when (file-directory-p auto-dir)
|
||||
(dolist (file (doom-files-in auto-dir :match "\\.el$" :full t))
|
||||
(push file targets)))))
|
||||
(push auto-file targets)
|
||||
(if module-p (push auto-file enabled-targets)))
|
||||
(dolist (file (doom-files-in auto-dir :match "\\.el$" :full t))
|
||||
(push file targets)
|
||||
(if module-p (push file enabled-targets)))))
|
||||
(if (and (not force-p)
|
||||
(not doom-emacs-changed-p)
|
||||
(file-exists-p doom-autoload-file)
|
||||
|
@ -404,65 +511,70 @@ modified."
|
|||
(not (cl-loop for file in targets
|
||||
if (file-newer-than-file-p file doom-autoload-file)
|
||||
return t)))
|
||||
(ignore (print! (green "Doom core autoloads is up-to-date"))
|
||||
(doom-initialize-autoloads doom-autoload-file))
|
||||
(progn (print! (green "Doom core autoloads is up-to-date"))
|
||||
(doom-initialize-autoloads doom-autoload-file)
|
||||
nil)
|
||||
(doom-delete-autoloads-file doom-autoload-file)
|
||||
;; in case the buffer is open somewhere and modified
|
||||
(when-let* ((buf (find-buffer-visiting doom-autoload-file)))
|
||||
(with-current-buffer buf
|
||||
(set-buffer-modified-p nil))
|
||||
(kill-buffer buf))
|
||||
(message "Generating new autoloads.el")
|
||||
(dolist (file (nreverse targets))
|
||||
(let* ((file (file-truename file))
|
||||
(generated-autoload-load-name (file-name-sans-extension file))
|
||||
(noninteractive (not doom-debug-mode)))
|
||||
(print!
|
||||
(cond ((not (doom-file-cookie-p file))
|
||||
"⚠ Ignoring %s")
|
||||
((update-file-autoloads file nil doom-autoload-file)
|
||||
(yellow "✕ Nothing in %%s"))
|
||||
((green "✓ 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))
|
||||
case-fold-search)
|
||||
(unwind-protect
|
||||
(with-current-buffer buf
|
||||
(goto-char (point-min))
|
||||
(insert ";;; -*- lexical-binding:t -*-\n"
|
||||
";; This file is autogenerated by `doom//reload-doom-autoloads', DO NOT EDIT !!\n\n")
|
||||
(save-excursion
|
||||
;; Replace autoload paths (only for module autoloads) with
|
||||
;; absolute paths for faster resolution during load and
|
||||
;; simpler `load-path'
|
||||
(let ((load-path (append doom-modules-dirs load-path))
|
||||
cache)
|
||||
(save-excursion
|
||||
(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)
|
||||
path)
|
||||
t t nil 1)))
|
||||
(print! (green "✓ Autoload paths expanded")))))
|
||||
;; 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))
|
||||
;; Byte compile it to give the file a chance to reveal errors.
|
||||
(save-buffer)
|
||||
(doom--byte-compile-file doom-autoload-file)
|
||||
(when (and noninteractive (not (daemonp)))
|
||||
(doom--server-load doom-autoload-file))
|
||||
t)
|
||||
(kill-buffer buf))))))
|
||||
(with-temp-file doom-autoload-file
|
||||
(doom--generate-header 'doom//reload-doom-autoloads)
|
||||
(save-excursion
|
||||
(doom--generate-autoloads (reverse enabled-targets)))
|
||||
;; Replace autoload paths (only for module autoloads) with absolute
|
||||
;; paths for faster resolution during load and simpler `load-path'
|
||||
(save-excursion
|
||||
(doom--expand-autoloads)
|
||||
(print! (green "✓ Expanded module autoload paths")))
|
||||
;; Generates stub definitions for functions/macros defined in disabled
|
||||
;; modules, so that you will never get a void-function when you use
|
||||
;; them.
|
||||
(save-excursion
|
||||
(doom--generate-autodefs (reverse targets) enabled-targets))
|
||||
;; Remove byte-compile inhibiting file variables so we can byte-compile
|
||||
;; the file, and autoload comments.
|
||||
(doom--cleanup-autoloads)
|
||||
(print! (green "✓ Clean up autoloads")))
|
||||
;; Byte compile it to give the file a chance to reveal errors.
|
||||
(doom--byte-compile-file doom-autoload-file)
|
||||
(when (and noninteractive (not (daemonp)))
|
||||
(doom--server-load doom-autoload-file))
|
||||
t)))
|
||||
|
||||
|
||||
;;
|
||||
;; Package autoloads
|
||||
;;
|
||||
|
||||
(defun doom--generate-package-autoloads ()
|
||||
(dolist (spec (doom-get-package-alist))
|
||||
(if-let* ((pkg (car spec))
|
||||
(desc (cdr spec)))
|
||||
(unless (memq pkg doom-autoload-excluded-packages)
|
||||
(let ((file (concat (package--autoloads-file-name desc) ".el")))
|
||||
(when (file-exists-p file)
|
||||
(insert "(let ((load-file-name " (prin1-to-string (abbreviate-file-name file)) "))\n")
|
||||
(insert-file-contents file)
|
||||
(while (re-search-forward "^\\(?:;;\\(.*\n\\)\\|\n\\|(provide '[^\n]+\\)" nil t)
|
||||
(unless (nth 8 (syntax-ppss))
|
||||
(replace-match "" t t)))
|
||||
(unless (bolp) (insert "\n"))
|
||||
(insert ")\n"))))
|
||||
(message "Couldn't find package desc for %s" (car spec)))))
|
||||
|
||||
(defun doom--generate-var-cache ()
|
||||
(doom-initialize-packages)
|
||||
(prin1 `(setq load-path ',load-path
|
||||
auto-mode-alist ',auto-mode-alist
|
||||
Info-directory-list ',Info-directory-list
|
||||
doom-disabled-packages ',doom-disabled-packages
|
||||
package-activated-list ',package-activated-list)
|
||||
(current-buffer)))
|
||||
|
||||
(defun doom--cleanup-package-autoloads ()
|
||||
(while (re-search-forward "^\\s-*\\((\\(?:add-to-list\\|\\(?:when\\|if\\) (boundp\\)\\s-+'\\(?:load-path\\|auto-mode-alist\\)\\)" nil t)
|
||||
(goto-char (match-beginning 1))
|
||||
(kill-sexp)))
|
||||
|
||||
(defun doom//reload-package-autoloads (&optional force-p)
|
||||
"Compiles `doom-package-autoload-file' from the autoloads files of all
|
||||
|
@ -485,43 +597,21 @@ This should be run whenever your `doom!' block or update your packages."
|
|||
return t))))
|
||||
(ignore (print! (green "Doom package autoloads is up-to-date"))
|
||||
(doom-initialize-autoloads doom-package-autoload-file))
|
||||
(doom-delete-autoloads-file doom-package-autoload-file)
|
||||
(with-temp-file doom-package-autoload-file
|
||||
(insert ";;; -*- lexical-binding:t -*-\n"
|
||||
";; This file is autogenerated by `doom//reload-package-autoloads', DO NOT EDIT !!\n\n")
|
||||
(let (case-fold-search)
|
||||
(let (case-fold-search)
|
||||
(doom-delete-autoloads-file doom-package-autoload-file)
|
||||
(with-temp-file doom-package-autoload-file
|
||||
(doom--generate-header 'doom//reload-package-autoloads)
|
||||
(save-excursion
|
||||
;; Cache the important and expensive-to-initialize state here.
|
||||
(doom-initialize-packages)
|
||||
(prin1 `(setq load-path ',load-path
|
||||
auto-mode-alist ',auto-mode-alist
|
||||
Info-directory-list ',Info-directory-list
|
||||
doom-disabled-packages ',doom-disabled-packages
|
||||
package-activated-list ',package-activated-list)
|
||||
(current-buffer))
|
||||
(doom--generate-var-cache)
|
||||
(print! (green "✓ Cached package state"))
|
||||
;; insert package autoloads
|
||||
(dolist (spec (doom-get-package-alist))
|
||||
(if-let* ((pkg (car spec))
|
||||
(desc (cdr spec)))
|
||||
(unless (memq pkg doom-autoload-excluded-packages)
|
||||
(let ((file (concat (package--autoloads-file-name desc) ".el")))
|
||||
(when (file-exists-p file)
|
||||
(insert "(let ((load-file-name " (prin1-to-string (abbreviate-file-name file)) "))\n")
|
||||
(insert-file-contents file)
|
||||
(while (re-search-forward "^\\(?:;;\\(.*\n\\)\\|\n\\|(provide '[^\n]+\\)" nil t)
|
||||
(unless (nth 8 (syntax-ppss))
|
||||
(replace-match "" t t)))
|
||||
(unless (bolp) (insert "\n"))
|
||||
(insert ")\n"))))
|
||||
(print! (yellow "⚠ Couldn't find package desc for %s" (car spec))))))
|
||||
(print! (green "✓ Package autoloads included"))
|
||||
;; Loop through packages and concatenate all their autoloads files.
|
||||
(doom--generate-package-autoloads)
|
||||
(print! (green "✓ Package autoloads included")))
|
||||
;; Remove `load-path' and `auto-mode-alist' modifications (most of them,
|
||||
;; at least); they are cached later, so all those membership checks are
|
||||
;; unnecessary overhead.
|
||||
(while (re-search-forward "^\\s-*\\((\\(?:add-to-list\\|\\(?:when\\|if\\) (boundp\\)\\s-+'\\(?:load-path\\|auto-mode-alist\\)\\)" nil t)
|
||||
(goto-char (match-beginning 1))
|
||||
(kill-sexp))
|
||||
(doom--cleanup-package-autoloads)
|
||||
(print! (green "✓ Removed load-path/auto-mode-alist entries"))))
|
||||
(doom--byte-compile-file doom-package-autoload-file)
|
||||
(when (and noninteractive (not (daemonp)))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue