Bagaimana cara menggunakan nadvice?

29

Konfigurasi saya penuh dengan saran, dan saya terus mendengar tentang nadvice.elpaket minimalis mengkilap yang baru .

Saya telah mencari manual, dan saya sudah membaca sumbernya , tetapi saya akan mengakui secara terbuka: Saya masih tidak tahu bagaimana cara menggunakannya.

Adakah yang bisa mengarahkan saya ke panduan, atau memberi tahu saya cara memulangkan saran gaya lama saya?

PythonNut
sumber
7
+1 untuk pertanyaan. Jika Anda telah mencari manual dan tidak menemukan apa yang Anda butuhkan, silakan mempertimbangkan mengajukan (doc) laporan bug: M-x report-emacs-bug. Beberapa pengembang terkadang lebih suka mengembangkan daripada mendokumentasikan. ;-) Adalah penting bahwa dokumen Emacs itu sendiri.
Drew
2
Manual ini sebenarnya memiliki bagian tentang itu, lihat (info "(elisp) Meminta saran lama") . Itu tidak tercantum dalam indeks terperinci untuk alasan apa pun.
wasamasa
3
Beberapa contoh menggunakan nadvicedari konfigurasi saya: : setelah , : filter-return , : sekitar , : sebelum-sampai
Kaushal Modi
1
@wasamasa aku khawatir bagian itu masih jauh dari selesai. Saya punya beberapa saran (mungkin hanya satu, kita akan lihat) yang lebih kompleks. Haruskah saya mengajukan pertanyaan untuk masing-masing di sini?
PythonNut

Jawaban:

22

Semua informasi yang Anda butuhkan termasuk dalam C-h f add-functionyang menggambarkan mekanisme yang mendasari advice-add.

Sistem saran baru pada dasarnya bertindak seperti mengganti definisi fungsi saat ini dengan fungsi yang dijelaskan dalam tabel di C-h f add-function, tergantung pada pilihan WHERE argumen Anda, hanya pembersih demi melacak perilaku apa yang telah didefinisikan dalam file sumber apa.

Contoh dengan :aroundopsi

Kasus yang paling umum adalah :aroundopsi, jadi saya memberikan contoh untuk itu. (Mungkin lebih baik menggunakan WHEREparameter khusus bila memungkinkan, tetapi Anda dapat mengganti satu sama lain dengan :aroundfungsi yang setara ).

Sama seperti contoh, katakanlah Anda ingin men-debug beberapa penggunaan find-file dan ingin printdaftar argumennya setiap kali dipanggil. Anda bisa menulis

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

Dengan implementasi baru ini, semua saran yang diperlukan dilewatkan sebagai argumen. ad-get-argsmenjadi tidak perlu, karena argumen diteruskan ke fungsi saran sebagai argumen fungsi normal (untuk WHEREargumen yang masuk akal). ad-do-itmenjadi tidak perlu karena :aroundsaran mendapat sebagai fungsi argumen dan argumen, jadi (ad-do-it)digantikan oleh formulir

(apply old-function arguments)

atau ketika Anda telah menyebutkan argumen

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

yang lebih bersih karena tidak ada bentuk sihir yang terlibat. Mengubah argumen hanya terjadi dengan meneruskan nilai yang dimodifikasi ke OLD-FUNCTION.

WHERENilai lainnya

Dokumen add-functionberisi tabel semua tempat saran (atau "kombinator"), dan apa yang setara dengan mereka, dan menjelaskan fungsionalitas dalam hal lambdaberperilaku setara dengan fungsi yang disarankan:

`: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')

di mana FUNCTION adalah fungsi saran dan OLDFUN fungsi di mana saran ditambahkan. Jangan mencoba untuk memahami semuanya sekaligus, cukup pilih WHEREsimbol yang terdengar pas dan cobalah untuk memahaminya.

Atau gunakan saja :around. Sejauh yang saya tahu satu-satunya keuntungan menggunakan WHEREs khusus :arounduntuk semuanya adalah bahwa Anda mendapatkan sedikit informasi lebih banyak dari mencari C-h f ADVISED-FUNCTION sebelum membaca dokumentasi saran. Kecuali Anda berencana untuk menerbitkan kode yang berisi saran itu mungkin tidak masalah.

Bernama fungsi saran

Saya sarankan menggunakan fungsi bernama sebagai saran karena memberikan banyak keuntungan (beberapa dari mereka juga berlaku untuk menggunakan fungsi bernama untuk kait):

  • Itu muncul C-h f find-filesebagai

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

    menautkan ke definisi fungsi saran, yang seperti biasa berisi tautan ke file di mana ia didefinisikan. Jika saran telah didefinisikan sebagai lambdabentuk langsung dalam advice-add bentuk docstring akan ditampilkan inline (berantakan untuk dokumen panjang?) Dan tidak ada yang menunjukkan di mana itu didefinisikan.

  • Anda dapat menghapus saran dengan

    (advice-remove #'find-file #'my-find-file-advice-print-arguments)
    
  • Anda dapat memperbarui definisi saran tanpa menjalankan kembali advice-addatau mengambil risiko untuk mengaktifkan versi lama (karena menjalankan advice-adddengan yang diubah lambdaakan diakui sebagai saran baru, bukan sebagai pembaruan ke yang lama).

Side komentar The #'functionnotasi pada dasarnya setara dengan 'function, kecuali bahwa itu membantu compiler byte mengidentifikasi simbol sebagai nama fungsi dan dengan demikian untuk mengidentifikasi fungsi yang hilang (misalnya karena kesalahan ketik).

kdb
sumber
Sesuai diskusi saya dengan Stephen Monnier, tanda kutip tidak boleh digunakan di sini dalam semua argumen .. itu harus (advice-add 'find-file :around #'my-find-file-advice-print-arguments)dan sama (advice-remove 'find-file #'my-find-file-advice-print-arguments).
Kaushal Modi
Saya kira advice-addkasus perbatasan. Secara pribadi saya menganggap ' ↔ #'perbedaan sebagai sebagian besar bantuan untuk mengidentifikasi kesalahan ketik pada nama fungsi, jadi di sini mungkin akan tergantung pada apakah seseorang mengharapkan fungsi untuk didefinisikan pada saat saran ditambahkan.
kdb
@ KDB akhirnya saya menemukan ini untuk diri saya sendiri (setelah saya bertemu dengan dokumen untuk add-function). Saya berharap dokumen membuatnya lebih jelas. Saya mungkin ingin membuat tambalan untuk itu.
PythonNut
@ kdb Maksud Anda "Ini muncul C-h f find-file, bukan C-x?
Peeja
@ Peja Ya, koreksi itu.
kdb