Spec-Zone.ru › Elisp

Добавление 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.

  • Примитивы для работы с advice
  • Добавление advice к именованным функциям
  • Способы композиции advice
  • Адаптация кода, использующего старый defadvice
  • 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API