Добавление advice к функциям Emacs Lisp
Когда вам нужно изменить функцию, определённую в другой библиотеке, или изменить хук, например foo-function, фильтр процесса или, в целом, любую переменную либо поле объекта, содержащее значение-функцию, можно использовать соответствующую функцию-сеттер, например fset или defun для именованных функций, setq для переменных-хуков или set-process-filter для фильтров процессов, но эти функции часто слишком грубы и полностью заменяют предыдущее значение.
Возможность advice позволяет дополнить существующее определение функции, добавив к ней advice. Это более аккуратный способ, чем переопределение всей функции.
Система advice в Emacs предоставляет для этого два набора примитивов: основной набор для значений-функций, хранящихся в переменных и полях объектов (соответствующие примитивы — add-function и remove-function), и другой набор, построенный поверх него, для именованных функций (основные примитивы — advice-add и advice-remove).
В качестве простого примера рассмотрим, как добавить advice, изменяющий возвращаемое функцией значение при каждом её вызове:
(defun my-double (x) (* x 2)) (defun my-increase (x) (+ x 1)) (advice-add 'my-double :filter-return #'my-increase)
После добавления этого advice вызов my-double с аргументом «3» вернёт значение «7». Чтобы удалить этот advice, выполните:
(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, использованные в примерах выше, задают способ композиции двух функций, поскольку существует множество способов это сделать. Добавленная функция также называется фрагментом advice.
Copyright © 1990-1996, 1998-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html