Kann ich eine Bibliothek neu laden und defvar Werte neu zuweisen lassen?

10

Ich entwickle eine Bibliothek und möchte sie nach der Bearbeitung neu laden, ohne Emacs zu beenden (vorausgesetzt, sie ist aktiviert load-path):

(load-library "myname")

Wenn ich das mache, nimmt Emacs keine Änderungen an defvargebundenen Variablen auf.

Ich möchte eval-defun( C-M-x) nicht manuell in jedem Formular der obersten Ebene aufrufen . Ist M-x eval-bufferRespekt defvar/ defcustom?

Gavenkoa
quelle
1
Vielleicht (unload-feature 'myname)zuerst?
Npostavs
Ich habe es einfach versucht und nein, im Gegensatz dazu nimmt eval-defunes keine Änderungen auf defvar.
JeanPierre
1
@ KaushalModi: Ich denke nicht, dass es ein Duplikat ist. Bei dieser Frage geht es darum, auf alle defvars in einer Datei oder einem Puffer zu reagieren, wenn ich das richtig verstehe.
Drew
1
Normalerweise müsste man niemals nur die Defvars bewerten. Auch die Verwendung des OP load-fileimpliziert, dass er die gesamte Datei auswerten und gleichzeitig sicherstellen möchte, dass die Defvars neu bewertet werden.
Kaushal Modi
2
Mein eigener Ansatz ist es, zu eval-defun, wenn ich die Werte ändere. Es ist selten genug, um für mich verwendbar zu sein. YMMV.
YoungFrog

Antworten:

3

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

Dies wird so lange arbeiten , wie Sie zuerst die defvars geladen , indem die Bibliothek durch Emacs geladen, und nicht mit eval-defun, eval-bufferusw.

Wenn Sie usw. verwenden require, verfolgt load-libraryEmacs, welche Variablen und Funktionen Teil Ihrer Bibliothek sind, und entfernt sie bei Verwendung vollständig für Sie unload-feature.

Beim Schreiben von Paketen finde ich, dass die Verwendung des obigen Codes eine bessere Lösung ist als das Ausführen, eval-defunwenn Sie neuen Code schreiben, damit Sie nicht in Zwischenzustände geraten.

Jordon Biondo
quelle
(info "(elisp) Loading"), (info "(elisp) Unloading")Und unload-featureerfordern forcearg , wenn Bibliothek Abhängigkeit für eine andere Bibliothek ist. Gute Antwort! Ich frage mich, welche Emacs-Version das Entladen ermöglicht ...
Gavenkoa
3

defvarweist den Wert einer Variablen nicht auf die gleiche Weise zu, wie z. B. setqoder setf. Sobald eine Variable einen Wert hat, defvar wird sie nicht mehr berührt.

Aus defvardem Dokument:

(defvar SYMBOL &optional INITVALUE DOCSTRING)

Definieren Sie SYMBOL als Variable und geben Sie SYMBOL zurück.

...

Das optionale Argument INITVALUE wird ausgewertet und zum Festlegen von SYMBOL nur verwendet, wenn der Wert von SYMBOL ungültig ist. Wenn SYMBOL pufferlokal ist, wird der Standardwert festgelegt. Pufferlokale Werte sind nicht betroffen. Wenn INITVALUE fehlt, wird der Wert von SYMBOL nicht festgelegt.

...

Da Sie defvardie fraglichen Variablen vermutlich so bearbeitet haben, dass sie beim ersten Laden der Bibliothek Werte erhalten, werden die Werte beim erneuten Laden der Bibliothek nicht geändert.

Siehe auch den elisp-Handbuchknoten zum Definieren globaler Variablen .

Anstatt sich darauf zu verlassen defvar, können Sie mit immer Werte neu zuweisen setq. Als alternative, klobige Option können Sie uninterndie Symbole so verwenden, dass die defvars sie beim erneuten Laden nicht finden:

(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
quelle
2
In diesem Zusammenhang, dh bei der Entwicklung eines Elisp-Pakets, defvarist die richtige Verwendung. setqwürde Anpassungen anpassen, die von einzelnen Benutzern festgelegt wurden. OP fragt nach einer Möglichkeit, das Überschreiben von defvarVariablen während der Paketentwicklung zu erzwingen . Das Umschalten auf setqwürde das Zurückschalten auf erfordern, defvarwenn das Paket freigegeben wird.
Tyler
@ Tyler, ja, ich stimme zu, dass dies defvarfür die Paketentwicklung geeignet ist. Ich weise nur darauf hin, dass defvarWerte nicht neu zugewiesen werden, während dies der setqFall ist.
Dan
2

Versuche dies:

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

Das verwendet nur den gleichen Code, eval-defunder auf einem verwendet wird defvar. Es durchläuft den Puffer (oder seine Einschränkung durch Verengung), stoppt bei jedem defvarund verwendet den darauf enthaltenen eval-defunCode.

Drew
quelle
1

Nachdem ich gehört habe, dass es keine bequeme Lösung für die Neubewertung des Puffers mit Neuzuweisung von gibt defvar, habe ich eine einfache Funktion erstellt, die Folgendes ermöglicht 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))))

Von der eval-defun-2Implementierung inspirierte Codestruktur. Es ist ähnlich wie Wie erzwinge ich eine Neubewertung einer Defvar? Lösung.

Ursprünglich möchte ich, dass die High-Level-Funktion die Bibliothek neu bewertet, die über das Build-Skript neu installiert wurde.

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

Die Drew- Lösung funktioniert auch bei verschachtelten Lösungen, defvaraber es ist schwierig, den Code vollständig zu verstehen.

Ich denke auch an uninternalle Symbole, die auf Symbolpräfix / Regex basieren (wie Dan vorgeschlagen hat), aber ich bin faul, jedes Mal ein Präfix einzugeben ... Siehe Wie kann ich alle Symboldefinitionen mit einem bestimmten Präfix aufheben?

Gavenkoa
quelle