Czy mogę ponownie załadować bibliotekę i ponownie przypisać wartości defvar?

10

Tworzę bibliotekę i chciałbym ją ponownie załadować po edycji bez wychodzenia z Emacsa (zakładam, że jest włączona load-path):

(load-library "myname")

Kiedy to robię, Emacs nie odbiera zmian w defvarzmiennych związanych z.

Nie chcę ręcznie wywoływać eval-defun( C-M-x) w każdym formularzu najwyższego poziomu. Czy M-x eval-bufferszacunek defvar/ defcustom?

gavenkoa
źródło
1
Może (unload-feature 'myname)pierwszy?
npostavs
Po prostu spróbowałem i nie, w przeciwieństwie do eval-defuntego, nie odbiera zmian w defvar.
JeanPierre
1
@KaushalModi: Nie sądzę, że to duplikat. To pytanie dotyczy działania wszystkich defvarplików w buforze, jeśli dobrze rozumiem.
Drew
1
Zwykle nigdy nie trzeba ewaluować tylko defvarów. Również użycie PO load-fileoznacza, że ​​chce ocenić cały plik, upewniając się, że defvary są ponownie ocenione.
Kaushal Modi
2
Moje własne podejście polega na ewaluacji, gdy zmieniam wartości. To jest dość rzadkie, aby było dla mnie przydatne. YMMV.
YoungFrog,

Odpowiedzi:

3

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

To będzie działać tak długo, jak pierwszy załadowane defvars poprzez załadowanie biblioteki przez emacs, a nie za pomocą eval-defun, eval-bufferitd.

Podczas korzystania require, load-libraryitp Emacs śledzić zmienne i funkcje, które są częścią biblioteki i będzie je usunąć całkowicie dla Ciebie podczas korzystania unload-feature.

Pisząc pakiety, uważam, że użycie powyższego kodu jest lepszym rozwiązaniem niż uruchamianie, eval-defungdy piszesz nowy kod, aby nie dostać się do stanów pośrednich.

Jordon Biondo
źródło
(info "(elisp) Loading"), (info "(elisp) Unloading")I unload-featurewymagają forcearg jeśli biblioteka jest zależność dla innej biblioteki. Świetna odpowiedź! Zastanawiam się, która wersja Emacsa zaczyna zapewniać rozładunek ...
gavenkoa
3

defvarnie przypisuje ponownie wartości zmiennej w taki sam sposób jak powiedz setqlub setf. Gdy zmienna ma wartość, defvar nie będzie jej dotykać.

Z dokumentu defvar:

(defvar SYMBOL &optional INITVALUE DOCSTRING)

Zdefiniuj SYMBOL jako zmienną i zwróć SYMBOL.

...

Opcjonalny argument INITVALUE jest analizowany i używany do ustawienia SYMBOL, tylko jeśli wartość SYMBOL jest nieważna. Jeśli SYMBOL jest lokalnie buforowany, jego domyślną wartością jest to, co jest ustawione; nie ma to wpływu na lokalne wartości buforów. Jeśli brakuje INITVALUE, wartość SYMBOL nie jest ustawiona.

...

Ponieważ przypuszczalnie defvaredytowałeś dane zmienne, aby nadać im wartości podczas pierwszego ładowania biblioteki, ponowne załadowanie biblioteki nie zmieni wartości.

Zobacz także ręczny węzeł elisp na temat Definiowania zmiennych globalnych .

Zamiast polegać defvar, zawsze możesz ponownie przypisać wartości za pomocą setq. Alternatywną, niezgrabną opcją są uninternsymbole, dzięki którym defvars nie znajdą ich po przeładowaniu:

(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
źródło
2
W tym kontekście, tj. Przy opracowywaniu pakietu elisp, defvarnależy używać właściwego rozwiązania. setqspowoduje zablokowanie dostosowań ustawionych przez poszczególnych użytkowników. OP prosi o sposób wymuszenia zastąpienia defvarzmiennych podczas tworzenia pakietu . Zmiana na setqwymagałaby przełączenia z powrotem do defvarmomentu wydania pakietu.
Tyler
@Tyler, tak, zgadzam się, że defvarjest to odpowiednie do rozwoju pakietu. Podkreślam tylko, że defvarnie przypisuje się wartości, a setqrobi to.
Dan
2

Spróbuj tego:

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

To po prostu używa tego samego kodu, który eval-defunużywa na defvar. Przechodzi przez bufor (lub jego ograniczenia przez zawężenie), zatrzymując się na każdym z nich defvari używając na nim eval-defunkodu.

Rysował
źródło
1

Po usłyszeniu, że nie ma wygodnego rozwiązania do ponownej oceny bufora z ponownym przypisaniem defvar, utworzyłem prostą funkcję, która przekazuje 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))))

Struktura kodu inspirowana eval-defun-2implementacją. Jest podobny do Jak wymusić ponowną ocenę defvar? rozwiązanie.

Początkowo chcę, aby funkcja wysokiego poziomu ponownie oceniła bibliotekę, która została ponownie zainstalowana za pomocą skryptu kompilacji, tak aby:

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

Rozwiązanie Drew działa nawet na zagnieżdżonych, defvarale trudno jest w pełni zrozumieć kod.

Myślę też o uninternwszystkich symbolach opartych na prefiksie / regexie symbolu (jak zasugerował Dan ), ale jestem leniwy, aby za każdym razem wpisywać prefiks ... Zobacz Jak mogę rozwiązać wszystkie definicje symboli za pomocą określonego prefiksu?

gavenkoa
źródło