我可以重新加载库并让defvar重新分配值吗?


10

我正在开发一个库,并且想在编辑后重新加载它而不退出Emacs(假设它在load-path):

(load-library "myname")

当我这样做时,Emacs不会对defvar-bound变量进行更改。

我不想在每个顶级表单上手动调用eval-defunC-M-x)。是否M-x eval-buffer尊重defvar/ defcustom


1
也许是(unload-feature 'myname)第一个?
npostavs

只是尝试过,不,相反,eval-defun它不会吸收中的更改defvar
JeanPierre

1
@KaushalModi:我不认为这是重复的。defvar如果我理解正确,那么这个问题是关于对文件或缓冲区中的所有s进行操作的。
提请

1
通常人们会永远需要EVAL 只是在defvars。另外,OP使用load-file意味着他想评估整个文件,同时确保重新评估defvar。
考沙尔·莫迪

2
我自己的方法是在更改值时进行eval-defun。它很少能对我有用。YMMV。
YoungFrog

Answers:


3

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

只要您首先通过emacs加载库(而不使用eval-defuneval-buffer等等)来加载defvars,这便会起作用。

当您使用requireload-library等Emacs会跟踪哪些变量和函数库的一部分,当你使用,将完全删除它们为你unload-feature

编写软件包时,我发现使用上面的代码比eval-defun编写新代码时运行更好,因此您不会陷入中间状态。


(info "(elisp) Loading")(info "(elisp) Unloading")unload-feature要求forceARG如果库是另一个库的依赖。好答案!我想知道Emacs的哪个版本开始提供卸载功能…
didnkoa

3

defvar不会以与say setq或相同的方式重新分配变量的值 setf。一旦变量具有值,defvar 就不要触摸它。

来自defvar的文档字符串:

(defvar SYMBOL &optional INITVALUE DOCSTRING)

将SYMBOL定义为变量,然后返回SYMBOL。

...

仅当SYMBOL的值为void时,才对可选参数INITVALUE进行评估,并用于设置SYMBOL 如果SYMBOL是本地缓冲区,则其默认值为设置的值。缓冲区局部值不受影响。如果缺少INITVALUE,则不会设置SYMBOL的值。

...

由于您大概是defvar在首次加载库时使用了有问题的变量来为它们提供值,因此重新加载库不会更改这些值。

另请参见关于定义全局变量的elisp手册节点 。

无需依赖defvar,您始终可以使用来重新分配值setq。作为另类的笨拙选项,您可以unintern使用符号,以便defvars在重新加载时找不到它们:

(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
在这种情况下,即开发elisp软件包时,defvar是正确的选择。setq将破坏单个用户设置的自定义设置。OP正在寻求一种在软件包开发过程中强制覆盖defvar变量的方法。切换到该版本将需要切换回发布软件包的时间。setqdefvar
泰勒

@Tyler,是的,我同意defvar适用于程序包开发。我只是指出,它defvar并不会重新分配值setq

2

尝试这个:

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

这只是使用相同的代码,eval-defun在使用defvar。它遍历缓冲区(或通过缩小来限制),在每个缓冲区处停止defvar并使用其eval-defun上的代码。


1

听说没有通过重新分配defvars 来重新评估缓冲区的便捷解决方案后,我制作了一个简单的函数,该函数基于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))))

代码结构受eval-defun-2实现启发。它类似于我如何强制重新评估defvar?解。

最初,我希望高级功能重新评估通过构建脚本重新安装的库,因此:

(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解决方案甚至适用于嵌套,defvar但很难完全理解代码。

我还考虑了unintern所有基于符号前缀/正则表达式的符号(如Dan所建议的那样),但是我懒于每次键入前缀...请参阅如何将所有符号定义与特定前缀解除绑定?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.