Stability/error-handling refactor (part 1)
This refactor is about improving how Emacs deals with errors. A large net is now cast at startup to catch possible errors, produce more helpful error messages, and localize the damage. Significantly reducing the risk of later modules not loading (and leaving you stranded in a half-broken Emacs session). The DOOM core files are an exception. If something messes up in there, it *should* choke. + use-package will now report missing packages or slow-loading/broken def-package! configurations. + Persp-mode no longer (inadvertantly) hides buffers that pop up at startup, like the *Warnings*, *Backtrace* or debugger buffers. + `make autoloads` (or doom/reload-autoloads) now produces a slightly more informative error message if an error occurs while building the autoloads file. + Error handling for package management is *slightly* better now; error messages now include the type of error; this needs work.
This commit is contained in:
parent
55f0760c4e
commit
732dee608a
5 changed files with 87 additions and 49 deletions
|
@ -153,7 +153,7 @@
|
||||||
(gnutls-verify-error t))
|
(gnutls-verify-error t))
|
||||||
(dolist (url '("https://elpa.gnu.org/packages/archive-contents"
|
(dolist (url '("https://elpa.gnu.org/packages/archive-contents"
|
||||||
"https://melpa.org/packages/archive-contents"))
|
"https://melpa.org/packages/archive-contents"))
|
||||||
(condition-case ex
|
(condition-case-unless-debug ex
|
||||||
(let (result)
|
(let (result)
|
||||||
(let ((inhibit-message t))
|
(let ((inhibit-message t))
|
||||||
(url-retrieve url (lambda (status &rest _) (setq result status))))
|
(url-retrieve url (lambda (status &rest _) (setq result status))))
|
||||||
|
@ -169,7 +169,7 @@
|
||||||
(explain! (pp-to-string ex))))))
|
(explain! (pp-to-string ex))))))
|
||||||
(dolist (url '("https://self-signed.badssl.com"
|
(dolist (url '("https://self-signed.badssl.com"
|
||||||
"https://wrong.host.badssl.com/"))
|
"https://wrong.host.badssl.com/"))
|
||||||
(condition-case ex
|
(condition-case-unless-debug ex
|
||||||
(let (result)
|
(let (result)
|
||||||
(let ((inhibit-message t))
|
(let ((inhibit-message t))
|
||||||
(url-retrieve url (lambda (status &rest _) (setq result status))))
|
(url-retrieve url (lambda (status &rest _) (setq result status))))
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
(doom-refresh-clear-cache))
|
(doom-refresh-clear-cache))
|
||||||
(unless (or (persistent-soft-fetch 'last-pkg-refresh "emacs")
|
(unless (or (persistent-soft-fetch 'last-pkg-refresh "emacs")
|
||||||
doom--refresh-p)
|
doom--refresh-p)
|
||||||
(condition-case ex
|
(condition-case-unless-debug ex
|
||||||
(progn
|
(progn
|
||||||
(message "Refreshing package archives")
|
(message "Refreshing package archives")
|
||||||
(package-refresh-contents (not doom-debug-mode))
|
(package-refresh-contents (not doom-debug-mode))
|
||||||
|
@ -19,9 +19,10 @@
|
||||||
(<= i 10))
|
(<= i 10))
|
||||||
do (sleep-for 0 250))
|
do (sleep-for 0 250))
|
||||||
(persistent-soft-store 'last-pkg-refresh t "emacs" 900))
|
(persistent-soft-store 'last-pkg-refresh t "emacs" 900))
|
||||||
(error
|
('error
|
||||||
(doom-refresh-clear-cache)
|
(doom-refresh-clear-cache)
|
||||||
(message "Failed to refresh packages: %s" (cadr ex))))))
|
(message "Failed to refresh packages: (%s) %s"
|
||||||
|
(car ex) (error-message-string ex))))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-refresh-clear-cache ()
|
(defun doom-refresh-clear-cache ()
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
(defun doom-package-backend (name)
|
(defun doom-package-backend (name)
|
||||||
"Get which backend the package NAME was installed with. Can either be elpa,
|
"Get which backend the package NAME was installed with. Can either be elpa,
|
||||||
quelpa or nil (if not installed)."
|
quelpa or nil (if not installed)."
|
||||||
|
(cl-assert (symbolp name) t)
|
||||||
(doom-initialize-packages)
|
(doom-initialize-packages)
|
||||||
(cond ((let ((plist (cdr (assq name doom-packages))))
|
(cond ((let ((plist (cdr (assq name doom-packages))))
|
||||||
(and (not (plist-get plist :pin))
|
(and (not (plist-get plist :pin))
|
||||||
|
@ -51,6 +53,7 @@ quelpa or nil (if not installed)."
|
||||||
"Determine whether NAME (a symbol) is outdated or not. If outdated, returns a
|
"Determine whether NAME (a symbol) is outdated or not. If outdated, returns a
|
||||||
list, whose car is NAME, and cdr the current version list and latest version
|
list, whose car is NAME, and cdr the current version list and latest version
|
||||||
list of the package."
|
list of the package."
|
||||||
|
(cl-assert (symbolp name) t)
|
||||||
(doom-initialize-packages)
|
(doom-initialize-packages)
|
||||||
(when-let (pkg (assq name package-alist))
|
(when-let (pkg (assq name package-alist))
|
||||||
(let* ((old-version (package-desc-version (cadr pkg)))
|
(let* ((old-version (package-desc-version (cadr pkg)))
|
||||||
|
@ -191,29 +194,23 @@ Used by `doom/packages-install'."
|
||||||
table))))
|
table))))
|
||||||
|
|
||||||
(defmacro doom--condition-case! (&rest body)
|
(defmacro doom--condition-case! (&rest body)
|
||||||
`(condition-case ex
|
`(condition-case-unless-debug ex
|
||||||
(condition-case ex2
|
(condition-case ex2
|
||||||
(progn ,@body)
|
(progn ,@body)
|
||||||
('file-error
|
('file-error
|
||||||
(message! (bold (red " FILE ERROR: %s" ex2)))
|
(message! (bold (red " FILE ERROR: %s" (error-message-string ex2))))
|
||||||
(message! " Trying again...")
|
(message! " Trying again...")
|
||||||
(doom-refresh-packages t)
|
(doom-refresh-packages t)
|
||||||
,@body))
|
,@body))
|
||||||
('user-error
|
('user-error
|
||||||
(message! (bold (red " ERROR: %s" ex))))
|
(message! (bold (red " ERROR: (%s) %s"
|
||||||
|
(upcase (symbol-name (car ex)))
|
||||||
|
(error-message-string ex)))))
|
||||||
('error
|
('error
|
||||||
(doom-refresh-clear-cache)
|
(doom-refresh-clear-cache)
|
||||||
(message! (bold (red " FATAL ERROR: %s" ex)))
|
(message! (bold (red " FATAL ERROR: (%s) %s"
|
||||||
(when doom-debug-mode
|
(upcase (symbol-name (car ex)))
|
||||||
(with-temp-buffer
|
(error-message-string ex)))))))
|
||||||
(insert
|
|
||||||
(pp-to-string
|
|
||||||
(cl-loop for i from 2
|
|
||||||
for frame = (backtrace-frame i)
|
|
||||||
while frame
|
|
||||||
collect frame)))
|
|
||||||
(indent-code-rigidly (point-min) (point-max) 4)
|
|
||||||
(message! "%s" (buffer-string)))))))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -104,7 +104,6 @@ base by `doom!' and for calculating how many packages exist.")
|
||||||
|
|
||||||
use-package-always-defer t
|
use-package-always-defer t
|
||||||
use-package-always-ensure nil
|
use-package-always-ensure nil
|
||||||
use-package-expand-minimally (not doom-debug-mode)
|
|
||||||
use-package-debug nil
|
use-package-debug nil
|
||||||
use-package-verbose doom-debug-mode
|
use-package-verbose doom-debug-mode
|
||||||
use-package-minimum-reported-time (if doom-debug-mode 0 0.1)
|
use-package-minimum-reported-time (if doom-debug-mode 0 0.1)
|
||||||
|
@ -189,9 +188,14 @@ This aggressively reloads core autoload files."
|
||||||
(let ((noninteractive t)
|
(let ((noninteractive t)
|
||||||
(load-fn
|
(load-fn
|
||||||
(lambda (file &optional noerror)
|
(lambda (file &optional noerror)
|
||||||
(condition-case ex
|
(condition-case-unless-debug ex
|
||||||
(load file noerror :nomessage :nosuffix)
|
(load file noerror :nomessage :nosuffix)
|
||||||
('error (message "INIT-PACKAGES ERROR (%s): %s" file ex))))))
|
('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))
|
(when (or force-p (not doom-modules))
|
||||||
(setq doom-modules nil)
|
(setq doom-modules nil)
|
||||||
(funcall load-fn (expand-file-name "init.el" doom-emacs-dir))
|
(funcall load-fn (expand-file-name "init.el" doom-emacs-dir))
|
||||||
|
@ -248,10 +252,12 @@ This aggressively reloads core autoload files."
|
||||||
|
|
||||||
(defun doom--module-pairs ()
|
(defun doom--module-pairs ()
|
||||||
"Returns `doom-modules' as a list of (MODULE . SUBMODULE) cons cells. The list
|
"Returns `doom-modules' as a list of (MODULE . SUBMODULE) cons cells. The list
|
||||||
is sorted by order of insertion."
|
is sorted by order of insertion unless ALL-P is non-nil. If ALL-P is non-nil,
|
||||||
(when (hash-table-p doom-modules)
|
include all modules, enabled or otherwise."
|
||||||
|
(if (hash-table-p doom-modules)
|
||||||
(cl-loop for key being the hash-keys of doom-modules
|
(cl-loop for key being the hash-keys of doom-modules
|
||||||
collect (cons (car key) (cdr key)))))
|
collect (cons (car key) (cdr key)))
|
||||||
|
(error "doom-modules is uninitialized")))
|
||||||
|
|
||||||
(defun doom--module-paths (&optional append-file)
|
(defun doom--module-paths (&optional append-file)
|
||||||
"Returns a list of absolute file paths to modules, with APPEND-FILE added, if
|
"Returns a list of absolute file paths to modules, with APPEND-FILE added, if
|
||||||
|
@ -290,7 +296,8 @@ Used by `require!' and `depends-on!'."
|
||||||
"DOOM Emacs bootstrap macro. List the modules to load. Benefits from
|
"DOOM Emacs bootstrap macro. List the modules to load. Benefits from
|
||||||
byte-compilation."
|
byte-compilation."
|
||||||
(doom-initialize-modules modules)
|
(doom-initialize-modules modules)
|
||||||
(unless (doom-module-loaded-p :private (intern user-login-name))
|
(when (and user-login-name
|
||||||
|
(not (doom-module-loaded-p :private (intern user-login-name))))
|
||||||
(doom--enable-module :private user-login-name))
|
(doom--enable-module :private user-login-name))
|
||||||
`(let (file-name-handler-alist)
|
`(let (file-name-handler-alist)
|
||||||
(setq doom-modules ',doom-modules)
|
(setq doom-modules ',doom-modules)
|
||||||
|
@ -367,7 +374,13 @@ it hasn't already, and if it exists."
|
||||||
(when (or reload-p (not loaded-p))
|
(when (or reload-p (not loaded-p))
|
||||||
(unless loaded-p
|
(unless loaded-p
|
||||||
(doom--enable-module module submodule t))
|
(doom--enable-module module submodule t))
|
||||||
`(load! config ,(doom-module-path module submodule) t)))))
|
`(condition-case-unless-debug ex
|
||||||
|
(load! config ,(doom-module-path module submodule) t)
|
||||||
|
('error
|
||||||
|
(lwarn 'doom-modules :error
|
||||||
|
"%s in '%s %s' -> %s"
|
||||||
|
(car ex) ,module ',submodule (error-message-string ex))))))))
|
||||||
|
|
||||||
|
|
||||||
(defmacro featurep! (module submodule)
|
(defmacro featurep! (module submodule)
|
||||||
"Convenience macro that wraps `doom-module-loaded-p'."
|
"Convenience macro that wraps `doom-module-loaded-p'."
|
||||||
|
@ -477,21 +490,32 @@ the commandline."
|
||||||
(when (file-exists-p doom-autoload-file)
|
(when (file-exists-p doom-autoload-file)
|
||||||
(delete-file doom-autoload-file)
|
(delete-file doom-autoload-file)
|
||||||
(message "Deleted old autoloads.el"))
|
(message "Deleted old autoloads.el"))
|
||||||
(dolist (file (nreverse targets))
|
(dolist (file (reverse targets))
|
||||||
(let ((inhibit-message (not doom-debug-mode)))
|
(message (if (update-file-autoloads file nil doom-autoload-file)
|
||||||
(update-file-autoloads file nil doom-autoload-file))
|
"Nothing in %s"
|
||||||
(message "Scanned %s" (file-relative-name file doom-emacs-dir)))
|
"Scanned %s")
|
||||||
(condition-case ex
|
(file-relative-name file doom-emacs-dir)))
|
||||||
(let ((buf (get-file-buffer doom-autoload-file)))
|
(let ((buf (get-file-buffer doom-autoload-file))
|
||||||
|
current-sexp)
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
|
(condition-case-unless-debug ex
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(save-buffer)
|
(save-buffer)
|
||||||
(eval-buffer)
|
(goto-char (point-min))
|
||||||
|
(while (re-search-forward "^(" nil t)
|
||||||
|
(save-excursion
|
||||||
|
(backward-char)
|
||||||
|
(setq current-sexp (read (thing-at-point 'sexp t)))
|
||||||
|
(eval current-sexp t))
|
||||||
|
(forward-char))
|
||||||
(message "Finished generating autoloads.el!"))
|
(message "Finished generating autoloads.el!"))
|
||||||
(kill-buffer buf)))
|
|
||||||
('error
|
('error
|
||||||
(delete-file doom-autoload-file)
|
(delete-file doom-autoload-file)
|
||||||
(error "Couldn't evaluate autoloads.el: %s" (cadr ex))))))
|
(error "Error in autoloads.el: (%s %s ...) %s -- %s"
|
||||||
|
(nth 0 current-sexp)
|
||||||
|
(nth 1 current-sexp)
|
||||||
|
(car ex) (error-message-string ex))))
|
||||||
|
(kill-buffer buf)))))
|
||||||
|
|
||||||
(defun doom/compile (&optional lite-p only-recompile-p)
|
(defun doom/compile (&optional lite-p only-recompile-p)
|
||||||
"Byte compile your emacs configuration (init.el, core/*.el &
|
"Byte compile your emacs configuration (init.el, core/*.el &
|
||||||
|
@ -511,14 +535,15 @@ If ONLY-RECOMPILE-P is non-nil, only recompile out-of-date files."
|
||||||
(cl-loop for file in command-line-args-left
|
(cl-loop for file in command-line-args-left
|
||||||
if (file-exists-p file)
|
if (file-exists-p file)
|
||||||
collect (expand-file-name file)
|
collect (expand-file-name file)
|
||||||
finally do (setq command-line-args-list nil)) )
|
finally do (setq command-line-args-left nil)) )
|
||||||
(t
|
(t
|
||||||
(append (list (expand-file-name "init.el" doom-emacs-dir)
|
(append (list (expand-file-name "init.el" doom-emacs-dir)
|
||||||
doom-core-dir)
|
doom-core-dir)
|
||||||
(unless lite-p (doom--module-paths))))))
|
(unless lite-p (doom--module-paths))))))
|
||||||
(total-success 0)
|
(total-success 0)
|
||||||
(total-fail 0)
|
(total-fail 0)
|
||||||
(total-nocomp 0))
|
(total-nocomp 0)
|
||||||
|
(use-package-expand-minimally t))
|
||||||
(let ((el-files (cl-loop for path in targets
|
(let ((el-files (cl-loop for path in targets
|
||||||
if (file-directory-p path)
|
if (file-directory-p path)
|
||||||
nconc (nreverse (directory-files-recursively path "\\.el$"))
|
nconc (nreverse (directory-files-recursively path "\\.el$"))
|
||||||
|
|
28
core/core.el
28
core/core.el
|
@ -133,6 +133,19 @@ melodramatic ex-vimmer disappointed with the text-editor status quo."
|
||||||
"A list of hooks run after DOOM initialization is complete, and after
|
"A list of hooks run after DOOM initialization is complete, and after
|
||||||
`doom-init-hook'.")
|
`doom-init-hook'.")
|
||||||
|
|
||||||
|
(defun doom-try-run-hook (fn hook)
|
||||||
|
"Runs a hook wrapped in a `condition-case-unless-debug' block; its objective
|
||||||
|
is to include more information in the error message, without sacrificing your
|
||||||
|
ability to invoke the debugger in debug mode."
|
||||||
|
(condition-case-unless-debug ex
|
||||||
|
(funcall fn)
|
||||||
|
('error
|
||||||
|
(display-warning
|
||||||
|
hook
|
||||||
|
(format "%s in '%s' -> %s" (car ex) fn (error-message-string ex))
|
||||||
|
:error)))
|
||||||
|
nil)
|
||||||
|
|
||||||
;; Automatic minor modes
|
;; Automatic minor modes
|
||||||
(defvar doom-auto-minor-mode-alist '()
|
(defvar doom-auto-minor-mode-alist '()
|
||||||
"Alist mapping filename patterns to corresponding minor mode functions, like
|
"Alist mapping filename patterns to corresponding minor mode functions, like
|
||||||
|
@ -179,9 +192,8 @@ enable multiple minor modes for the same regexp.")
|
||||||
|
|
||||||
(defun doom|finalize ()
|
(defun doom|finalize ()
|
||||||
(unless doom-init-p
|
(unless doom-init-p
|
||||||
(with-demoted-errors "INIT ERROR: %s"
|
(dolist (hook '(doom-init-hook doom-post-init-hook))
|
||||||
(run-hooks 'doom-init-hook)
|
(run-hook-wrapped hook #'doom-try-run-hook hook))
|
||||||
(run-hooks 'doom-post-init-hook))
|
|
||||||
|
|
||||||
;; Don't keep gc-cons-threshold too high. It helps to stave off the GC while
|
;; Don't keep gc-cons-threshold too high. It helps to stave off the GC while
|
||||||
;; Emacs starts up, but afterwards it causes stuttering and random freezes.
|
;; Emacs starts up, but afterwards it causes stuttering and random freezes.
|
||||||
|
@ -197,9 +209,13 @@ enable multiple minor modes for the same regexp.")
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;; Bootstrap
|
;; Bootstrap
|
||||||
(load! core-os) ; consistent behavior across Oses
|
(load! core-os) ; consistent behavior across OSes
|
||||||
(with-demoted-errors "AUTOLOAD ERROR: %s"
|
(condition-case-unless-debug ex
|
||||||
(require 'autoloads doom-autoload-file t))
|
(require 'autoloads doom-autoload-file t)
|
||||||
|
('error
|
||||||
|
(lwarn 'doom-autoloads :warning
|
||||||
|
"%s in autoloads.el -> %s"
|
||||||
|
(car ex) (error-message-string ex))))
|
||||||
|
|
||||||
(unless noninteractive
|
(unless noninteractive
|
||||||
(load! core-ui) ; draw me like one of your French editors
|
(load! core-ui) ; draw me like one of your French editors
|
||||||
|
|
|
@ -151,7 +151,7 @@ whose dimensions may not be fully initialized by the time this is run."
|
||||||
(s-center +doom-dashboard--width
|
(s-center +doom-dashboard--width
|
||||||
(format "Loaded %d packages in %.03fs "
|
(format "Loaded %d packages in %.03fs "
|
||||||
(- (length load-path) (length doom--base-load-path))
|
(- (length load-path) (length doom--base-load-path))
|
||||||
doom-init-time))
|
(if (floatp doom-init-time) doom-init-time 0.0)))
|
||||||
'face 'font-lock-comment-face)
|
'face 'font-lock-comment-face)
|
||||||
"\n"))
|
"\n"))
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue