22.2.5 Выбор среди альтернатив команд

Иногда полезно определить команду, которая служит «обобщённым диспетчером», способным вызывать одну из набора команд в соответствии с потребностями пользователя. Например, представьте, что вы хотите определить команду с именем ‘open’, которая может «открывать» и отображать несколько различных типов объектов. Или вы можете иметь команду с именем ‘mua’ (что означает «Mail User Agent» — почтовый клиент), которая может читать и отправлять электронную почту, используя один из нескольких почтовых бэкендов, таких как Rmail, Gnus или MH-E. Макрос define-alternatives можно использовать для определения таких обобщённых команд. Обобщённая команда — это интерактивная функция, реализация которой может быть выбрана из нескольких альтернатив в соответствии с предпочтениями пользователя.

Макрос: define-alternatives команда &rest настройки

Этот макрос определяет новую обобщённую команду, которая может иметь несколько альтернативных реализаций. Аргумент команда должен быть символом без кавычек.

При вызове макрос создаёт интерактивное замыкание на языке Lisp (см. Замыкания). Когда пользователь впервые запускает M-x команда RET, Emacs предлагает выбрать одну из альтернативных реализаций команды, предлагая дополнение для имён этих альтернатив. Эти имена берутся из пользовательской опции, имя которой имеет вид команда-alternatives; этот макрос создаёт такую опцию (если она не существовала ранее). Чтобы она была полезной, значение этой переменной должно быть ассоциативным списком, элементы которого имеют вид (имя-альт . функция-альт), где имя-альт — это имя альтернативы, а функция-альт — это интерактивная функция, которая будет вызвана при выборе данной альтернативы. Когда пользователь выбирает альтернативу, Emacs запоминает выбор и в дальнейшем автоматически вызывает выбранную альтернативу без запроса при повторном вызове M-x команда. Чтобы выбрать другую альтернативу, наберите C-u M-x команда RET — тогда Emacs снова запросит одну из альтернатив, и выбор заменит предыдущий.

Переменная команда-alternatives может быть создана до вызова define-alternatives с соответствующими значениями; в противном случае макрос создаёт переменную со значением nil, и затем её следует заполнить ассоциациями, описывающими альтернативы. Пакеты, которые хотят предоставить свою собственную реализацию существующей обобщённой команды, могут использовать куки autoload (см. Автозагрузка) для добавления в ассоциативный список, например:

;;;###autoload (push '("Моё имя" . my-foo-symbol) foo-alternatives

Если необязательный аргумент настройки отличен от nil, он должен состоять из чередующихся ключевых слов defcustom (обычно :group и :version) и значений, добавляемых к определению defcustom для команда-alternatives.

Вот пример простой обобщённой команды-диспетчера с именем open с тремя альтернативными реализациями:

(define-alternatives open
  :group 'files
  :version "42.1")
(setq open-alternatives
      '(("file" . find-file)
	("directory" . dired)
	("hexl" . hexl-find-file)))