Is there any standard way in Common Lisp (+common libraries today) how to put default settings for not-yet-loaded libraries/systems (that are from public sources and cannot be reasonably modified) in the config file such as .sbclrc
?
For example, I want to have set
(setf quickproject:*template-directory* "~/projects/template/"
quickproject:*author* "my name <etcetc>")
when Quickproject is loaded. (Obviously, there is an additional complication with the relevant package not being defined at that point of time, but this I can handle.)
Something along the lines of emacs's (with)-eval-after-load
.
I am interested primarily in sbcl and quicklisp/asdf libraries, but implementation independent solution is preferred.
I tried to find in existing libraries and out of the box functionalities of SBCL require and of asdf, without success.
I considered and rejected abusing sbcl's extensions on trace.
The best I was able to do so far is define method for asdf:operate
, something like (for illustration, not really used)
(defvar *after-system-hooks* (make-hash-table :test 'equal))
(defmethod asdf:operate :after ((op asdf:load-op) (component asdf:system) &key)
(let* ((name (asdf:component-name component)))
(dolist (hook (gethash name *after-system-hooks*))
(funcall hook))
(setf (gethash name *after-system-hooks*) nil)))
(defun intern-uninterned (code package)
(typecase code
(cons (cons (intern-uninterned (car code) package)
(intern-uninterned (cdr code) package)))
(symbol (if (symbol-package code) code (intern (symbol-name code) package)))
(t code)))
(defmacro with-eval-after-load ((name package) &body body)
`(let ((fn (lambda () (eval (intern-uninterned '(progn ,@body) ',package)))))
(if (member ,name (asdf:already-loaded-systems) :test 'equal)
(funcall fn)
(push fn (gethash ,name *after-system-hooks*)))))
and then write something like
(with-eval-after-load ("quickproject" :quickproject)
(setf
#:*template-directory* "~/projects/template/"
#:*author* "My Name <etcetc>"))
However, this is overwriting method on standard component dispatched on standard classes, so it does not seem safe and future-proof. And I do not see how to define new classes to specialize in such a way that it would work with existing systems and tooling.
(And it has eval
, but it does not bother me much here)