24.2.4 Определение производных режимов

Рекомендуемый способ определения нового основного режима — создать его как производный от существующего с помощью define-derived-mode. Если нет тесно связанного режима, следует наследовать от text-mode, special-mode или prog-mode. См. Базовые основные режимы. Если ни один из них не подходит, можно наследовать от fundamental-mode (см. Основные режимы).

Макрос: define-derived-mode variant parent name docstring keyword-args… body…

Этот макрос определяет variant как команду основного режима, используя name в качестве строковой формы имени режима. variant и parent должны быть символами без кавычек.

Новая команда variant определяется так, чтобы вызывать функцию parent, а затем переопределять некоторые аспекты этого родительского режима:

  • Новый режим имеет собственную разреженную карту клавиш, названную variant-map. define-derived-mode делает карту клавиш родительского режима родительской для новой карты, если только variant-map уже не задана и уже не имеет родителя.
  • Новый режим имеет собственную синтаксическую таблицу, хранящуюся в переменной variant-syntax-table, если только вы не переопределите это с помощью ключевого слова :syntax-table (см. ниже). define-derived-mode делает синтаксическую таблицу родительского режима родительской для variant-syntax-table, если последняя уже не задана и уже не имеет родителя, отличного от стандартной синтаксической таблицы.
  • Новый режим имеет собственную таблицу аббревиатур, хранящуюся в переменной variant-abbrev-table, если только вы не переопределите это с помощью ключевого слова :abbrev-table (см. ниже).
  • Новый режим имеет собственный хук режима, variant-hook. Он выполняет этот хук после выполнения хуков своих родительских режимов с помощью run-mode-hooks как последнее действие, кроме выполнения формы :after-hook, если она имеется. См. Хуки режимов.

Кроме того, вы можете указать, как переопределять другие аспекты parent с помощью body. Команда variant вычисляет формы в body после настройки всех своих обычных переопределений, непосредственно перед выполнением хуков режима.

Если parent имеет ненулевое свойство символа mode-class, то define-derived-mode устанавливает свойство mode-class для variant в то же значение. Это гарантирует, например, что если parent является специальным режимом, то variant также будет специальным режимом (см. Соглашения об основных режимах).

Вы также можете указать nil для parent. Это даёт новому режиму отсутствие родителя. Тогда define-derived-mode ведёт себя как описано выше, но, конечно, опускает все действия, связанные с parent. И наоборот, вы можете использовать derived-mode-set-parent и derived-mode-add-parents, описанные ниже, чтобы явно задать родословную нового режима.

Аргумент docstring задаёт строку документации для нового режима. define-derived-mode добавляет некоторую общую информацию о хуке режима, а затем о карте клавиш режима, в конец этой строки документации. Если вы опустите docstring, define-derived-mode сгенерирует строку документации.

keyword-args — это пары ключевых слов и значений. Значения, кроме значения :after-hook, вычисляются. В настоящее время поддерживаются следующие ключевые слова:

:syntax-table

Вы можете использовать это, чтобы явно указать синтаксическую таблицу для нового режима. Если вы укажете значение nil, новый режим использует ту же синтаксическую таблицу, что и parent, или стандартную синтаксическую таблицу, если parent равен nil. (Обратите внимание, что это не следует соглашению, используемому для неключевых аргументов, согласно которому значение nil эквивалентно отсутствию указания аргумента.)

:abbrev-table

Вы можете использовать это, чтобы явно указать таблицу аббревиатур для нового режима. Если вы укажете значение nil, новый режим использует ту же таблицу аббревиатур, что и parent, или fundamental-mode-abbrev-table, если parent равен nil. (Опять же, значение nil не эквивалентно отсутствию указания этого ключевого слова.)

:interactive

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

:group

Если это указано, значением должна быть группа настройки для этого режима. (Не все основные режимы имеют её.) Команда customize-mode использует это. define-derived-mode не определяет указанную группу настройки автоматически.

:after-hook

Это необязательное ключевое слово указывает одну форму Lisp, которая вычисляется как последнее действие функции режима, после выполнения хуков режима. Её не следует заключать в кавычки. Поскольку форма может вычисляться после завершения функции режима, она не должна обращаться к каким-либо элементам локального состояния функции режима. Форма :after-hook полезна для настройки аспектов режима, которые зависят от настроек пользователя, которые, в свою очередь, могли быть изменены в хуке режима.

Вот гипотетический пример:

(defvar-keymap hypertext-mode-map
  "<down-mouse-3>" #'do-hyper-link)

(define-derived-mode hypertext-mode
  text-mode "Hypertext"
  "Основной режим для гипертекста."
  (setq-local case-fold-search nil))

Не пишите спецификацию interactive в определении; define-derived-mode делает это автоматически.

Функция: derived-mode-p modes

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

Кроме того, мы всё ещё поддерживаем устаревшее соглашение вызова, при котором аргументы modes передавались как отдельные аргументы.

При проверке родительских режимов текущего основного режима эта функция учитывает родителей текущего режима, заданных с помощью define-derived-mode, а также его дополнительные родители, заданные с помощью derived-mode-add-parents, описанного ниже.

Функция: provided-mode-derived-p mode modes

Эта функция возвращает ненулевое значение, если mode является производным от любого из основных режимов, заданных списком символов в modes. Как и в derived-mode-p, modes также может быть одним символом, и эта функция также поддерживает устаревшее соглашение вызова, при котором аргументы modes передавались как отдельные символьные аргументы.

При проверке родительских режимов mode эта функция учитывает родителей mode, заданных с помощью define-derived-mode, а также его дополнительные родители, заданные с помощью derived-mode-add-parents, описанного ниже.

Граф родословной основного режима можно просматривать и изменять с помощью следующих низкоуровневых функций:

Функция: derived-mode-set-parent mode parent

Эта функция объявляет, что mode наследует от parent. Это функция, которую define-derived-mode вызывает после определения mode, чтобы зарегистрировать тот факт, что mode был определён путём повторного использования parent.

Функция: derived-mode-add-parents mode extra-parents

Эта функция позволяет зарегистрировать дополнительных родителей в дополнение к тому, который использовался при определении mode. Это может быть использовано, когда сходство между mode и режимами из extra-parents таково, что имеет смысл рассматривать mode как дочерний по отношению к этим режимам для таких целей, как применение переменных каталога и других специфических для режима настроек. Дополнительные родительские режимы задаются в виде списка символов в extra-parents. Эти дополнительные родительские режимы будут считаться одними из родителей mode функциями derived-mode-p и provided-mode-derived-p.

Функция: derived-mode-all-parents mode

Эта функция возвращает список всех режимов в родословной mode, упорядоченный от наиболее специфичного к наименее специфичному, начиная с самого mode. Это включает дополнительные родительские режимы, если они есть, добавленные вызовом derived-mode-add-parents.