Bisakah saya memuat ulang pustaka dan menetapkan nilai defvar?

10

Saya mengembangkan perpustakaan dan ingin memuatnya kembali setelah diedit tanpa keluar dari Emacs (anggap sudah aktif load-path):

(load-library "myname")

Ketika saya melakukan ini, Emacs tidak mengambil perubahan ke defvarvariabel-terikat.

Saya tidak ingin memanggil eval-defun( C-M-x) secara manual di setiap formulir tingkat atas. Apakah M-x eval-bufferrasa hormat defvar/ defcustom?

gavenkoa
sumber
1
Mungkin (unload-feature 'myname)dulu?
npostavs
Hanya mencobanya dan tidak, bertentangan dengan eval-defunitu tidak menerima perubahan defvar.
JeanPierre
1
@ KaushalModi: Saya rasa ini bukan duplikat. Pertanyaan ini adalah tentang bertindak pada semua defvarfile atau buffer, jika saya mengerti dengan benar.
Drew
1
Biasanya seseorang tidak perlu eval hanya defvars. Juga penggunaan OP load-filemenyiratkan bahwa ia ingin mengevaluasi seluruh file sambil memastikan bahwa defvars dievaluasi kembali.
Kaushal Modi
2
Pendekatan saya sendiri adalah eval-defun ketika saya mengubah nilainya. Cukup jarang untuk bisa digunakan untukku. YMMV.
YoungFrog

Jawaban:

3

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

Ini akan berfungsi selama Anda pertama kali memuat defvars dengan memuat perpustakaan melalui emacs, dan tidak menggunakan eval-defun, eval-bufferdll.

Saat Anda menggunakan require, load-librarydll. Emacs akan melacak variabel dan fungsi mana yang merupakan bagian dari perpustakaan Anda, dan akan menghapusnya sepenuhnya untuk Anda saat Anda menggunakannya unload-feature.

Saat menulis paket, saya menemukan bahwa menggunakan kode di atas adalah solusi yang lebih baik daripada menjalankan eval-defunsaat Anda menulis kode baru sehingga Anda tidak masuk ke kondisi perantara.

Jordon Biondo
sumber
(info "(elisp) Loading"), (info "(elisp) Unloading")dan unload-featurememerlukan forcearg jika pustaka adalah ketergantungan untuk pustaka lain. Jawaban bagus! Saya bertanya-tanya versi Emacs apa yang mulai menyediakan bongkar ...
gavenkoa
3

defvartidak menetapkan ulang nilai variabel dengan cara yang sama seperti, katakan setqatau setf. Setelah variabel memiliki nilai, defvar tidak akan menyentuhnya.

Dari defvardokumentasi:

(defvar SYMBOL &optional INITVALUE DOCSTRING)

Tentukan SYMBOL sebagai variabel, dan kembalikan SYMBOL.

...

Argumen opsional INITVALUE dievaluasi, dan digunakan untuk mengatur SYMBOL, hanya jika nilai SYMBOL batal. Jika SYMBOL adalah buffer-local, nilai defaultnya adalah apa yang ditetapkan; nilai buffer-local tidak terpengaruh. Jika INITVALUE hilang, nilai SYMBOL tidak disetel.

...

Karena Anda mungkin defvarmengedit variabel yang bersangkutan untuk memberi mereka nilai saat pertama kali memuat pustaka, memuat ulang pustaka tidak akan mengubah nilai.

Lihat juga simpul manual elisp pada Mendefinisikan Variabel Global .

Alih-alih mengandalkan defvar, Anda selalu dapat menetapkan ulang nilai setq. Sebagai alternatif, opsi kikuk, Anda dapat uninternsimbol sehingga defvars tidak akan menemukannya saat memuat ulang:

(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
sumber
2
Dalam konteks ini, yaitu, ketika mengembangkan paket elisp, defvaradalah hal yang benar untuk digunakan. setqakan kustomisasi yang ditetapkan oleh pengguna individu. OP meminta cara untuk memaksa menimpa defvarvariabel selama pengembangan paket . Beralih ke setqakan membutuhkan beralih kembali ke defvarsaat paket dirilis.
Tyler
@ Tyler, ya, saya setuju itu defvarsesuai untuk pengembangan paket. Saya hanya menunjukkan bahwa defvartidak menetapkan ulang nilai, sementara setqdemikian.
Dan
2

Coba ini:

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

Itu hanya menggunakan kode yang sama yang eval-defundigunakan pada a defvar. Itu melintasi buffer (atau pembatasannya dengan mempersempit), berhenti di masing defvar- masing dan menggunakan eval-defunkode di atasnya.

Drew
sumber
1

Setelah saya mendengar bahwa tidak ada solusi yang mudah untuk mengevaluasi kembali buffer dengan menugaskan ulang defvar, saya membuat fungsi sederhana yang menyampaikan 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))))

Struktur kode terinspirasi oleh eval-defun-2implementasi. Ini mirip dengan Bagaimana saya memaksa evaluasi ulang defvar? larutan.

Awalnya saya ingin fungsi tingkat tinggi untuk mengevaluasi kembali perpustakaan yang diinstal ulang melalui skrip build jadi:

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

Solusi Drew bekerja bahkan pada nested defvartetapi sulit untuk sepenuhnya memahami kode.

Saya juga berpikir tentang uninternsemua simbol berdasarkan awalan simbol / regex (seperti yang disarankan Dan ) tapi saya malas mengetik awalan setiap kali ... Lihat Bagaimana saya bisa melepaskan ikatan semua definisi simbol dengan awalan tertentu?

gavenkoa
sumber