Консультирование функций Emacs Lisp
Когда вам нужно изменить функцию, определенную в другой библиотеке, или когда вам нужно изменить хук, например foo-function, фильтр процесса или, по сути, любое переменное или поле объекта, которое содержит значение функции, вы можете использовать соответствующую функцию-сеттер, например, fset или defun для именованных функций, setq для переменных хуков или set-process-filter для фильтров процессов, но они часто слишком грубые, полностью удаляя предыдущее значение.
Функция advice позволяет добавить к существующему определению функции, консультируя функцию. Это более чистый метод, чем переопределение всей функции.
Система консультаций Emacs предоставляет два набора примитивов для этого: основной набор для значений функций, хранящихся в переменных и полях объектов (соответствующие примитивы add-function и remove-function) и другой набор, наложенный поверх него для именованных функций (основные примитивы advice-add и advice-remove).
В качестве тривиального примера, вот как добавить консультацию, которая будет изменять возвращаемое значение функции каждый раз, когда она вызывается:
(defun my-double (x) (* x 2)) (defun my-increase (x) (+ x 1)) (advice-add 'my-double :filter-return #'my-increase)
После добавления этой консультации, если вы вызовете my-double со значением ‘3’, возвращаемое значение будет ‘7’. Чтобы удалить эту консультацию, скажите
(advice-remove 'my-double #'my-increase)
Более сложный пример — отслеживание вызовов фильтра процесса процесса proc:
(defun my-tracing-function (proc string) (message "Proc %S received %S" proc string)) (add-function :before (process-filter proc) #'my-tracing-function)
Это заставит вывод процесса передаваться в my-tracing-function перед передачей в исходный фильтр процесса. my-tracing-function получает те же аргументы, что и исходная функция. Когда вы закончите, вы можете вернуться к поведению без отслеживания с помощью:
(remove-function (process-filter proc) #'my-tracing-function)
Аналогично, если вы хотите отследить выполнение функции под названием display-buffer, вы можете использовать:
(defun his-tracing-function (orig-fun &rest args)
(message "display-buffer called with args %S" args)
(let ((res (apply orig-fun args)))
(message "display-buffer returned %S" res)
res))
(advice-add 'display-buffer :around #'his-tracing-function)
Здесь his-tracing-function вызывается вместо исходной функции и получает исходную функцию (в дополнение к аргументам этой функции) в качестве аргумента, так что она может вызвать её, если и когда это необходимо. Когда вы устанете от этого вывода, вы можете вернуться к поведению без отслеживания с помощью:
(advice-remove 'display-buffer #'his-tracing-function)
Аргументы :before и :around в вышеприведенных примерах определяют, как составлены две функции, так как существует множество способов сделать это. Добавленная функция также называется фрагментом консультации.
| • Основные примитивы консультации | Примитивы для управления консультацией. | |
| • Консультирование именованных функций | Консультирование именованных функций. | |
| • Комбинаторы консультации | Способы составления консультаций. | |
| • Перевод старой консультации | Адаптация кода, использующего старую defadvice. |
Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html