Макрос define-minor-mode предоставляет удобный способ
реализации режима в одном самодостаточном определении.
Этот макрос определяет новый второстепенный режим, имя которого — режим (символ). Он определяет команду с именем режим для переключения второстепенного режима, с doc в качестве строки документации.
Команда переключения принимает один необязательный (префиксный) аргумент.
При интерактивном вызове без аргумента она включает или выключает режим.
Положительный префиксный аргумент включает режим, любой другой префиксный аргумент
выключает его. Из Lisp аргумент toggle переключает режим,
а пропущенный аргумент или nil включает режим.
Это позволяет легко включать второстепенный режим в хуке основного режима, например.
Если doc равен nil, макрос предоставляет стандартную строку документации,
объясняющую вышеуказанное.
По умолчанию он также определяет переменную с именем режим, которая устанавливается
в t или nil при включении или выключении режима.
Ключ-арг состоят из ключевых слов, за которыми следуют соответствующие значения. Некоторые ключевые слова имеют особое значение:
:global globalЕсли не nil, указывает, что второстепенный режим должен быть глобальным,
а не буферно-локальным. По умолчанию — nil.
Одним из следствий создания глобального второстепенного режима является то,
что переменная режим становится настраиваемой переменной.
Её переключение через интерфейс Customize включает и выключает режим, а её
значение может быть сохранено для будущих сеансов Emacs (см. Сохранение
настроек в Руководстве GNU Emacs. Чтобы сохранённая
переменная работала, следует убедиться, что функция второстепенного режима
доступна при каждом запуске Emacs; обычно это делается путём
пометки формы define-minor-mode как автозагружаемой.
:init-value init-valueЭто значение, в которое инициализируется переменная режим.
За исключением необычных обстоятельств (см. ниже), это значение должно быть
nil.
:lighter lighterСтрока lighter указывает, что отображать в строке режима,
когда режим включён; если она равна nil, режим не отображается
в строке режима.
:keymap keymapНеобязательный аргумент keymap задаёт клавиатурную карту для второстепенного
режима. Если не nil, это должно быть имя переменной (значение которой —
клавиатурная карта), клавиатурная карта или список alist вида
(последовательность-клавиш . определение)
где каждая последовательность-клавиш и определение являются аргументами,
подходящими для передачи в define-key (см. Изменение привязок клавиш). Если keymap — это клавиатурная карта или alist, то это также
определяет переменную режим-map.
:variable placeЗаменяет переменную по умолчанию режим, используемую для хранения состояния
режима. Если вы указываете это, переменная режим не определяется,
и любой аргумент init-value не используется. place
может быть другой именованной переменной (которую вы должны определить сами) или
чем-либо, что можно использовать с функцией setf
(см. Обобщённые переменные).
place также может быть cons (get . set),
где get — выражение, возвращающее текущее состояние,
а set — функция одного аргумента (состояния), которая должна
присваиваться place.
:after-hook after-hookОпределяет одну форму Lisp, которая вычисляется после выполнения хуков режима. Она не должна заключаться в кавычки.
:interactive valueВторостепенные режимы по умолчанию являются интерактивными командами. Если value равен
nil, это отключается. Если value — список символов,
он используется для указания, для каких основных режимов этот второстепенный режим полезен.
Любые другие ключевые аргументы передаются непосредственно в
defcustom, создаваемый для переменной режим.
См. Определение настраиваемых переменных для описания этих ключевых слов и
их значений.
Команда с именем режим сначала выполняет стандартные действия, такие как
установка переменной с именем режим, а затем выполняет формы тела,
если они есть. Затем она запускает переменную хука режима
режим-hook и завершает вычислением любой формы в
:after-hook. (Обратите внимание, что всё это, включая запуск хука,
выполняется как при включении, так и при выключении режима.)
Начальное значение должно быть nil, за исключением случаев, когда (1)
режим предварительно загружен в Emacs или (2) включение режима без запроса
пользователя не вызывает проблем. Например,
если режим не оказывает влияния, пока что-то ещё не включено,
и будет обязательно загружен к этому моменту, включение его по умолчанию
безвредно. Но это необычные обстоятельства. Обычно
начальное значение должно быть nil.
Вот пример использования define-minor-mode:
(define-minor-mode hungry-mode "Переключение режима Hungry. При интерактивном вызове без аргумента эта команда переключает режим. Положительный префиксный аргумент включает режим, любой другой префиксный аргумент выключает его. Из Lisp пропущенный аргумент или nil включает режим, `toggle' переключает состояние. Когда режим Hungry включён, управляющая клавиша delete поглощает все предшествующие пробельные символы, кроме последнего. См. команду \\[hungry-electric-delete]." ;; Начальное значение. nil ;; Индикатор в строке режима. " Hungry" ;; Привязки второстепенного режима. '(([C-backspace] . hungry-electric-delete)))
Это определяет второстепенный режим с именем «Режим Hungry», команду с именем
hungry-mode для его переключения, переменную с именем hungry-mode,
которая указывает, включён ли режим, и переменную с именем
hungry-mode-map, которая содержит клавиатурную карту, активную, когда
режим включён. Он инициализирует клавиатурную карту привязкой клавиши
C-DEL. Формы тела отсутствуют — многим второстепенным режимам
они не нужны.
Вот эквивалентный способ записи:
(define-minor-mode hungry-mode
"Переключение режима Hungry.
...остальная документация как раньше..."
;; Начальное значение.
:init-value nil
;; Индикатор в строке режима.
:lighter " Hungry"
;; Привязки второстепенного режима.
:keymap
'(([C-backspace] . hungry-electric-delete)
([C-M-backspace]
. (lambda ()
(interactive)
(hungry-electric-delete t)))))
Это определяет глобальное переключение с именем глобальный-режим, смысл которого состоит во включении или выключении буферно-локального второстепенного режима режим во всех (или некоторых; см. ниже) буферах. Он также выполняет формы тела. Чтобы включить второстепенный режим в буфере, он использует функцию turn-on; чтобы выключить второстепенный режим, он вызывает режим с аргументом −1. (Функция turn-on является отдельной функцией, чтобы она могла определить, включать ли второстепенный режим или нет, когда заранее не очевидно, что его всегда следует включать.)
Глобальное включение режима влияет только на те буферы, которые впоследствии
создаются и используют основной режим, следующий соглашению о вызове
run-mode-hooks. Второстепенный режим не будет включён в тех основных
режимах, которые не следуют этому соглашению.
Этот макрос определяет опцию настройки глобальный-режим
(см. Настройки), которую можно переключать через интерфейс Customize
для включения и выключения второстепенного режима. Как и в случае с
define-minor-mode, следует убедиться, что форма
define-globalized-minor-mode вычисляется при каждом запуске Emacs,
например, с помощью ключевого слова :require.
Используйте :group group в ключ-арг, чтобы указать
группу настройки для переменной режима глобального второстепенного режима.
По умолчанию буферно-локальная переменная второстепенного режима, указывающая,
включён ли режим, совпадает с именем самого режима.
Используйте :variable variable, если это не так — некоторые
второстепенные режимы используют другую переменную для хранения этой информации о состоянии.
Вообще говоря, когда вы определяете глобализованный второстепенный режим, вам следует также определить неглобализованную версию, чтобы люди могли использовать его (или отключать) в отдельных буферах. Это также позволяет им отключать глобально включённый второстепенный режим в конкретном основном режиме, используя хук этого режима.
Если макросу задано ключевое слово :predicate, он создаст
пользовательскую опцию с тем же именем, что и переменная глобального режима, но
с -modes вместо -mode в конце, т.е.
глобальный-режимs. Эта переменная будет использоваться в функции-предикате,
которая определяет, следует ли активировать второстепенный режим в
конкретном основном режиме, и пользователи могут настраивать значение
переменной для управления режимами, в которых второстепенный режим будет включён.
Допустимые значения :predicate (и, следовательно, допустимые значения
создаваемой им пользовательской опции) включают t (использовать во всех основных режимах),
nil (не использовать ни в каких основных режимах) или список имён режимов,
при необходимости предварённый not (как в (not имя-режима …)). Эти элементы можно смешивать, как показано в
следующих примерах.
(c-mode (not mail-mode message-mode) text-mode)
Это означает «использовать в режимах, производных от c-mode, и не
в режимах, производных от message-mode или mail-mode, но использовать
в режимах, производных от text-mode, и никаких других
режимах».
((not c-mode) t)
Это означает «не использовать в режимах, производных от c-mode, но использовать
везде остальное».
(text-mode)
Это означает «использовать в режимах, производных от text-mode, но больше
нигде». (В конце неявно подразумевается nil.)
Второстепенные режимы часто устанавливают буферно-локальные переменные, которые влияют на некоторые
возможности Emacs. Когда второстепенный режим выключается, ожидается, что режим
восстановит предыдущее состояние этих переменных. Этот удобный макрос
помогает в этом: он работает во многом как setq-local, но
возвращает объект, который можно использовать для восстановления этих значений к
их предыдущим значениям/состояниям (с помощью сопутствующей функции
buffer-local-restore-state).