10

I am developing a library and would like to reload it after editing without exiting Emacs (assume that it is on load-path):

(load-library "myname")

When I do this, Emacs doesn't pick up changes to defvar-bound variables.

I don't want to call eval-defun (C-M-x) manually on each top level form. Does M-x eval-buffer respect defvar/defcustom?

8
  • 1
    Maybe (unload-feature 'myname) first?
    – npostavs
    Aug 24, 2016 at 19:40
  • Just tried it and no, contrary to eval-defun it doesn't pick up changes in defvar.
    – JeanPierre
    Aug 24, 2016 at 20:15
  • 1
    @KaushalModi: I don't think it's a duplicate. This question is about acting on all the defvars in a file or buffer, if I understand correctly.
    – Drew
    Aug 24, 2016 at 21:11
  • 1
    Normally one would never need to eval just the defvars. Also the OP using load-file implies that he wants to evaluate the whole file while making sure that the defvars are reevaluated. Aug 24, 2016 at 21:34
  • 2
    My own approach is to eval-defun as I change the values. It's infrequent enough to be useable for me. YMMV.
    – YoungFrog
    Aug 25, 2016 at 7:45

4 Answers 4

4

(progn (unload-feature 'your-lib) (load-library "your-lib"))

This will work as long as you first loaded the defvars by loading the library through emacs, and not using eval-defun, eval-buffer etc.

When you use require, load-library etc. Emacs will keep track of which variables and functions are part of your library, and will remove them entirely for you when you use unload-feature.

When writing packages, I find that using the code above is a better solution than running eval-defun as you write new code so you don't get into intermediate states.

1
  • (info "(elisp) Loading"), (info "(elisp) Unloading") and unload-feature require force arg if library is dependency for another library. Great answer! I am wondering what Emacs version begin to provide unloading...
    – gavenkoa
    Aug 27, 2016 at 9:48
3

defvar does not reassign a variable's value in the same way as, say setq or setf. Once a variable has a value, defvar won't touch it.

From defvar's docstring:

(defvar SYMBOL &optional INITVALUE DOCSTRING)

Define SYMBOL as a variable, and return SYMBOL.

...

The optional argument INITVALUE is evaluated, and used to set SYMBOL, only if SYMBOL's value is void. If SYMBOL is buffer-local, its default value is what is set; buffer-local values are not affected. If INITVALUE is missing, SYMBOL's value is not set.

...

Since you presumably defvared the variables in question to give them values when you first loaded the library, re-loading the library won't change the values.

See also the elisp manual node on Defining Global Variables.

Instead of relying on defvar, you can always re-assign values with setq. As an alternative, clunky option, you can unintern the symbols so that the defvars will not find them upon reloading:

(defvar test-1 "test this")
(defvar test-2 "test this one, too")

test-1                                  ; => "test this"
test-2                                  ; => "test this one, too"

(defvar test-1 "trying to redefine")
(defvar test-2 "trying to redefine, too")

test-1                                  ; => "test this"
test-2                                  ; => "test this one, too"

(mapc #'unintern '(test-1 test-2))

test-1                                  ; => error!
test-2                                  ; => error!

(defvar test-1 "trying to redefine")
(defvar test-2 "trying to redefine, too")

test-1                                  ; => "trying to redefine"
test-2                                  ; => "trying to redefine, too"
2
  • 2
    In this context, i.e., when developing an elisp package, defvar is the correct thing to use. setq would clobber customizations set by individual users. OP is asking for a way to force overwriting of defvar variables during package development. Switching to setq would require switching back to defvar when the package is released.
    – Tyler
    Aug 24, 2016 at 21:21
  • @Tyler, yes, I agree that defvar is appropriate for package development. I'm only pointing out that defvar does not re-assign values, while setq does.
    – Dan
    Aug 24, 2016 at 21:23
2

Try this:

(defun foo ()
  "(Re-)evaluate all `defvar's in the buffer (or its restriction)."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (not (eobp))
      (when (re-search-forward "\\s-*(defvar \\([^ \t\n(\"]+\\)[ \t\n]+[^)]" nil 'MOVE)
        (let ((old-value (make-symbol "t"))
              new-value value)
          (let ((debug-on-error old-value))
            (setq value (eval-defun-2))
            (setq new-value debug-on-error))
          (unless (eq old-value new-value)
            (setq debug-on-error new-value))
          value)))))

That just uses the same code that eval-defun uses on a defvar. It traverses the buffer (or its restriction by narrowing), stopping at each defvar and using the eval-defun code on it.

1

After I heard that there is no convenient solution for re-evaluation of buffer with reassigning of defvar's I made simple function that relays on eval-defun:

(defun my/eval-buffer ()
  "Evaluate entire buffer with re-assigning values to `defvar' / `defcustom'.
Useful during package development."
  (interactive)
  (save-excursion
    (beginning-of-buffer)
    (while (not (eobp))
      (eval-defun nil)
      (end-of-defun))))

Code structure inspired by eval-defun-2 implementation. It is similar to How do I force re-evaluation of a defvar? solution.

Originally I want high level function to re-evaluate library that re-installed through build script so:

(defun my/load-library (library)
  "Evaluate entire library with re-assigning values to `defvar' / `defcustom'.
Useful during package development."
  (interactive
   (list (completing-read "Load library: "
                          (apply-partially 'locate-file-completion-table
                                           load-path
                                           '("" ".el")))))
  (with-temp-buffer
    (insert-file-contents (locate-file library load-path '("" ".el")))
    (my/eval-buffer)))

Drew solution works even on nested defvar but it is hard to completely understand code.

I also think about unintern all symbols based on symbol prefix/regex (as Dan suggested) but I am lazy to type prefix each time... See How can I unbind all symbol definitions with a certain prefix?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.