22.4 Различение интерактивных вызовов

Иногда команда должна отображать дополнительную визуальную обратную связь (например, информационное сообщение в области эхо) только для интерактивных вызовов. Существует три способа сделать это. Рекомендуемый способ проверки того, был ли вызов выполнен с использованием call-interactively, — это передать ему необязательный аргумент print-message и использовать спецификатор interactive, чтобы он не был nil в интерактивных вызовах. Вот пример:

(defun foo (&optional print-message)
  (interactive "p")
  (when print-message
    (message "foo")))

Мы используем "p", потому что аргумент числового префикса никогда не бывает nil. Определенная таким образом, функция отображает сообщение при вызове из макроса клавиатуры.

Вышеупомянутый метод с дополнительным аргументом обычно лучше, потому что он позволяет вызывающим функциям сказать: «обращаться с этим вызовом как с интерактивным». Но вы также можете выполнить эту задачу, проверяя called-interactively-p.

Функция: called-interactively-p kind

Эта функция возвращает t, если вызывающая функция была вызвана с использованием call-interactively.

Аргумент kind должен быть либо символом interactive, либо символом any. Если это interactive, то called-interactively-p возвращает t только в том случае, если вызов был сделан непосредственно пользователем — например, если пользователь ввел последовательность клавиш, привязанную к вызывающей функции, но не если пользователь запустил макрос клавиатуры, который вызвал функцию (см. Макросы клавиатуры). Если kind равен any, called-interactively-p возвращает t для любого типа интерактивного вызова, включая макросы клавиатуры.

Если сомневаетесь, используйте any; единственное известное правильное использование interactive — это если вам нужно решить, отображать ли полезное сообщение во время выполнения функции.

Функция никогда не считается вызванной интерактивно, если она была вызвана через вычисление Lisp (или с использованием apply или funcall).

Вот пример использования called-interactively-p:

(defun foo ()
  (interactive)
  (when (called-interactively-p 'any)
    (message "Interactive!")
    'foo-called-interactively))

;; Введите M-x foo.
     -| Interactive!

(foo)
     ⇒ nil

Вот еще один пример, который противопоставляет прямые и косвенные вызовы called-interactively-p.

(defun bar ()
  (interactive)
  (message "%s" (list (foo) (called-interactively-p 'any))))

;; Введите M-x bar.
     -| (nil t)