Определение новых типов
В предыдущих разделах мы описали, как создавать сложные спецификации типов для defcustom. В некоторых случаях может потребоваться дать такой спецификации типа имя. Очевидный случай — когда один и тот же тип используется для многих пользовательских параметров: вместо того чтобы повторять спецификацию для каждого параметра, можно присвоить спецификации типа имя и использовать это имя каждый раз defcustom. Другой случай — когда значение пользовательского параметра представляет собой рекурсивную структуру данных. Чтобы тип данных мог ссылаться на самого себя, ему необходимо имя.
Поскольку пользовательские типы реализованы в виде виджетов, новый настраиваемый тип определяется созданием нового виджета. Здесь мы не будем подробно описывать интерфейс виджетов; см. Введение в Библиотеку виджетов Emacs. Вместо этого мы продемонстрируем на простом примере минимальную функциональность, необходимую для определения новых настраиваемых типов.
(define-widget 'binary-tree-of-string 'lazy
"A binary tree made of cons-cells and strings."
:offset 4
:tag "Node"
:type '(choice (string :tag "Leaf" :value "")
(cons :tag "Interior"
:value ("" . "")
binary-tree-of-string
binary-tree-of-string)))
(defcustom foo-bar ""
"Sample variable holding a binary tree of strings."
:type 'binary-tree-of-string)
Функция для определения нового виджета называется define-widget. Первый аргумент — это символ, который мы хотим использовать как новый тип виджета. Второй аргумент — символ, представляющий существующий виджет; новый виджет будет определён как отличающийся от существующего. Для определения новых типов настройки идеально подходит виджет lazy, поскольку он принимает аргумент-ключевое слово :type с тем же синтаксисом, что и аргумент-ключевое слово функции defcustom с таким же именем. Третий аргумент — строка документации для нового виджета. Эту строку можно посмотреть с помощью команды M-x widget-browse RET binary-tree-of-string RET.
После этих обязательных аргументов следуют аргументы-ключевые слова. Самый важный из них — :type, описывающий тип данных, которому должен соответствовать этот виджет. Здесь binary-tree-of-string описывается как строка либо cons-ячейка, car и cdr которой также являются binary-tree-of-string. Обратите внимание на ссылку на тип виджета, который мы сейчас определяем. Ещё один важный аргумент-ключевое слово — :tag, поскольку для нового виджета мы используем виджет lazy. По умолчанию у виджета lazy нет метки, и в её отсутствие буфер настройки показывает всё значение виджета (то есть значение настраиваемого пользовательского параметра). Поскольку это почти никогда не бывает хорошей идеей, мы задаём строку, которая будет обозначать виджет binary-tree-or-string. Аргумент :offset нужен, чтобы дочерние узлы располагались с отступом в четыре пробела относительно родительского узла, благодаря чему структура дерева становится очевидной в буфере настройки.
В defcustom показано, как новый виджет можно использовать в качестве обычного типа настройки.
Название lazy объясняется тем, что другие составные виджеты преобразуют подчинённые виджеты во внутреннее представление при создании экземпляра виджета в буфере. Это преобразование рекурсивно, поэтому подчинённые виджеты преобразуют свои подчинённые виджеты. Если сама структура данных рекурсивна, такое преобразование приводит к бесконечной рекурсии. Виджет lazy предотвращает рекурсию: он преобразует свой аргумент :type только при необходимости.
Copyright © 1990-1996, 1998-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Defining-New-Types.html