In the previous sections we have described how to construct elaborate
type specifications for defcustom
. In some cases you may want
to give such a type specification a name. The obvious case is when
you are using the same type for many user options: rather than repeat
the specification for each option, you can give the type specification
a name, and use that name each defcustom
. The other case is
when a user option’s value is a recursive data structure. To make it
possible for a datatype to refer to itself, it needs to have a name.
Since custom types are implemented as widgets, the way to define a new customize type is to define a new widget. We are not going to describe the widget interface here in details, see Introduction in The Emacs Widget Library, for that. Instead we are going to demonstrate the minimal functionality needed for defining new customize types by a simple example.
(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)
The function to define a new widget is called define-widget
. The
first argument is the symbol we want to make a new widget type. The
second argument is a symbol representing an existing widget, the new
widget is going to be defined in terms of difference from the existing
widget. For the purpose of defining new customization types, the
lazy
widget is perfect, because it accepts a :type
keyword
argument with the same syntax as the keyword argument to
defcustom
with the same name. The third argument is a
documentation string for the new widget. You will be able to see that
string with the M-x widget-browse RET binary-tree-of-string
RET command.
After these mandatory arguments follow the keyword arguments. The most
important is :type
, which describes the data type we want to match
with this widget. Here a binary-tree-of-string
is described as
being either a string, or a cons-cell whose car and cdr are themselves
both binary-tree-of-string
. Note the reference to the widget
type we are currently in the process of defining. The :tag
attribute is a string to name the widget in the user interface, and the
:offset
argument is there to ensure that child nodes are
indented four spaces relative to the parent node, making the tree
structure apparent in the customization buffer.
The defcustom
shows how the new widget can be used as an ordinary
customization type.
The reason for the name lazy
is that the other composite
widgets convert their inferior widgets to internal form when the
widget is instantiated in a buffer. This conversion is recursive, so
the inferior widgets will convert their inferior widgets. If
the data structure is itself recursive, this conversion is an infinite
recursion. The lazy
widget prevents the recursion: it convert
its :type
argument only when needed.