2003-12-12 Jesper Harder <harder@ifa.au.dk>

* cus-edit.el (custom-add-parent-links): Define "many".

2003-12-08  Per Abrahamsen  <abraham@dina.kvl.dk>

	* wid-edit.el (widget-child-value-get, widget-child-value-inline)
	(widget-child-validate, widget-type-value-create)
	(widget-type-default-get, widget-type-match): New functions.
	(lazy): New widget.
	(menu-choice, checklist, radio-button-choice, editable-list)
	(group, documentation-string): Removed redundant (per 2003-10-25
	change) calls to `widget-children-value-delete'.
	(widget-choice-value-get, widget-choice-value-inline): Removed
	functions.
	(menu-choice): Updated widget.
This commit is contained in:
Per Abrahamsen 2003-12-27 16:41:13 +00:00
parent c91406620c
commit cfa921fd39
4 changed files with 185 additions and 18 deletions

View file

@ -76,6 +76,23 @@
* info.el (Info-unescape-quotes, Info-split-parameter-string)
(Info-goto-emacs-command-node): Doc fixes.
2003-12-12 Jesper Harder <harder@ifa.au.dk>
* cus-edit.el (custom-add-parent-links): Define "many".
2003-12-08 Per Abrahamsen <abraham@dina.kvl.dk>
* wid-edit.el (widget-child-value-get, widget-child-value-inline)
(widget-child-validate, widget-type-value-create)
(widget-type-default-get, widget-type-match): New functions.
(lazy): New widget.
(menu-choice, checklist, radio-button-choice, editable-list)
(group, documentation-string): Removed redundant (per 2003-10-25
change) calls to `widget-children-value-delete'.
(widget-choice-value-get, widget-choice-value-inline): Removed
functions.
(menu-choice): Updated widget.
2003-12-03 Kenichi Handa <handa@m17n.org>
* language/cyrillic.el: Register "microsoft-cp1251" in

View file

@ -1970,7 +1970,8 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
(setq parents (cons symbol parents))))))
(and (null (get symbol 'custom-links)) ;No links of its own.
(= (length parents) 1) ;A single parent.
(let ((links (get (car parents) 'custom-links)))
(let* ((links (get (car parents) 'custom-links))
(many (> (length links) 2)))
(when links
(insert "\nParent documentation: ")
(while links

View file

@ -1267,6 +1267,42 @@ Optional EVENT is the event that triggered the action."
found (widget-apply child :validate)))
found))
(defun widget-child-value-get (widget)
"Get the value of the first member of :children in WIDGET."
(widget-value (car (widget-get widget :children))))
(defun widget-child-value-inline (widget)
"Get the inline value of the first member of :children in WIDGET."
(widget-apply (car (widget-get widget :children)) :value-inline))
(defun widget-child-validate (widget)
"The result of validating the first member of :children in WIDGET."
(widget-apply (car (widget-get widget :children)) :validate))
(defun widget-type-value-create (widget)
"Convert and instantiate the value of the :type attribute of WIDGET.
Store the newly created widget in the :children attribute.
The value of the :type attribute should be an unconverted widget type."
(let ((value (widget-get widget :value))
(type (widget-get widget :type)))
(widget-put widget :children
(list (widget-create-child-value widget
(widget-convert type)
value)))))
(defun widget-type-default-get (widget)
"Get default value from the :type attribute of WIDGET.
The value of the :type attribute should be an unconverted widget type."
(widget-default-get (widget-convert (widget-get widget :type))))
(defun widget-type-match (widget value)
"Non-nil if the :type value of WIDGET matches VALUE.
The value of the :type attribute should be an unconverted widget type."
(widget-apply (widget-convert (widget-get widget :type)) :match value))
(defun widget-types-copy (widget)
"Copy :args as widget types in WIDGET."
(widget-put widget :args (mapcar 'widget-copy (widget-get widget :args)))
@ -1862,9 +1898,8 @@ the earlier input."
:tag "choice"
:void '(item :format "invalid (%t)\n")
:value-create 'widget-choice-value-create
:value-delete 'widget-children-value-delete
:value-get 'widget-choice-value-get
:value-inline 'widget-choice-value-inline
:value-get 'widget-child-value-get
:value-inline 'widget-child-value-inline
:default-get 'widget-choice-default-get
:mouse-down-action 'widget-choice-mouse-down-action
:action 'widget-choice-action
@ -1901,14 +1936,6 @@ the earlier input."
widget void :value value)))
(widget-put widget :choice void))))))
(defun widget-choice-value-get (widget)
;; Get value of the child widget.
(widget-value (car (widget-get widget :children))))
(defun widget-choice-value-inline (widget)
;; Get value of the child widget.
(widget-apply (car (widget-get widget :children)) :value-inline))
(defun widget-choice-default-get (widget)
;; Get default for the first choice.
(widget-default-get (car (widget-get widget :args))))
@ -2099,7 +2126,6 @@ when he invoked the menu."
:entry-format "%b %v"
:greedy nil
:value-create 'widget-checklist-value-create
:value-delete 'widget-children-value-delete
:value-get 'widget-checklist-value-get
:validate 'widget-checklist-validate
:match 'widget-checklist-match
@ -2276,7 +2302,6 @@ Return an alist of (TYPE MATCH)."
:format "%v"
:entry-format "%b %v"
:value-create 'widget-radio-value-create
:value-delete 'widget-children-value-delete
:value-get 'widget-radio-value-get
:value-inline 'widget-radio-value-inline
:value-set 'widget-radio-value-set
@ -2466,7 +2491,6 @@ Return an alist of (TYPE MATCH)."
:format-handler 'widget-editable-list-format-handler
:entry-format "%i %d %v"
:value-create 'widget-editable-list-value-create
:value-delete 'widget-children-value-delete
:value-get 'widget-editable-list-value-get
:validate 'widget-children-validate
:match 'widget-editable-list-match
@ -2637,7 +2661,6 @@ Return an alist of (TYPE MATCH)."
:copy 'widget-types-copy
:format "%v"
:value-create 'widget-group-value-create
:value-delete 'widget-children-value-delete
:value-get 'widget-editable-list-value-get
:default-get 'widget-group-default-get
:validate 'widget-children-validate
@ -2803,7 +2826,6 @@ link for that string."
"A documentation string."
:format "%v"
:action 'widget-documentation-string-action
:value-delete 'widget-children-value-delete
:value-create 'widget-documentation-string-value-create)
(defun widget-documentation-string-value-create (widget)
@ -3250,6 +3272,62 @@ To use this type, you must define :match or :match-alternatives."
(widget-group-match widget
(widget-apply widget :value-to-internal value))))
;;; The `lazy' Widget.
;;
;; Recursive datatypes.
(define-widget 'lazy 'default
"Base widget for recursive datastructures.
The `lazy' widget will, when instantiated, contain a single inferior
widget, of the widget type specified by the :type parameter. The
value of the `lazy' widget is the same as the value of the inferior
widget. When deriving a new widget from the 'lazy' widget, the :type
parameter is allowed to refer to the widget currently being defined,
thus allowing recursive datastructures to be described.
The :type parameter takes the same arguments as the defcustom
parameter with the same name.
Most composite widgets, i.e. widgets containing other widgets, does
not allow recursion. That is, when you define a new widget type, none
of the inferior widgets may be of the same type you are currently
defining.
In Lisp, however, it is custom to define datastructures in terms of
themselves. A list, for example, is defined as either nil, or a cons
cell whose cdr itself is a list. The obvious way to translate this
into a widget type would be
(define-widget 'my-list 'choice
\"A list of sexps.\"
:tag \"Sexp list\"
:args '((const nil) (cons :value (nil) sexp my-list)))
Here we attempt to define my-list as a choice of either the constant
nil, or a cons-cell containing a sexp and my-lisp. This will not work
because the `choice' widget does not allow recursion.
Using the `lazy' widget you can overcome this problem, as in this
example:
(define-widget 'sexp-list 'lazy
\"A list of sexps.\"
:tag \"Sexp list\"
:type '(choice (const nil) (cons :value (nil) sexp sexp-list)))"
:format "%{%t%}: %v"
;; We don't convert :type because we want to allow recursive
;; datastructures. This is slow, so we should not create speed
;; critical widgets by deriving from this.
:convert-widget 'widget-value-convert-widget
:value-create 'widget-type-value-create
:value-get 'widget-child-value-get
:value-inline 'widget-child-value-inline
:default-get 'widget-type-default-get
:match 'widget-type-match
:validate 'widget-child-validate)
;;; The `plist' Widget.
;;
;; Property lists.

View file

@ -1,6 +1,6 @@
@c -*-texinfo-*-
@c This is part of the GNU Emacs Lisp Reference Manual.
@c Copyright (C) 1997, 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
@c Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
@c See the file elisp.texi for copying conditions.
@setfilename ../info/customize
@node Customization, Loading, Macros, Top
@ -373,6 +373,7 @@ equivalent to @code{(string)}.
* Composite Types::
* Splicing into Lists::
* Type Keywords::
* Defining New Types::
@end menu
All customization types are implemented as widgets; see @ref{Top, ,
@ -1056,6 +1057,76 @@ arguments, which will be used when creating the @code{radio-button} or
@end ignore
@end table
@node Defining New Types
@subsection Defining New Types
In the previous sections we have described how to construct elaborate
type specifications for @code{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 once, and use that name each @code{defcustom}. The other case is
when a user option accept a recursive datastructure. 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 @ref{Top, , Introduction,
widget, 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.
@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)
@end example
The function to define a new widget is name @code{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
@code{lazy} widget is perfect, because it accept a @code{:type} keyword
argument with the same syntax as the keyword argument to
@code{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 @kbd{M-x widget-browse @key{ret} binary-tree-of-string
@key{ret}} command.
After these mandatory arguments follows the keyword arguments. The most
important is @code{:type}, which describes the datatype we want to match
with this widget. Here a @code{binary-tree-of-string} is described as
being either a string, or a cons-cell whose car and cdr are themselves
both @code{binary-tree-of-string}. Note the reference to the widget
type we are currently in the process of defining. The @code{:tag}
attribute is a string to name the widget in the user interface, and the
@code{:offset} argument are there to ensure that child nodes are
indented four spaces relatively to the parent node, making the tree
structure apparent in the customization buffer.
The @code{defcustom} shows how the new widget can be used as an ordinary
customization type.
If you wonder about the name @code{lazy}, know 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 @emph{their} inferior widgets. If the
datastructure is itself recursive, this conversion will go on forever,
or at least until Emacs run out of stack space. The @code{lazy} widget
stop this recursion, it will only convert its @code{:type} argument when
needed.
@ignore
arch-tag: d1b8fad3-f48c-4ce4-a402-f73b5ef19bd2
@end ignore