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?

  • 1
    Maybe (unload-feature 'myname) first? – npostavs Aug 24 '16 at 19:40
  • Just tried it and no, contrary to eval-defun it doesn't pick up changes in defvar. – JeanPierre Aug 24 '16 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 '16 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. – Kaushal Modi Aug 24 '16 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 '16 at 7:45
3

(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.

| improve this answer | |
  • (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 '16 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"
| improve this answer | |
  • 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 '16 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 '16 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.

| improve this answer | |
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?

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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