Làm thế nào để tôi sử dụng nadvice?


29

Cấu hình của tôi đầy lời khuyên, và tôi tiếp tục nghe về nadvice.elgói tối giản mới sáng bóng .

Tôi đã tìm kiếm các hướng dẫn và tôi đã đọc nguồn này , nhưng tôi sẽ công khai thừa nhận: Tôi vẫn không biết làm thế nào để thực sự sử dụng nó.

Bất cứ ai ở đây có thể chỉ cho tôi một hướng dẫn, hoặc cho tôi biết làm thế nào để bắt đầu chuyển lời khuyên kiểu cũ của tôi qua?


7
+1 cho câu hỏi. Nếu bạn đã tìm kiếm các hướng dẫn và không tìm thấy những gì bạn cần, vui lòng xem xét việc gửi báo cáo lỗi (doc) : M-x report-emacs-bug. Một số nhà phát triển đôi khi thích phát triển hơn tài liệu. ;-) Điều quan trọng là tài liệu của Emacs.
vẽ

2
Hướng dẫn thực sự có một phần về điều đó, xem (thông tin "(elisp) Chuyển lời khuyên cũ") . Nó không được liệt kê trong chỉ mục chi tiết cho dù lý do.
wasamasa


3
Một vài ví dụ sử dụng nadvicetừ cấu hình của tôi :: after , : filter-return , : around , : before-
Until

1
@wasamasa Tôi sợ phần đó không hoàn thành. Tôi có một vài lời khuyên (có thể chỉ là một, chúng ta sẽ thấy) phức tạp hơn. Tôi có nên đặt câu hỏi cho mỗi ở đây không?
PythonNut

Câu trả lời:


22

Tất cả thông tin bạn cần được bao gồm trong C-h f add-functionđó mô tả cơ chế cơ bản của advice-add.

Hệ thống tư vấn mới về cơ bản hoạt động như thay thế định nghĩa hiện tại của hàm bằng hàm được mô tả trong bảng C-h f add-function, tùy thuộc vào lựa chọn WHERE đối số của bạn, chỉ sạch hơn để theo dõi hành vi nào đã được xác định trong tệp nguồn nào.

Một ví dụ với :aroundtùy chọn

Trường hợp chung nhất là :aroundtùy chọn, vì vậy tôi đưa ra một ví dụ cho điều đó. (Có thể tốt hơn để sử dụng WHEREcác tham số chuyên dụng khi có thể, nhưng bạn có thể thay thế các tham số khác bằng một :aroundchức năng tương đương ).

Chỉ là một ví dụ, giả sử bạn muốn gỡ lỗi một số cách sử dụng find-file và muốn vào printdanh sách đối số của nó mỗi khi nó được gọi. Bạn có thể viết

(defun my-find-file-advice-print-arguments (old-function &rest arguments)
  "Print the argument list every time the advised function is called."
  (print arguments)
  (apply old-function arguments))

(advice-add #'find-file :around #'my-find-file-advice-print-arguments)

Với việc thực hiện mới này, mọi thứ mà lời khuyên cần được thông qua như là đối số. ad-get-argstrở nên không cần thiết, bởi vì các đối số được truyền cho hàm lời khuyên dưới dạng đối số hàm bình thường (đối với các WHEREđối số có ý nghĩa). ad-do-ittrở nên không cần thiết khi :aroundlời khuyên trở thành đối số của hàm và đối số, do đó (ad-do-it)được thay thế bằng biểu mẫu

(apply old-function arguments)

hoặc khi bạn đã đặt tên cho các đối số

(funcall old-function first-arg second-arg)

đó là sạch hơn vì không có hình thức ma thuật liên quan. Sửa đổi các đối số chỉ đơn giản xảy ra bằng cách chuyển các giá trị sửa đổi đến OLD-FUNCTION.

Các WHEREgiá trị khác

Chuỗi tài liệu add-functionchứa một bảng gồm tất cả các vị trí tư vấn (hoặc "tổ hợp") và những gì chúng tương đương và giải thích chức năng theo cách lambdahành xử tương đương với chức năng được tư vấn:

`:before'       (lambda (&rest r) (apply FUNCTION r) (apply OLDFUN r))
`:after'        (lambda (&rest r) (prog1 (apply OLDFUN r) (apply FUNCTION r)))
`:around'       (lambda (&rest r) (apply FUNCTION OLDFUN r))
`:override'     (lambda (&rest r) (apply FUNCTION r))
`:before-while' (lambda (&rest r) (and (apply FUNCTION r) (apply OLDFUN r)))
`:before-until' (lambda (&rest r) (or  (apply FUNCTION r) (apply OLDFUN r)))
`:after-while'  (lambda (&rest r) (and (apply OLDFUN r) (apply FUNCTION r)))
`:after-until'  (lambda (&rest r) (or  (apply OLDFUN r) (apply FUNCTION r)))
`:filter-args'  (lambda (&rest r) (apply OLDFUN (funcall FUNCTION r)))
`:filter-return'(lambda (&rest r) (funcall FUNCTION (apply OLDFUN r)))

(cited from `C-h f add-function')

trong đó FUNCTION là chức năng tư vấn và OLDFUN chức năng nơi lời khuyên được thêm vào. Đừng cố gắng hiểu tất cả chúng cùng một lúc, chỉ cần chọn một WHEREbiểu tượng nghe có vẻ phù hợp và cố gắng hiểu biểu tượng đó.

Hoặc chỉ sử dụng :around. Theo như tôi có thể nói lợi thế duy nhất của việc sử dụng WHEREs chuyên biệt :aroundcho mọi thứ là bạn có thêm một chút thông tin từ việc tra cứu C-h f ADVISED-FUNCTION trước khi đọc chuỗi tài liệu của lời khuyên. Trừ khi bạn có kế hoạch xuất bản mã chứa lời khuyên, nó có thể không quan trọng.

Chức năng tư vấn được đặt tên

Tôi khuyên bạn nên sử dụng các hàm được đặt tên như lời khuyên vì nó cung cấp nhiều lợi thế (một số trong số chúng cũng áp dụng cho việc sử dụng các hàm được đặt tên cho hook):

  • Nó hiện lên C-h f find-filenhư

    :around advice: `my-find-file-advice-print-arguments'
    

    liên kết đến định nghĩa của chức năng tư vấn, như thường lệ chứa một liên kết đến tệp nơi nó được xác định. Nếu lời khuyên đã được định nghĩa là một lambdabiểu mẫu trực tiếp trong advice-add biểu mẫu thì chuỗi doc sẽ được hiển thị nội tuyến (một mớ hỗn độn cho các tài liệu dài?) Và không có gì cho biết nó được định nghĩa ở đâu.

  • Bạn có thể xóa lời khuyên với

    (advice-remove #'find-file #'my-find-file-advice-print-arguments)
    
  • Bạn có thể cập nhật định nghĩa về lời khuyên mà không cần chạy lại advice-addhoặc mạo hiểm để giữ phiên bản cũ hoạt động (vì chạy advice-addvới thay đổi lambdasẽ được công nhận là lời khuyên mới, không phải là cập nhật cho phiên bản cũ).

Side nhận xét Các #'functionký hiệu về cơ bản là tương đương với 'function, ngoại trừ việc nó giúp trình biên dịch byte xác định những biểu tượng như tên hàm và do đó để xác định các chức năng còn thiếu (ví dụ như do lỗi chính tả).


Theo cuộc thảo luận tôi đã có với Stephen Monnier, không nên sử dụng dấu ngoặc kép ở đây trong tất cả các đối số .. nó nên (advice-add 'find-file :around #'my-find-file-advice-print-arguments)và tương tự (advice-remove 'find-file #'my-find-file-advice-print-arguments).
Kaushal Modi

Tôi đoán advice-addlà một trường hợp biên giới. Cá nhân tôi coi sự ' ↔ #'khác biệt này chủ yếu là giúp xác định lỗi chính tả trong tên hàm, vì vậy ở đây có lẽ sẽ phụ thuộc vào việc người ta có mong đợi chức năng được xác định theo thời gian lời khuyên được thêm vào hay không.
kdb

@kdb Cuối cùng tôi cũng tự mình tìm ra cái này (sau khi tôi chạy vào tài liệu cho add-function). Tôi muốn các tài liệu làm cho rõ ràng hơn. Tôi có thể tìm cách tạo ra một bản vá cho nó.
PythonNut

@kdb Ý bạn là "Nó xuất hiện C-h f find-filephải không C-x?
Peeja 28/03/2016

@Peeja Vâng, đã sửa nó.
kdb
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.