Когда вам нужно изменить функцию, определённую в другой библиотеке, или когда вам нужно
изменить хук, например foo-function, фильтр процесса или, в общем,
любую переменную или поле объекта, которое хранит значение функции, вы можете использовать
соответствующую функцию установки, такую как fset или defun для именованных
функций, setq для переменных-хуков или set-process-filter для
фильтров процессов, но они часто слишком грубы, полностью отбрасывая предыдущее
значение.
Возможность советов позволяет вам добавлять что-то к существующему определению функции, давая совет функции. Это более чистый метод, чем полное переопределение всей функции.
Система советов 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, использованные в приведённых выше примерах,
указывают, как компонуются две функции, поскольку существует много различных
способов это сделать. Добавленная функция также называется советом.