The other answers have pretty well covered the low-level error-handling facilities that will be useful in a case like this. Another approach that can help is modularity. For instance, I divide my initialization file into several different files (using provide
as appropriate), and I load them using this function instead of require
:
(defun my/require-softly (feature &optional filename)
"As `require', but instead of an error just print a message.
If there is an error, its message will be included in the message
printed.
Like `require', the return value will be FEATURE if the load was
successful (or unnecessary) and nil if not."
(condition-case err
(require feature filename)
(error (message "Error loading %s: \"%s\""
(if filename (format "%s (%s)" feature filename) feature)
(error-message-string err))
nil)))
An error while loading a file in this way will still print a message, but it won't prevent execution of anything outside of the file where the error actually occurred.
Of course, this function isn't really that different from wrapping a require
call in with-demoted-errors
(I wrote it before I knew about with-demoted-errors
), but the important point is that it you can essentially implement something like Dan's combination of with-demoted-errors
and unwind-protect
without wrapping (potentially very lengthy) blocks of code.