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?

gavenkoa
  • 3,352
  • 19
  • 36
  • 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
  • Possible duplicate of [How do I force re-evaluation of a defvar?](http://emacs.stackexchange.com/questions/2298/how-do-i-force-re-evaluation-of-a-defvar) – Kaushal Modi Aug 24 '16 at 21:09
  • 1
    @KaushalModi: I don't think it's a duplicate. This question is about acting on all the `defvar`s in a file or buffer, if I understand correctly. – Drew Aug 24 '16 at 21:11
  • @Drew Check out this solution under that question: http://emacs.stackexchange.com/a/2302/115 – Kaushal Modi Aug 24 '16 at 21:13
  • @KaushalModi: I see. But (1) the question there is different, even if that particular answer mostly answers this question, and (2) that answer reevaluates more than just `defvar`s. Maybe you would like to create a community question that combines the two? – Drew Aug 24 '16 at 21:24
  • 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 07:45

4 Answers4

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.

Jordon Biondo
  • 12,332
  • 2
  • 41
  • 62
  • `(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 09: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"
Dan
  • 32,584
  • 6
  • 98
  • 168
  • 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.

Drew
  • 75,699
  • 9
  • 109
  • 225
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?

gavenkoa
  • 3,352
  • 19
  • 36