This package provides the macros lazily-do
lazily-do-all
for use in Emacs
configuration files. With these you can wrap configuration steps in the macro
without having to worry (too much) about void-variable messages or void-function
errors. In the example below good-list
is declared, but Emacs doesn’t know
about bad-list
or bad-func
yet. This would throw a void-variable
error. Execution stops here and we don’t get to bad-func
, which would throw a
void-function error.
(defvar good-list nil)
(add-to-list 'good-list 1)
(add-to-list 'bad-list 1)
(bad-func))
We have a couple of options here. We could figure out which library defines
bad-list
and bad-func
. This is usually straightforward but not always. To
fix this we could (require 'bad-library)
or use with-eval-after-load
like
this
(with-eval-after-load 'bad-library
(add-to-list 'bad-list 1)
(bad-func))
The way lazily-do
and lazily-do-all
work is they store the forms in a list
along with the conditions that produced the error. When a new library is loaded,
lazily checks if the error condition has been resolved for any of the
problematic forms. If so, execution is tried again. It accomplishes this through
using the after-load-functions
hook. To illustrate suppose we modified the
example to this.
(defvar good-list nil)
(lazily-do
(add-to-list 'good-list 1)
(add-to-list 'bad-list 1)
(bad-func))
The form with good-list
will execute fine and there will be no difference to
having this form at the top level. The one with bad-list
throws a
void-variable error which is caught and execution stops. The form with
bad-list
in it as well as all of the forms following it are saved for later
along with some information about the error and the file it happened in. Every
time a new file is loaded in Emacs, lazily checks to see if the error is
resolved (i.e., bad-list
is now defined) and if it is it tries to execute the
forms again, automatically.
lazily-do-all
is greedier. In the example below, after the bad-list
form
throws an error lazily continues to try forms catching and storing errors along
the way. In this example, this means that good-func
gets executed right away,
instead of waiting for the problem to be resolved with bad-list
.
(defvar good-list nil)
(lazily-do-all
(add-to-list 'good-list 1)
(add-to-list 'bad-list 1)
(bad-func)
(good-func))
The guiding idea is that void variables or functions are void because they have not yet been loaded. This seems like a common configuration error, and to a certain degree lazily removes some concern about what should be loaded before what. It queues undefined variables and functions and checks to see if they are defined later.
Of course, if the variable is never defined, the form will never execute. It
can’t execute anyway, but lazily might prevent an error due to a typo for
example. That is the purpose of using the report function lazily-report
to
inspect any forms that never get executed.
A basic report of what lazily found can be generated with lazily-report
. This
can be used to debug any issues with lazily.
lazily-is-quiet
: Set this variable tonil
if you want to log bad forms when they are found.