From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Per Abrahamsen Newsgroups: gmane.emacs.devel Subject: Creating recursive customization types / widgets Date: Sat, 29 Nov 2003 17:38:24 +0100 Organization: The Church of Emacs Sender: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Message-ID: NNTP-Posting-Host: deer.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1070123979 8412 80.91.224.253 (29 Nov 2003 16:39:39 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Sat, 29 Nov 2003 16:39:39 +0000 (UTC) Original-X-From: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Sat Nov 29 17:39:35 2003 Return-path: Original-Received: from quimby.gnus.org ([80.91.224.244]) by deer.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 1AQ887-0006Yk-00 for ; Sat, 29 Nov 2003 17:39:35 +0100 Original-Received: from monty-python.gnu.org ([199.232.76.173]) by quimby.gnus.org with esmtp (Exim 3.35 #1 (Debian)) id 1AQ887-0006Da-00 for ; Sat, 29 Nov 2003 17:39:35 +0100 Original-Received: from localhost ([127.0.0.1] helo=monty-python.gnu.org) by monty-python.gnu.org with esmtp (Exim 4.24) id 1AQ956-0006H1-Hq for emacs-devel@quimby.gnus.org; Sat, 29 Nov 2003 12:40:32 -0500 Original-Received: from list by monty-python.gnu.org with tmda-scanned (Exim 4.24) id 1AQ94y-0006GE-Pp for emacs-devel@gnu.org; Sat, 29 Nov 2003 12:40:24 -0500 Original-Received: from mail by monty-python.gnu.org with spam-scanned (Exim 4.24) id 1AQ94S-00066i-I0 for emacs-devel@gnu.org; Sat, 29 Nov 2003 12:40:23 -0500 Original-Received: from [80.91.224.249] (helo=main.gmane.org) by monty-python.gnu.org with esmtp (Exim 4.24) id 1AQ94R-00065n-N2 for emacs-devel@gnu.org; Sat, 29 Nov 2003 12:39:51 -0500 Original-Received: from list by main.gmane.org with local (Exim 3.35 #1 (Debian)) id 1AQ870-0002Ng-00 for ; Sat, 29 Nov 2003 17:38:26 +0100 Mail-Followup-To: emacs-devel@gnu.org X-Injected-Via-Gmane: http://gmane.org/ Original-To: emacs-devel@gnu.org Original-Received: from sea.gmane.org ([80.91.224.252]) by main.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 1AQ86y-0002NU-00 for ; Sat, 29 Nov 2003 17:38:24 +0100 Original-Received: from news by sea.gmane.org with local (Exim 3.35 #1 (Debian)) id 1AQ86y-00029s-00 for ; Sat, 29 Nov 2003 17:38:24 +0100 Original-Lines: 106 Original-X-Complaints-To: usenet@sea.gmane.org X-Face: +kRV2]2q}lixHkE{U)mY#+6]{AH=yN~S9@IFiOa@X6?GM|8MBp/ Mail-Copies-To: nobody User-Agent: Gnus/5.1003 (Gnus v5.10.3) Emacs/21.3 (gnu/linux) Cancel-Lock: sha1:2Q6ytm/kEvDFEqgMqsOV5Rvwy3w= X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.2 Precedence: list List-Id: Emacs development discussions. List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Xref: main.gmane.org gmane.emacs.devel:18207 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:18207 Creating new widgets from existing customization type specifications has something of a black magic feel to it, and creating widgets for recursive datastructures is next to impossible. Below is a new widget named "child", which should simplify both tasks a lot. Background: The predefined complex widgets, i.e. the widgets that is build from other widgets, has their types expanded at creation for speed. This obviously goes wrong for recursive types. This new "child" widget is a delayed action wrapper of an arbitrary widget, specified in its :type argument. The value of the :type argument will not be expanded before it is needed, which allow for recursive datastructures. Since the :type argument to this widget takes exactly the same values as the :type argument to defcustom, it will also be useful for people who want to "name" a type for custom use. If the datastructures is recursive, you need to gave a :match argument as well as :type. If not, it will simply match any values that the type specified for :type will match. Here is the code for the "child" widget, as well as an example of a recursive datastructure (a binary tree of strings). I suggest we add the "child" widget to wid-edit.el, and document it somewhere. (define-widget 'child 'default "Base widget for recursive datastructures. You need to set :type to the widget type for the datastructure you want to define, and set :match to a function that matches the datastructure. If the datastructure is not recursive, you don't have to set :match." :format "%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-child-value-create :value-delete 'widget-children-value-delete :value-get 'widget-child-value-get :value-inline 'widget-child-value-inline :default-get 'widget-child-default-get :validate 'widget-child-validate) (defun widget-child-value-create (widget) "Create the child widget." (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-child-value-get (widget) ;; Get value of the child widget. (widget-value (car (widget-get widget :children)))) (defun widget-child-value-inline (widget) ;; Get value of the child widget. (widget-apply (car (widget-get widget :children)) :value-inline)) (defun widget-child-default-get (widget) ;; Get default for the child. (widget-default-get (car (widget-get widget :args)))) (defun widget-child-match (widget value) "Matches iff the child matches. You need to overwrite you want to match recursive datastructures." (widget-apply (widget-convert (widget-get widget :type)) :match value)) (defun widget-child-validate (widget) "Valid iff the child is valid." (widget-apply (car (widget-get widget :children)) :validate)) (define-widget 'binary-tree-of-string 'child "A binary tree made of cons-cells and strings." :offset 4 :match (lambda (widget value) (binary-tree-of-string-p value)) :type '(menu-choice (string :tag "Leaf" :value "") (cons :tag "Interior" :value ("" . "") binary-tree-of-string binary-tree-of-string))) (defun binary-tree-of-string-p (object) "Return t if OBJECT is a binary tree of strings." (or (stringp object) (and (consp object) (binary-tree-of-string-p (car object)) (binary-tree-of-string-p (cdr object))))) ;; Evaluate this to edit the buffer again. (lisp-interaction-mode) ;; Evaluate this to get the current value. (widget-value w) ;; Evaluate this to create and edit a test widget. (progn (setq w (widget-create 'binary-tree-of-string '("a" . (("b" . "c") . "d")))) (widget-setup) (widget-browse-mode))