1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<h4 class="subsection">Defining New Types</h4> <p>In the previous sections we have described how to construct elaborate type specifications for <code>defcustom</code>. 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 <code>defcustom</code>. 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. </p> <p>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 <a href="https://www.gnu.org/software/emacs/manual/html_node/widget/index.html#Top">Introduction</a> in <cite>The Emacs Widget Library</cite>, for that. Instead we are going to demonstrate the minimal functionality needed for defining new customize types by a simple example. </p> <div class="example"> <pre class="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)
</pre>
</div> <p>The function to define a new widget is called <code>define-widget</code>. 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 <code>lazy</code> widget is perfect, because it accepts a <code>:type</code> keyword argument with the same syntax as the keyword argument to <code>defcustom</code> 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 <kbd>M-x widget-browse <span class="key">RET</span> binary-tree-of-string <span class="key">RET</span></kbd> command. </p> <p>After these mandatory arguments follow the keyword arguments. The most important is <code>:type</code>, which describes the data type we want to match with this widget. Here a <code>binary-tree-of-string</code> is described as being either a string, or a cons-cell whose car and cdr are themselves both <code>binary-tree-of-string</code>. Note the reference to the widget type we are currently in the process of defining. The <code>:tag</code> attribute is a string to name the widget in the user interface, and the <code>:offset</code> 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. </p> <p>The <code>defcustom</code> shows how the new widget can be used as an ordinary customization type. </p> <p>The reason for the name <code>lazy</code> 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 <em>their</em> inferior widgets. If the data structure is itself recursive, this conversion is an infinite recursion. The <code>lazy</code> widget prevents the recursion: it convert its <code>:type</code> argument only when needed. </p><div class="_attribution">
<p class="_attribution-p">
Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc. <br>Licensed under the GNU GPL license.<br>
<a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Defining-New-Types.html" class="_attribution-link">https://www.gnu.org/software/emacs/manual/html_node/elisp/Defining-New-Types.html</a>
</p>
</div>
|