Tôi có thể tải lại thư viện và có các giá trị gán lại defvar không?


10

Tôi đang phát triển một thư viện và muốn tải lại nó sau khi chỉnh sửa mà không thoát khỏi Emacs (giả sử rằng nó đang bật load-path):

(load-library "myname")

Khi tôi làm điều này, Emacs không nhận các thay đổi đối với defvarcác biến liên kết.

Tôi không muốn gọi eval-defun( C-M-x) theo cách thủ công trên mỗi biểu mẫu cấp cao nhất. Có M-x eval-buffertôn trọng defvar/ defcustom?


1
Có lẽ (unload-feature 'myname)đầu tiên?
npostavs

Chỉ cần thử nó và không, trái với eval-defunnó không nhận được thay đổi trong defvar.
JeanPierre

1
@KaushalModi: Tôi không nghĩ đó là một bản sao. Câu hỏi này là về hành động trên tất cả các defvars trong một tệp hoặc bộ đệm, nếu tôi hiểu chính xác.
vẽ

1
Thông thường, người ta sẽ không bao giờ cần phải đánh giá chỉ các defvars. Ngoài ra, OP sử dụng load-filengụ ý rằng anh ta muốn đánh giá toàn bộ tập tin trong khi đảm bảo rằng các defvars được đánh giá lại.
Kaushal Modi

2
Cách tiếp cận của riêng tôi là eval-defun khi tôi thay đổi các giá trị. Nó không đủ để sử dụng cho tôi. YMMV.
YoungFrog

Câu trả lời:


3

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

Điều này sẽ hoạt động miễn là lần đầu tiên bạn tải các defvars bằng cách tải thư viện thông qua emacs, và không sử dụng eval-defun, eval-bufferv.v.

Khi bạn sử dụng require, load-libraryv.v. Emacs sẽ theo dõi các biến và chức năng nào là một phần của thư viện của bạn và sẽ loại bỏ chúng hoàn toàn cho bạn khi bạn sử dụng unload-feature.

Khi viết các gói, tôi thấy rằng sử dụng mã ở trên là một giải pháp tốt hơn so với chạy eval-defunkhi bạn viết mã mới để bạn không rơi vào trạng thái trung gian.


(info "(elisp) Loading"), (info "(elisp) Unloading")unload-featuređòi hỏi forcearg nếu thư viện là phụ thuộc cho thư viện khác. Câu trả lời chính xác! Tôi đang tự hỏi phiên bản Emacs nào bắt đầu cung cấp dỡ tải ...
gavenkoa

3

defvarkhông gán lại giá trị của biến theo cùng một cách như, nói setqhoặc setf. Khi một biến có giá trị, defvar sẽ không chạm vào nó.

Từ defvarchuỗi của:

(defvar SYMBOL &optional INITVALUE DOCSTRING)

Xác định SYMBOL là một biến và trả về SYMBOL.

...

Đối số tùy chọn INITVALUE được ước tính và được sử dụng để đặt SYMBOL, chỉ khi giá trị của SYMBOL bị vô hiệu. Nếu SYMBOL là bộ đệm cục bộ, giá trị mặc định của nó là giá trị được đặt; giá trị đệm-cục bộ không bị ảnh hưởng. Nếu INITVALUE bị thiếu, giá trị của SYMBOL không được đặt.

...

Vì bạn có thể chỉnh sửa defvarcác biến trong câu hỏi để cung cấp cho chúng các giá trị khi bạn tải thư viện lần đầu tiên, tải lại thư viện sẽ không thay đổi các giá trị.

Xem thêm nút thủ công elisp trên Xác định biến toàn cầu .

Thay vì dựa vào defvar, bạn luôn có thể gán lại các giá trị với setq. Thay vào đó, tùy chọn cồng kềnh, bạn có thể uninternký hiệu để các defvars sẽ không tìm thấy chúng khi tải lại:

(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
Trong bối cảnh này, tức là, khi phát triển một gói elisp, defvarlà điều chính xác để sử dụng. setqsẽ tùy chỉnh clobber được thiết lập bởi người dùng cá nhân. OP đang yêu cầu một cách để ghi đè các defvarbiến trong quá trình phát triển gói . Chuyển sang setqsẽ yêu cầu chuyển trở lại defvarkhi gói được phát hành.
Tyler

@Tyler, vâng, tôi đồng ý rằng defvarnó phù hợp để phát triển gói. Tôi chỉ chỉ ra rằng defvarkhông gán lại giá trị, trong khi setqđó.
Dân

2

Thử cái này xem sao:

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

Điều đó chỉ sử dụng cùng một mã eval-defunsử dụng trên a defvar. Nó đi qua bộ đệm (hoặc hạn chế của nó bằng cách thu hẹp), dừng lại ở mỗi bộ đệm defvarvà sử dụng eval-defunmã trên nó.


1

Sau khi tôi nghe nói rằng không có giải pháp thuận tiện cho việc đánh giá lại bộ đệm với việc gán lại defvarchức năng đơn giản, tôi đã thực hiện lại 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))))

Cấu trúc mã lấy cảm hứng từ eval-defun-2việc thực hiện. Nó tương tự như Làm thế nào để tôi buộc đánh giá lại một defvar? giải pháp.

Ban đầu tôi muốn hàm cấp cao đánh giá lại thư viện được cài đặt lại thông qua tập lệnh xây dựng để:

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

Giải pháp Drew hoạt động ngay cả trên lồng nhau defvarnhưng thật khó để hiểu mã hoàn toàn.

Tôi cũng nghĩ về uninterntất cả các ký hiệu dựa trên tiền tố ký hiệu / regex (như Dan đề xuất) nhưng tôi lười gõ tiền tố mỗi lần ... Xem Làm cách nào tôi có thể hủy liên kết tất cả các định nghĩa ký hiệu với một tiền tố nhất định?

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.