aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/cus-edit.el398
-rw-r--r--lisp/custom.el154
-rw-r--r--lisp/wid-browse.el35
-rw-r--r--lisp/wid-edit.el180
-rw-r--r--lisp/widget.el13
5 files changed, 622 insertions, 158 deletions
diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el
index 43a8ca53ade..eafbcec48c9 100644
--- a/lisp/cus-edit.el
+++ b/lisp/cus-edit.el
@@ -4,7 +4,7 @@
4;; 4;;
5;; Author: Per Abrahamsen <abraham@dina.kvl.dk> 5;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6;; Keywords: help, faces 6;; Keywords: help, faces
7;; Version: 1.84 7;; Version: 1.90
8;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ 8;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
9 9
10;; This file is part of GNU Emacs. 10;; This file is part of GNU Emacs.
@@ -26,6 +26,8 @@
26 26
27;;; Commentary: 27;;; Commentary:
28;; 28;;
29;; This file implements the code to create and edit customize buffers.
30;;
29;; See `custom.el'. 31;; See `custom.el'.
30 32
31;;; Code: 33;;; Code:
@@ -33,6 +35,11 @@
33(require 'cus-face) 35(require 'cus-face)
34(require 'wid-edit) 36(require 'wid-edit)
35(require 'easymenu) 37(require 'easymenu)
38(eval-when-compile (require 'cl))
39
40(condition-case nil
41 (require 'cus-load)
42 (error nil))
36 43
37(defun custom-face-display-set (face spec &optional frame) 44(defun custom-face-display-set (face spec &optional frame)
38 (face-spec-set face spec frame)) 45 (face-spec-set face spec frame))
@@ -355,10 +362,30 @@ Return a list suitable for use in `interactive'."
355 (if v 362 (if v
356 (format "Customize variable (default %s): " v) 363 (format "Customize variable (default %s): " v)
357 "Customize variable: ") 364 "Customize variable: ")
358 obarray 'boundp t)) 365 obarray (lambda (symbol)
366 (and (boundp symbol)
367 (or (get symbol 'custom-type)
368 (user-variable-p symbol))))))
359 (list (if (equal val "") 369 (list (if (equal val "")
360 v (intern val))))) 370 v (intern val)))))
361 371
372(defun custom-menu-filter (menu widget)
373 "Convert MENU to the form used by `widget-choose'.
374MENU should be in the same format as `custom-variable-menu'.
375WIDGET is the widget to apply the filter entries of MENU on."
376 (let ((result nil)
377 current name action filter)
378 (while menu
379 (setq current (car menu)
380 name (nth 0 current)
381 action (nth 1 current)
382 filter (nth 2 current)
383 menu (cdr menu))
384 (if (or (null filter) (funcall filter widget))
385 (push (cons name action) result)
386 (push name result)))
387 (nreverse result)))
388
362;;; Unlispify. 389;;; Unlispify.
363 390
364(defvar custom-prefix-list nil 391(defvar custom-prefix-list nil
@@ -552,6 +579,74 @@ when the action is chosen.")
552 579
553;;; The Customize Commands 580;;; The Customize Commands
554 581
582(defun custom-prompt-variable (prompt-var prompt-val)
583 "Prompt for a variable and a value and return them as a list.
584PROMPT-VAR is the prompt for the variable, and PROMPT-VAL is the
585prompt for the value. The %s escape in PROMPT-VAL is replaced with
586the name of the variable.
587
588If the variable has a `variable-interactive' property, that is used as if
589it were the arg to `interactive' (which see) to interactively read the value.
590
591If the variable has a `custom-type' property, it must be a widget and the
592`:prompt-value' property of that widget will be used for reading the value."
593 (let* ((var (read-variable prompt-var))
594 (minibuffer-help-form '(describe-variable var)))
595 (list var
596 (let ((prop (get var 'variable-interactive))
597 (type (get var 'custom-type))
598 (prompt (format prompt-val var)))
599 (unless (listp type)
600 (setq type (list type)))
601 (cond (prop
602 ;; Use VAR's `variable-interactive' property
603 ;; as an interactive spec for prompting.
604 (call-interactively (list 'lambda '(arg)
605 (list 'interactive prop)
606 'arg)))
607 (type
608 (widget-prompt-value type
609 prompt
610 (if (boundp var)
611 (symbol-value var))
612 (not (boundp var))))
613 (t
614 (eval-minibuffer prompt)))))))
615
616;;;###autoload
617(defun custom-set-value (var val)
618 "Set VARIABLE to VALUE. VALUE is a Lisp object.
619
620If VARIABLE has a `variable-interactive' property, that is used as if
621it were the arg to `interactive' (which see) to interactively read the value.
622
623If VARIABLE has a `custom-type' property, it must be a widget and the
624`:prompt-value' property of that widget will be used for reading the value."
625 (interactive (custom-prompt-variable "Set variable: "
626 "Set %s to value: "))
627
628 (set var val))
629
630;;;###autoload
631(defun custom-set-variable (var val)
632 "Set the default for VARIABLE to VALUE. VALUE is a Lisp object.
633
634If VARIABLE has a `custom-set' property, that is used for setting
635VARIABLE, otherwise `set-default' is used.
636
637The `customized-value' property of the VARIABLE will be set to a list
638with a quoted VALUE as its sole list member.
639
640If VARIABLE has a `variable-interactive' property, that is used as if
641it were the arg to `interactive' (which see) to interactively read the value.
642
643If VARIABLE has a `custom-type' property, it must be a widget and the
644`:prompt-value' property of that widget will be used for reading the value. "
645 (interactive (custom-prompt-variable "Set variable: "
646 "Set customized value for %s to: "))
647 (funcall (or (get var 'custom-set) 'set-default) var val)
648 (put var 'customized-value (list (custom-quote val))))
649
555;;;###autoload 650;;;###autoload
556(defun customize (symbol) 651(defun customize (symbol)
557 "Customize SYMBOL, which must be a customization group." 652 "Customize SYMBOL, which must be a customization group."
@@ -568,6 +663,21 @@ when the action is chosen.")
568 (custom-buffer-create (list (list symbol 'custom-group)))) 663 (custom-buffer-create (list (list symbol 'custom-group))))
569 664
570;;;###autoload 665;;;###autoload
666(defun customize-other-window (symbol)
667 "Customize SYMBOL, which must be a customization group."
668 (interactive (list (completing-read "Customize group: (default emacs) "
669 obarray
670 (lambda (symbol)
671 (get symbol 'custom-group))
672 t)))
673
674 (when (stringp symbol)
675 (if (string-equal "" symbol)
676 (setq symbol 'emacs)
677 (setq symbol (intern symbol))))
678 (custom-buffer-create-other-window (list (list symbol 'custom-group))))
679
680;;;###autoload
571(defun customize-variable (symbol) 681(defun customize-variable (symbol)
572 "Customize SYMBOL, which must be a variable." 682 "Customize SYMBOL, which must be a variable."
573 (interactive (custom-variable-prompt)) 683 (interactive (custom-variable-prompt))
@@ -617,7 +727,24 @@ If SYMBOL is nil, customize all faces."
617 727
618;;;###autoload 728;;;###autoload
619(defun customize-customized () 729(defun customize-customized ()
620 "Customize all already customized user options." 730 "Customize all user options set since the last save in this session."
731 (interactive)
732 (let ((found nil))
733 (mapatoms (lambda (symbol)
734 (and (get symbol 'customized-face)
735 (custom-facep symbol)
736 (setq found (cons (list symbol 'custom-face) found)))
737 (and (get symbol 'customized-value)
738 (boundp symbol)
739 (setq found
740 (cons (list symbol 'custom-variable) found)))))
741 (if found
742 (custom-buffer-create found)
743 (error "No customized user options"))))
744
745;;;###autoload
746(defun customize-saved ()
747 "Customize all already saved user options."
621 (interactive) 748 (interactive)
622 (let ((found nil)) 749 (let ((found nil))
623 (mapatoms (lambda (symbol) 750 (mapatoms (lambda (symbol)
@@ -630,7 +757,7 @@ If SYMBOL is nil, customize all faces."
630 (cons (list symbol 'custom-variable) found))))) 757 (cons (list symbol 'custom-variable) found)))))
631 (if found 758 (if found
632 (custom-buffer-create found) 759 (custom-buffer-create found)
633 (error "No customized user options")))) 760 (error "No saved user options"))))
634 761
635;;;###autoload 762;;;###autoload
636(defun customize-apropos (regexp &optional all) 763(defun customize-apropos (regexp &optional all)
@@ -657,6 +784,8 @@ user-settable."
657 (custom-buffer-create found) 784 (custom-buffer-create found)
658 (error "No matches")))) 785 (error "No matches"))))
659 786
787;;; Buffer.
788
660;;;###autoload 789;;;###autoload
661(defun custom-buffer-create (options) 790(defun custom-buffer-create (options)
662 "Create a buffer containing OPTIONS. 791 "Create a buffer containing OPTIONS.
@@ -667,6 +796,7 @@ that option."
667 (switch-to-buffer (get-buffer-create "*Customization*")) 796 (switch-to-buffer (get-buffer-create "*Customization*"))
668 (custom-buffer-create-internal options)) 797 (custom-buffer-create-internal options))
669 798
799;;;###autoload
670(defun custom-buffer-create-other-window (options) 800(defun custom-buffer-create-other-window (options)
671 "Create a buffer containing OPTIONS. 801 "Create a buffer containing OPTIONS.
672OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where 802OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where
@@ -758,6 +888,7 @@ Make the modifications default for future sessions."
758 (message "Creating customization setup...") 888 (message "Creating customization setup...")
759 (widget-setup) 889 (widget-setup)
760 (goto-char (point-min)) 890 (goto-char (point-min))
891 (forward-line 3) ;Kludge: bob is writable in XEmacs.
761 (message "Creating customization buffer...done")) 892 (message "Creating customization buffer...done"))
762 893
763;;; Modification of Basic Widgets. 894;;; Modification of Basic Widgets.
@@ -939,6 +1070,7 @@ The list should be sorted most significant first."
939 "Show and manipulate state for a customization option." 1070 "Show and manipulate state for a customization option."
940 :format "%v" 1071 :format "%v"
941 :action 'widget-choice-item-action 1072 :action 'widget-choice-item-action
1073 :notify 'ignore
942 :value-get 'ignore 1074 :value-get 'ignore
943 :value-create 'custom-magic-value-create 1075 :value-create 'custom-magic-value-create
944 :value-delete 'widget-children-value-delete) 1076 :value-delete 'widget-children-value-delete)
@@ -998,15 +1130,7 @@ Change the state of this item."
998 1130
999(defun custom-level-action (widget &optional event) 1131(defun custom-level-action (widget &optional event)
1000 "Toggle visibility for parent to WIDGET." 1132 "Toggle visibility for parent to WIDGET."
1001 (let* ((parent (widget-get widget :parent)) 1133 (custom-toggle-hide (widget-get widget :parent)))
1002 (state (widget-get parent :custom-state)))
1003 (cond ((memq state '(invalid modified))
1004 (error "There are unset changes"))
1005 ((eq state 'hidden)
1006 (widget-put parent :custom-state 'unknown))
1007 (t
1008 (widget-put parent :custom-state 'hidden)))
1009 (custom-redraw parent)))
1010 1134
1011;;; The `custom' Widget. 1135;;; The `custom' Widget.
1012 1136
@@ -1094,14 +1218,20 @@ Change the state of this item."
1094 1218
1095(defun custom-redraw (widget) 1219(defun custom-redraw (widget)
1096 "Redraw WIDGET with current settings." 1220 "Redraw WIDGET with current settings."
1097 (let ((pos (point)) 1221 (let ((line (count-lines (point-min) (point)))
1222 (column (current-column))
1223 (pos (point))
1098 (from (marker-position (widget-get widget :from))) 1224 (from (marker-position (widget-get widget :from)))
1099 (to (marker-position (widget-get widget :to)))) 1225 (to (marker-position (widget-get widget :to))))
1100 (save-excursion 1226 (save-excursion
1101 (widget-value-set widget (widget-value widget)) 1227 (widget-value-set widget (widget-value widget))
1102 (custom-redraw-magic widget)) 1228 (custom-redraw-magic widget))
1103 (when (and (>= pos from) (<= pos to)) 1229 (when (and (>= pos from) (<= pos to))
1104 (goto-char pos)))) 1230 (condition-case nil
1231 (progn
1232 (goto-line line)
1233 (move-to-column column))
1234 (error nil)))))
1105 1235
1106(defun custom-redraw-magic (widget) 1236(defun custom-redraw-magic (widget)
1107 "Redraw WIDGET state with current settings." 1237 "Redraw WIDGET state with current settings."
@@ -1150,6 +1280,17 @@ Change the state of this item."
1150 "Load all dependencies for WIDGET." 1280 "Load all dependencies for WIDGET."
1151 (custom-load-symbol (widget-value widget))) 1281 (custom-load-symbol (widget-value widget)))
1152 1282
1283(defun custom-toggle-hide (widget)
1284 "Toggle visibility of WIDGET."
1285 (let ((state (widget-get widget :custom-state)))
1286 (cond ((memq state '(invalid modified))
1287 (error "There are unset changes"))
1288 ((eq state 'hidden)
1289 (widget-put widget :custom-state 'unknown))
1290 (t
1291 (widget-put widget :custom-state 'hidden)))
1292 (custom-redraw widget)))
1293
1153;;; The `custom-variable' Widget. 1294;;; The `custom-variable' Widget.
1154 1295
1155(defface custom-variable-sample-face '((t (:underline t))) 1296(defface custom-variable-sample-face '((t (:underline t)))
@@ -1203,8 +1344,10 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
1203 (tag (widget-get widget :tag)) 1344 (tag (widget-get widget :tag))
1204 (type (custom-variable-type symbol)) 1345 (type (custom-variable-type symbol))
1205 (conv (widget-convert type)) 1346 (conv (widget-convert type))
1347 (get (or (get symbol 'custom-get) 'default-value))
1348 (set (or (get symbol 'custom-set) 'set-default))
1206 (value (if (default-boundp symbol) 1349 (value (if (default-boundp symbol)
1207 (default-value symbol) 1350 (funcall get symbol)
1208 (widget-get conv :value)))) 1351 (widget-get conv :value))))
1209 ;; If the widget is new, the child determine whether it is hidden. 1352 ;; If the widget is new, the child determine whether it is hidden.
1210 (cond (state) 1353 (cond (state)
@@ -1234,7 +1377,7 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
1234 ((get symbol 'factory-value) 1377 ((get symbol 'factory-value)
1235 (car (get symbol 'factory-value))) 1378 (car (get symbol 'factory-value)))
1236 ((default-boundp symbol) 1379 ((default-boundp symbol)
1237 (custom-quote (default-value symbol))) 1380 (custom-quote (funcall get symbol)))
1238 (t 1381 (t
1239 (custom-quote (widget-get conv :value)))))) 1382 (custom-quote (widget-get conv :value))))))
1240 (push (widget-create-child-and-convert 1383 (push (widget-create-child-and-convert
@@ -1266,8 +1409,9 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
1266(defun custom-variable-state-set (widget) 1409(defun custom-variable-state-set (widget)
1267 "Set the state of WIDGET." 1410 "Set the state of WIDGET."
1268 (let* ((symbol (widget-value widget)) 1411 (let* ((symbol (widget-value widget))
1412 (get (or (get symbol 'custom-get) 'default-value))
1269 (value (if (default-boundp symbol) 1413 (value (if (default-boundp symbol)
1270 (default-value symbol) 1414 (funcall get symbol)
1271 (widget-get widget :value))) 1415 (widget-get widget :value)))
1272 tmp 1416 tmp
1273 (state (cond ((setq tmp (get symbol 'customized-value)) 1417 (state (cond ((setq tmp (get symbol 'customized-value))
@@ -1292,29 +1436,52 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
1292 (widget-put widget :custom-state state))) 1436 (widget-put widget :custom-state state)))
1293 1437
1294(defvar custom-variable-menu 1438(defvar custom-variable-menu
1295 '(("Edit" . custom-variable-edit) 1439 '(("Hide" custom-toggle-hide
1296 ("Edit Lisp" . custom-variable-edit-lisp) 1440 (lambda (widget)
1297 ("Set" . custom-variable-set) 1441 (not (memq (widget-get widget :custom-state) '(modified invalid)))))
1298 ("Save" . custom-variable-save) 1442 ("Edit" custom-variable-edit
1299 ("Reset to Current" . custom-redraw) 1443 (lambda (widget)
1300 ("Reset to Saved" . custom-variable-reset-saved) 1444 (not (eq (widget-get widget :custom-form) 'edit))))
1301 ("Reset to Factory Settings" . custom-variable-reset-factory)) 1445 ("Edit Lisp" custom-variable-edit-lisp
1446 (lambda (widget)
1447 (not (eq (widget-get widget :custom-form) 'lisp))))
1448 ("Set" custom-variable-set
1449 (lambda (widget)
1450 (eq (widget-get widget :custom-state) 'modified)))
1451 ("Save" custom-variable-save
1452 (lambda (widget)
1453 (memq (widget-get widget :custom-state) '(modified set changed rogue))))
1454 ("Reset to Current" custom-redraw
1455 (lambda (widget)
1456 (and (default-boundp (widget-value widget))
1457 (memq (widget-get widget :custom-state) '(modified)))))
1458 ("Reset to Saved" custom-variable-reset-saved
1459 (lambda (widget)
1460 (and (get (widget-value widget) 'saved-value)
1461 (memq (widget-get widget :custom-state)
1462 '(modified set changed rogue)))))
1463 ("Reset to Factory Settings" custom-variable-reset-factory
1464 (lambda (widget)
1465 (and (get (widget-value widget) 'factory-value)
1466 (memq (widget-get widget :custom-state)
1467 '(modified set changed saved rogue))))))
1302 "Alist of actions for the `custom-variable' widget. 1468 "Alist of actions for the `custom-variable' widget.
1303The key is a string containing the name of the action, the value is a 1469Each entry has the form (NAME ACTION FILTER) where NAME is the name of
1304lisp function taking the widget as an element which will be called 1470the menu entry, ACTION is the function to call on the widget when the
1305when the action is chosen.") 1471menu is selected, and FILTER is a predicate which takes a `custom-variable'
1472widget as an argument, and returns non-nil if ACTION is valid on that
1473widget. If FILTER is nil, ACTION is always valid.")
1306 1474
1307(defun custom-variable-action (widget &optional event) 1475(defun custom-variable-action (widget &optional event)
1308 "Show the menu for `custom-variable' WIDGET. 1476 "Show the menu for `custom-variable' WIDGET.
1309Optional EVENT is the location for the menu." 1477Optional EVENT is the location for the menu."
1310 (if (eq (widget-get widget :custom-state) 'hidden) 1478 (if (eq (widget-get widget :custom-state) 'hidden)
1311 (progn 1479 (custom-toggle-hide widget)
1312 (widget-put widget :custom-state 'unknown)
1313 (custom-redraw widget))
1314 (let* ((completion-ignore-case t) 1480 (let* ((completion-ignore-case t)
1315 (answer (widget-choose (custom-unlispify-tag-name 1481 (answer (widget-choose (custom-unlispify-tag-name
1316 (widget-get widget :value)) 1482 (widget-get widget :value))
1317 custom-variable-menu 1483 (custom-menu-filter custom-variable-menu
1484 widget)
1318 event))) 1485 event)))
1319 (if answer 1486 (if answer
1320 (funcall answer widget))))) 1487 (funcall answer widget)))))
@@ -1333,32 +1500,34 @@ Optional EVENT is the location for the menu."
1333 1500
1334(defun custom-variable-set (widget) 1501(defun custom-variable-set (widget)
1335 "Set the current value for the variable being edited by WIDGET." 1502 "Set the current value for the variable being edited by WIDGET."
1336 (let ((form (widget-get widget :custom-form)) 1503 (let* ((form (widget-get widget :custom-form))
1337 (state (widget-get widget :custom-state)) 1504 (state (widget-get widget :custom-state))
1338 (child (car (widget-get widget :children))) 1505 (child (car (widget-get widget :children)))
1339 (symbol (widget-value widget)) 1506 (symbol (widget-value widget))
1340 val) 1507 (set (or (get symbol 'custom-set) 'set-default))
1508 val)
1341 (cond ((eq state 'hidden) 1509 (cond ((eq state 'hidden)
1342 (error "Cannot set hidden variable.")) 1510 (error "Cannot set hidden variable."))
1343 ((setq val (widget-apply child :validate)) 1511 ((setq val (widget-apply child :validate))
1344 (goto-char (widget-get val :from)) 1512 (goto-char (widget-get val :from))
1345 (error "%s" (widget-get val :error))) 1513 (error "%s" (widget-get val :error)))
1346 ((eq form 'lisp) 1514 ((eq form 'lisp)
1347 (set-default symbol (eval (setq val (widget-value child)))) 1515 (funcall set symbol (eval (setq val (widget-value child))))
1348 (put symbol 'customized-value (list val))) 1516 (put symbol 'customized-value (list val)))
1349 (t 1517 (t
1350 (set-default symbol (setq val (widget-value child))) 1518 (funcall set symbol (setq val (widget-value child)))
1351 (put symbol 'customized-value (list (custom-quote val))))) 1519 (put symbol 'customized-value (list (custom-quote val)))))
1352 (custom-variable-state-set widget) 1520 (custom-variable-state-set widget)
1353 (custom-redraw-magic widget))) 1521 (custom-redraw-magic widget)))
1354 1522
1355(defun custom-variable-save (widget) 1523(defun custom-variable-save (widget)
1356 "Set the default value for the variable being edited by WIDGET." 1524 "Set the default value for the variable being edited by WIDGET."
1357 (let ((form (widget-get widget :custom-form)) 1525 (let* ((form (widget-get widget :custom-form))
1358 (state (widget-get widget :custom-state)) 1526 (state (widget-get widget :custom-state))
1359 (child (car (widget-get widget :children))) 1527 (child (car (widget-get widget :children)))
1360 (symbol (widget-value widget)) 1528 (symbol (widget-value widget))
1361 val) 1529 (set (or (get symbol 'custom-set) 'set-default))
1530 val)
1362 (cond ((eq state 'hidden) 1531 (cond ((eq state 'hidden)
1363 (error "Cannot set hidden variable.")) 1532 (error "Cannot set hidden variable."))
1364 ((setq val (widget-apply child :validate)) 1533 ((setq val (widget-apply child :validate))
@@ -1366,12 +1535,12 @@ Optional EVENT is the location for the menu."
1366 (error "%s" (widget-get val :error))) 1535 (error "%s" (widget-get val :error)))
1367 ((eq form 'lisp) 1536 ((eq form 'lisp)
1368 (put symbol 'saved-value (list (widget-value child))) 1537 (put symbol 'saved-value (list (widget-value child)))
1369 (set-default symbol (eval (widget-value child)))) 1538 (funcall set symbol (eval (widget-value child))))
1370 (t 1539 (t
1371 (put symbol 1540 (put symbol
1372 'saved-value (list (custom-quote (widget-value 1541 'saved-value (list (custom-quote (widget-value
1373 child)))) 1542 child))))
1374 (set-default symbol (widget-value child)))) 1543 (funcall set symbol (widget-value child))))
1375 (put symbol 'customized-value nil) 1544 (put symbol 'customized-value nil)
1376 (custom-save-all) 1545 (custom-save-all)
1377 (custom-variable-state-set widget) 1546 (custom-variable-state-set widget)
@@ -1379,10 +1548,11 @@ Optional EVENT is the location for the menu."
1379 1548
1380(defun custom-variable-reset-saved (widget) 1549(defun custom-variable-reset-saved (widget)
1381 "Restore the saved value for the variable being edited by WIDGET." 1550 "Restore the saved value for the variable being edited by WIDGET."
1382 (let ((symbol (widget-value widget))) 1551 (let* ((symbol (widget-value widget))
1552 (set (or (get symbol 'custom-set) 'set-default)))
1383 (if (get symbol 'saved-value) 1553 (if (get symbol 'saved-value)
1384 (condition-case nil 1554 (condition-case nil
1385 (set-default symbol (eval (car (get symbol 'saved-value)))) 1555 (funcall set symbol (eval (car (get symbol 'saved-value))))
1386 (error nil)) 1556 (error nil))
1387 (error "No saved value for %s" symbol)) 1557 (error "No saved value for %s" symbol))
1388 (put symbol 'customized-value nil) 1558 (put symbol 'customized-value nil)
@@ -1391,9 +1561,10 @@ Optional EVENT is the location for the menu."
1391 1561
1392(defun custom-variable-reset-factory (widget) 1562(defun custom-variable-reset-factory (widget)
1393 "Restore the factory setting for the variable being edited by WIDGET." 1563 "Restore the factory setting for the variable being edited by WIDGET."
1394 (let ((symbol (widget-value widget))) 1564 (let* ((symbol (widget-value widget))
1565 (set (or (get symbol 'custom-set) 'set-default)))
1395 (if (get symbol 'factory-value) 1566 (if (get symbol 'factory-value)
1396 (set-default symbol (eval (car (get symbol 'factory-value)))) 1567 (funcall set symbol (eval (car (get symbol 'factory-value))))
1397 (error "No factory default for %S" symbol)) 1568 (error "No factory default for %S" symbol))
1398 (put symbol 'customized-value nil) 1569 (put symbol 'customized-value nil)
1399 (when (get symbol 'saved-value) 1570 (when (get symbol 'saved-value)
@@ -1550,9 +1721,7 @@ Match frames with dark backgrounds.")
1550 1721
1551(defun custom-display-unselected-match (widget value) 1722(defun custom-display-unselected-match (widget value)
1552 "Non-nil if VALUE is an unselected display specification." 1723 "Non-nil if VALUE is an unselected display specification."
1553 (and (listp value) 1724 (not (custom-display-match-frame value (selected-frame))))
1554 (eq (length value) 2)
1555 (not (custom-display-match-frame value (selected-frame)))))
1556 1725
1557(define-widget 'custom-face-selected 'group 1726(define-widget 'custom-face-selected 'group
1558 "Edit the attributes of the selected display in a face specification." 1727 "Edit the attributes of the selected display in a face specification."
@@ -1600,17 +1769,32 @@ Match frames with dark backgrounds.")
1600 (message "Creating face editor...done"))) 1769 (message "Creating face editor...done")))
1601 1770
1602(defvar custom-face-menu 1771(defvar custom-face-menu
1603 '(("Edit Selected" . custom-face-edit-selected) 1772 '(("Hide" custom-toggle-hide
1604 ("Edit All" . custom-face-edit-all) 1773 (lambda (widget)
1605 ("Edit Lisp" . custom-face-edit-lisp) 1774 (not (memq (widget-get widget :custom-state) '(modified invalid)))))
1606 ("Set" . custom-face-set) 1775 ("Edit Selected" custom-face-edit-selected
1607 ("Save" . custom-face-save) 1776 (lambda (widget)
1608 ("Reset to Saved" . custom-face-reset-saved) 1777 (not (eq (widget-get widget :custom-form) 'selected))))
1609 ("Reset to Factory Setting" . custom-face-reset-factory)) 1778 ("Edit All" custom-face-edit-all
1779 (lambda (widget)
1780 (not (eq (widget-get widget :custom-form) 'all))))
1781 ("Edit Lisp" custom-face-edit-lisp
1782 (lambda (widget)
1783 (not (eq (widget-get widget :custom-form) 'lisp))))
1784 ("Set" custom-face-set)
1785 ("Save" custom-face-save)
1786 ("Reset to Saved" custom-face-reset-saved
1787 (lambda (widget)
1788 (get (widget-value widget) 'saved-face)))
1789 ("Reset to Factory Setting" custom-face-reset-factory
1790 (lambda (widget)
1791 (get (widget-value widget) 'factory-face))))
1610 "Alist of actions for the `custom-face' widget. 1792 "Alist of actions for the `custom-face' widget.
1611The key is a string containing the name of the action, the value is a 1793Each entry has the form (NAME ACTION FILTER) where NAME is the name of
1612lisp function taking the widget as an element which will be called 1794the menu entry, ACTION is the function to call on the widget when the
1613when the action is chosen.") 1795menu is selected, and FILTER is a predicate which takes a `custom-face'
1796widget as an argument, and returns non-nil if ACTION is valid on that
1797widget. If FILTER is nil, ACTION is always valid.")
1614 1798
1615(defun custom-face-edit-selected (widget) 1799(defun custom-face-edit-selected (widget)
1616 "Edit selected attributes of the value of WIDGET." 1800 "Edit selected attributes of the value of WIDGET."
@@ -1646,13 +1830,13 @@ when the action is chosen.")
1646 "Show the menu for `custom-face' WIDGET. 1830 "Show the menu for `custom-face' WIDGET.
1647Optional EVENT is the location for the menu." 1831Optional EVENT is the location for the menu."
1648 (if (eq (widget-get widget :custom-state) 'hidden) 1832 (if (eq (widget-get widget :custom-state) 'hidden)
1649 (progn 1833 (custom-toggle-hide widget)
1650 (widget-put widget :custom-state 'unknown)
1651 (custom-redraw widget))
1652 (let* ((completion-ignore-case t) 1834 (let* ((completion-ignore-case t)
1653 (symbol (widget-get widget :value)) 1835 (symbol (widget-get widget :value))
1654 (answer (widget-choose (custom-unlispify-tag-name symbol) 1836 (answer (widget-choose (custom-unlispify-tag-name symbol)
1655 custom-face-menu event))) 1837 (custom-menu-filter custom-face-menu
1838 widget)
1839 event)))
1656 (if answer 1840 (if answer
1657 (funcall answer widget))))) 1841 (funcall answer widget)))))
1658 1842
@@ -1865,27 +2049,44 @@ and so forth. The remaining group tags are shown with
1865 (message "Creating group... done"))))) 2049 (message "Creating group... done")))))
1866 2050
1867(defvar custom-group-menu 2051(defvar custom-group-menu
1868 '(("Set" . custom-group-set) 2052 '(("Hide" custom-toggle-hide
1869 ("Save" . custom-group-save) 2053 (lambda (widget)
1870 ("Reset to Current" . custom-group-reset-current) 2054 (not (memq (widget-get widget :custom-state) '(modified invalid)))))
1871 ("Reset to Saved" . custom-group-reset-saved) 2055 ("Set" custom-group-set
1872 ("Reset to Factory" . custom-group-reset-factory)) 2056 (lambda (widget)
2057 (eq (widget-get widget :custom-state) 'modified)))
2058 ("Save" custom-group-save
2059 (lambda (widget)
2060 (memq (widget-get widget :custom-state) '(modified set))))
2061 ("Reset to Current" custom-group-reset-current
2062 (lambda (widget)
2063 (and (default-boundp (widget-value widget))
2064 (memq (widget-get widget :custom-state) '(modified)))))
2065 ("Reset to Saved" custom-group-reset-saved
2066 (lambda (widget)
2067 (and (get (widget-value widget) 'saved-value)
2068 (memq (widget-get widget :custom-state) '(modified set)))))
2069 ("Reset to Factory" custom-group-reset-factory
2070 (lambda (widget)
2071 (and (get (widget-value widget) 'factory-value)
2072 (memq (widget-get widget :custom-state) '(modified set saved))))))
1873 "Alist of actions for the `custom-group' widget. 2073 "Alist of actions for the `custom-group' widget.
1874The key is a string containing the name of the action, the value is a 2074Each entry has the form (NAME ACTION FILTER) where NAME is the name of
1875lisp function taking the widget as an element which will be called 2075the menu entry, ACTION is the function to call on the widget when the
1876when the action is chosen.") 2076menu is selected, and FILTER is a predicate which takes a `custom-group'
2077widget as an argument, and returns non-nil if ACTION is valid on that
2078widget. If FILTER is nil, ACTION is always valid.")
1877 2079
1878(defun custom-group-action (widget &optional event) 2080(defun custom-group-action (widget &optional event)
1879 "Show the menu for `custom-group' WIDGET. 2081 "Show the menu for `custom-group' WIDGET.
1880Optional EVENT is the location for the menu." 2082Optional EVENT is the location for the menu."
1881 (if (eq (widget-get widget :custom-state) 'hidden) 2083 (if (eq (widget-get widget :custom-state) 'hidden)
1882 (progn 2084 (custom-toggle-hide widget)
1883 (widget-put widget :custom-state 'unknown)
1884 (custom-redraw widget))
1885 (let* ((completion-ignore-case t) 2085 (let* ((completion-ignore-case t)
1886 (answer (widget-choose (custom-unlispify-tag-name 2086 (answer (widget-choose (custom-unlispify-tag-name
1887 (widget-get widget :value)) 2087 (widget-get widget :value))
1888 custom-group-menu 2088 (custom-menu-filter custom-group-menu
2089 widget)
1889 event))) 2090 event)))
1890 (if answer 2091 (if answer
1891 (funcall answer widget))))) 2092 (funcall answer widget)))))
@@ -1986,17 +2187,26 @@ Leave point at the location of the call, or after the last expression."
1986 (princ "\n")) 2187 (princ "\n"))
1987 (princ "(custom-set-variables") 2188 (princ "(custom-set-variables")
1988 (mapatoms (lambda (symbol) 2189 (mapatoms (lambda (symbol)
1989 (let ((value (get symbol 'saved-value))) 2190 (let ((value (get symbol 'saved-value))
2191 (requests (get symbol 'custom-requests))
2192 (now (not (or (get symbol 'factory-value)
2193 (and (not (boundp symbol))
2194 (not (get symbol 'force-value)))))))
1990 (when value 2195 (when value
1991 (princ "\n '(") 2196 (princ "\n '(")
1992 (princ symbol) 2197 (princ symbol)
1993 (princ " ") 2198 (princ " ")
1994 (prin1 (car value)) 2199 (prin1 (car value))
1995 (if (or (get symbol 'factory-value) 2200 (cond (requests
1996 (and (not (boundp symbol)) 2201 (if now
1997 (not (get symbol 'force-value)))) 2202 (princ " t ")
1998 (princ ")") 2203 (princ " nil "))
1999 (princ " t)")))))) 2204 (prin1 requests)
2205 (princ ")"))
2206 (now
2207 (princ " t)"))
2208 (t
2209 (princ ")")))))))
2000 (princ ")") 2210 (princ ")")
2001 (unless (looking-at "\n") 2211 (unless (looking-at "\n")
2002 (princ "\n"))))) 2212 (princ "\n")))))
@@ -2038,6 +2248,22 @@ Leave point at the location of the call, or after the last expression."
2038 (princ "\n"))))) 2248 (princ "\n")))))
2039 2249
2040;;;###autoload 2250;;;###autoload
2251(defun custom-save-customized ()
2252 "Save all user options which have been set in this session."
2253 (interactive)
2254 (mapatoms (lambda (symbol)
2255 (let ((face (get symbol 'customized-face))
2256 (value (get symbol 'customized-value)))
2257 (when face
2258 (put symbol 'saved-face face)
2259 (put symbol 'customized-face nil))
2260 (when value
2261 (put symbol 'saved-value value)
2262 (put symbol 'customized-value nil)))))
2263 ;; We really should update all custom buffers here.
2264 (custom-save-all))
2265
2266;;;###autoload
2041(defun custom-save-all () 2267(defun custom-save-all ()
2042 "Save all customizations in `custom-file'." 2268 "Save all customizations in `custom-file'."
2043 (custom-save-variables) 2269 (custom-save-variables)
@@ -2178,7 +2404,7 @@ The format is suitable for use with `easy-menu-define'."
2178 2404
2179(easy-menu-define custom-mode-customize-menu 2405(easy-menu-define custom-mode-customize-menu
2180 custom-mode-map 2406 custom-mode-map
2181 "Menu used in customization buffers." 2407 "Menu used to customize customization buffers."
2182 (customize-menu-create 'customize)) 2408 (customize-menu-create 'customize))
2183 2409
2184(easy-menu-define custom-mode-menu 2410(easy-menu-define custom-mode-menu
diff --git a/lisp/custom.el b/lisp/custom.el
index afa5b20ca21..58cc6e3468c 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -4,7 +4,7 @@
4;; 4;;
5;; Author: Per Abrahamsen <abraham@dina.kvl.dk> 5;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6;; Keywords: help, faces 6;; Keywords: help, faces
7;; Version: 1.84 7;; Version: 1.90
8;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ 8;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
9 9
10;; This file is part of GNU Emacs. 10;; This file is part of GNU Emacs.
@@ -38,7 +38,9 @@
38 38
39(require 'widget) 39(require 'widget)
40 40
41(define-widget-keywords :prefix :tag :load :link :options :type :group) 41(define-widget-keywords :initialize :set :get :require :prefix :tag
42 :load :link :options :type :group)
43
42 44
43(defvar custom-define-hook nil 45(defvar custom-define-hook nil
44 ;; Customize information for this option is in `cus-edit.el'. 46 ;; Customize information for this option is in `cus-edit.el'.
@@ -46,14 +48,62 @@
46 48
47;;; The `defcustom' Macro. 49;;; The `defcustom' Macro.
48 50
49(defun custom-declare-variable (symbol value doc &rest args) 51(defun custom-initialize-default (symbol value)
50 "Like `defcustom', but SYMBOL and VALUE are evaluated as normal arguments." 52 "Initialize SYMBOL with VALUE.
51 ;; Bind this variable unless it already is bound. 53This will do nothing if symbol already has a default binding.
54Otherwise, if symbol has a `saved-value' property, it will evaluate
55the car of that and used as the default binding for symbol.
56Otherwise, VALUE will be evaluated and used as the default binding for
57symbol."
52 (unless (default-boundp symbol) 58 (unless (default-boundp symbol)
53 ;; Use the saved value if it exists, otherwise the factory setting. 59 ;; Use the saved value if it exists, otherwise the factory setting.
54 (set-default symbol (if (get symbol 'saved-value) 60 (set-default symbol (if (get symbol 'saved-value)
55 (eval (car (get symbol 'saved-value))) 61 (eval (car (get symbol 'saved-value)))
56 (eval value)))) 62 (eval value)))))
63
64(defun custom-initialize-set (symbol value)
65 "Initialize SYMBOL with VALUE.
66Like `custom-initialize-default', but use the function specified by
67`:set' to initialize SYMBOL."
68 (unless (default-boundp symbol)
69 (funcall (or (get symbol 'custom-set) 'set-default)
70 symbol
71 (if (get symbol 'saved-value)
72 (eval (car (get symbol 'saved-value)))
73 (eval value)))))
74
75(defun custom-initialize-reset (symbol value)
76 "Initialize SYMBOL with VALUE.
77Like `custom-initialize-set', but use the function specified by
78`:get' to reinitialize SYMBOL if it is already bound."
79 (funcall (or (get symbol 'custom-set) 'set-default)
80 symbol
81 (cond ((default-boundp symbol)
82 (funcall (or (get symbol 'custom-get) 'default-value)
83 symbol))
84 ((get symbol 'saved-value)
85 (eval (car (get symbol 'saved-value))))
86 (t
87 (eval value)))))
88
89(defun custom-initialize-changed (symbol value)
90 "Initialize SYMBOL with VALUE.
91Like `custom-initialize-reset', but only use the `:set' function if the
92not using the factory setting. Otherwise, use the `set-default'."
93 (cond ((default-boundp symbol)
94 (funcall (or (get symbol 'custom-set) 'set-default)
95 symbol
96 (funcall (or (get symbol 'custom-get) 'default-value)
97 symbol)))
98 ((get symbol 'saved-value)
99 (funcall (or (get symbol 'custom-set) 'set-default)
100 symbol
101 (eval (car (get symbol 'saved-value)))))
102 (t
103 (set-default symbol (eval value)))))
104
105(defun custom-declare-variable (symbol value doc &rest args)
106 "Like `defcustom', but SYMBOL and VALUE are evaluated as normal arguments."
57 ;; Remember the factory setting. 107 ;; Remember the factory setting.
58 (put symbol 'factory-value (list value)) 108 (put symbol 'factory-value (list value))
59 ;; Maybe this option was rogue in an earlier version. It no longer is. 109 ;; Maybe this option was rogue in an earlier version. It no longer is.
@@ -62,29 +112,42 @@
62 (put symbol 'force-value nil)) 112 (put symbol 'force-value nil))
63 (when doc 113 (when doc
64 (put symbol 'variable-documentation doc)) 114 (put symbol 'variable-documentation doc))
65 (while args 115 (let ((initialize 'custom-initialize-set)
66 (let ((arg (car args))) 116 (requests nil))
67 (setq args (cdr args)) 117 (while args
68 (unless (symbolp arg) 118 (let ((arg (car args)))
69 (error "Junk in args %S" args))
70 (let ((keyword arg)
71 (value (car args)))
72 (unless args
73 (error "Keyword %s is missing an argument" keyword))
74 (setq args (cdr args)) 119 (setq args (cdr args))
75 (cond ((eq keyword :type) 120 (unless (symbolp arg)
76 (put symbol 'custom-type value)) 121 (error "Junk in args %S" args))
77 ((eq keyword :options) 122 (let ((keyword arg)
78 (if (get symbol 'custom-options) 123 (value (car args)))
79 ;; Slow safe code to avoid duplicates. 124 (unless args
80 (mapcar (lambda (option) 125 (error "Keyword %s is missing an argument" keyword))
81 (custom-add-option symbol option)) 126 (setq args (cdr args))
82 value) 127 (cond ((eq keyword :initialize)
83 ;; Fast code for the common case. 128 (setq initialize value))
84 (put symbol 'custom-options (copy-sequence value)))) 129 ((eq keyword :set)
85 (t 130 (put symbol 'custom-set value))
86 (custom-handle-keyword symbol keyword value 131 ((eq keyword :get)
87 'custom-variable)))))) 132 (put symbol 'custom-get value))
133 ((eq keyword :require)
134 (push value requests))
135 ((eq keyword :type)
136 (put symbol 'custom-type value))
137 ((eq keyword :options)
138 (if (get symbol 'custom-options)
139 ;; Slow safe code to avoid duplicates.
140 (mapcar (lambda (option)
141 (custom-add-option symbol option))
142 value)
143 ;; Fast code for the common case.
144 (put symbol 'custom-options (copy-sequence value))))
145 (t
146 (custom-handle-keyword symbol keyword value
147 'custom-variable))))))
148 (put symbol 'custom-requests requests)
149 ;; Do the actual initialization.
150 (funcall initialize symbol value))
88 (run-hooks 'custom-define-hook) 151 (run-hooks 'custom-define-hook)
89 symbol) 152 symbol)
90 153
@@ -100,10 +163,25 @@ The remaining arguments should have the form
100 163
101The following KEYWORD's are defined: 164The following KEYWORD's are defined:
102 165
103:type VALUE should be a widget type. 166:type VALUE should be a widget type for editing the symbols value.
167 The default is `sexp'.
104:options VALUE should be a list of valid members of the widget type. 168:options VALUE should be a list of valid members of the widget type.
105:group VALUE should be a customization group. 169:group VALUE should be a customization group.
106 Add SYMBOL to that group. 170 Add SYMBOL to that group.
171:initialize VALUE should be a function used to initialize the
172 variable. It takes two arguments, the symbol and value
173 given in the `defcustom' call. The default is
174 `custom-initialize-default'
175:set VALUE should be a function to set the value of the symbol.
176 It takes two arguments, the symbol to set and the value to
177 give it. The default is `set-default'.
178:get VALUE should be a function to extract the value of symbol.
179 The function takes one argument, a symbol, and should return
180 the current value for that symbol. The default is
181 `default-value'.
182:require VALUE should be a feature symbol. Each feature will be
183 required after initialization, of the the user have saved this
184 option.
107 185
108Read the section about customization in the Emacs Lisp manual for more 186Read the section about customization in the Emacs Lisp manual for more
109information." 187information."
@@ -163,6 +241,9 @@ information."
163 241
164(defun custom-declare-group (symbol members doc &rest args) 242(defun custom-declare-group (symbol members doc &rest args)
165 "Like `defgroup', but SYMBOL is evaluated as a normal argument." 243 "Like `defgroup', but SYMBOL is evaluated as a normal argument."
244 (while members
245 (apply 'custom-add-to-group symbol (car members))
246 (setq members (cdr members)))
166 (put symbol 'custom-group (nconc members (get symbol 'custom-group))) 247 (put symbol 'custom-group (nconc members (get symbol 'custom-group)))
167 (when doc 248 (when doc
168 (put symbol 'group-documentation doc)) 249 (put symbol 'group-documentation doc))
@@ -285,17 +366,22 @@ the default value for the SYMBOL."
285 (while args 366 (while args
286 (let ((entry (car args))) 367 (let ((entry (car args)))
287 (if (listp entry) 368 (if (listp entry)
288 (let ((symbol (nth 0 entry)) 369 (let* ((symbol (nth 0 entry))
289 (value (nth 1 entry)) 370 (value (nth 1 entry))
290 (now (nth 2 entry))) 371 (now (nth 2 entry))
372 (requests (nth 3 entry))
373 (set (or (get symbol 'custom-set) 'set-default)))
291 (put symbol 'saved-value (list value)) 374 (put symbol 'saved-value (list value))
292 (cond (now 375 (cond (now
293 ;; Rogue variable, set it now. 376 ;; Rogue variable, set it now.
294 (put symbol 'force-value t) 377 (put symbol 'force-value t)
295 (set-default symbol (eval value))) 378 (funcall set symbol (eval value)))
296 ((default-boundp symbol) 379 ((default-boundp symbol)
297 ;; Something already set this, overwrite it. 380 ;; Something already set this, overwrite it.
298 (set-default symbol (eval value)))) 381 (funcall set symbol (eval value))))
382 (when requests
383 (put symbol 'custom-requests requests)
384 (mapcar 'require requests))
299 (setq args (cdr args))) 385 (setq args (cdr args)))
300 ;; Old format, a plist of SYMBOL VALUE pairs. 386 ;; Old format, a plist of SYMBOL VALUE pairs.
301 (message "Warning: old format `custom-set-variables'") 387 (message "Warning: old format `custom-set-variables'")
diff --git a/lisp/wid-browse.el b/lisp/wid-browse.el
index f656a3b9020..984d802f75b 100644
--- a/lisp/wid-browse.el
+++ b/lisp/wid-browse.el
@@ -4,7 +4,7 @@
4;; 4;;
5;; Author: Per Abrahamsen <abraham@dina.kvl.dk> 5;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6;; Keywords: extensions 6;; Keywords: extensions
7;; Version: 1.84 7;; Version: 1.90
8;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ 8;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
9 9
10;;; Commentary: 10;;; Commentary:
@@ -16,7 +16,7 @@
16(require 'easymenu) 16(require 'easymenu)
17(require 'custom) 17(require 'custom)
18(require 'wid-edit) 18(require 'wid-edit)
19(require 'cl) 19(eval-when-compile (require 'cl))
20 20
21(defgroup widget-browse nil 21(defgroup widget-browse nil
22 "Customization support for browsing widgets." 22 "Customization support for browsing widgets."
@@ -245,6 +245,37 @@ VALUE is assumed to be a list of widgets."
245(put :button 'widget-keyword-printer 'widget-browse-widget) 245(put :button 'widget-keyword-printer 'widget-browse-widget)
246(put :args 'widget-keyword-printer 'widget-browse-sexps) 246(put :args 'widget-keyword-printer 'widget-browse-sexps)
247 247
248;;; Widget Minor Mode.
249
250(defvar widget-minor-mode nil
251 "I non-nil, we are in Widget Minor Mode.")
252 (make-variable-buffer-local 'widget-minor-mode)
253
254(defvar widget-minor-mode-map nil
255 "Keymap used in Widget Minor Mode.")
256
257(unless widget-minor-mode-map
258 (setq widget-minor-mode-map (make-sparse-keymap))
259 (set-keymap-parent widget-minor-mode-map widget-keymap))
260
261;;;###autoload
262(defun widget-minor-mode (&optional arg)
263 "Togle minor mode for traversing widgets.
264With arg, turn widget mode on if and only if arg is positive."
265 (interactive "P")
266 (cond ((null arg)
267 (setq widget-minor-mode (not widget-minor-mode)))
268 ((<= 0 arg)
269 (setq widget-minor-mode nil))
270 (t
271 (setq widget-minor-mode t)))
272 (force-mode-line-update))
273
274(add-to-list 'minor-mode-alist '(widget-minor-mode " Widget"))
275
276(add-to-list 'minor-mode-map-alist
277 (cons 'widget-minor-mode widget-minor-mode-map))
278
248;;; The End: 279;;; The End:
249 280
250(provide 'wid-browse) 281(provide 'wid-browse)
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index 62b0274676d..555ab181f1a 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -4,7 +4,7 @@
4;; 4;;
5;; Author: Per Abrahamsen <abraham@dina.kvl.dk> 5;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6;; Keywords: extensions 6;; Keywords: extensions
7;; Version: 1.84 7;; Version: 1.90
8;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ 8;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
9 9
10;; This file is part of GNU Emacs. 10;; This file is part of GNU Emacs.
@@ -32,8 +32,7 @@
32 32
33(require 'widget) 33(require 'widget)
34 34
35(eval-when-compile 35(eval-when-compile (require 'cl))
36 (require 'cl))
37 36
38;;; Compatibility. 37;;; Compatibility.
39 38
@@ -75,7 +74,7 @@ and `end-open' if it should sticky to the front."
75 ;; We have the old custom-library, hack around it! 74 ;; We have the old custom-library, hack around it!
76 (defmacro defgroup (&rest args) nil) 75 (defmacro defgroup (&rest args) nil)
77 (defmacro defcustom (var value doc &rest args) 76 (defmacro defcustom (var value doc &rest args)
78 `(defvar ,var ,value ,doc)) 77 (` (defvar (, var) (, value) (, doc))))
79 (defmacro defface (&rest args) nil) 78 (defmacro defface (&rest args) nil)
80 (define-widget-keywords :prefix :tag :load :link :options :type :group) 79 (define-widget-keywords :prefix :tag :load :link :options :type :group)
81 (when (fboundp 'copy-face) 80 (when (fboundp 'copy-face)
@@ -134,7 +133,7 @@ into the buffer visible in the event's window."
134 133
135(defface widget-field-face '((((class grayscale color) 134(defface widget-field-face '((((class grayscale color)
136 (background light)) 135 (background light))
137 (:background "light gray")) 136 (:background "gray85"))
138 (((class grayscale color) 137 (((class grayscale color)
139 (background dark)) 138 (background dark))
140 (:background "dark gray")) 139 (:background "dark gray"))
@@ -184,7 +183,9 @@ Larger menus are read through the minibuffer."
184 "Choose an item from a list. 183 "Choose an item from a list.
185 184
186First argument TITLE is the name of the list. 185First argument TITLE is the name of the list.
187Second argument ITEMS is an alist (NAME . VALUE). 186Second argument ITEMS is an list whose members are either
187 (NAME . VALUE), to indicate selectable items, or just strings to
188 indicate unselectable items.
188Optional third argument EVENT is an input event. 189Optional third argument EVENT is an input event.
189 190
190The user is asked to choose between each NAME from the items alist, 191The user is asked to choose between each NAME from the items alist,
@@ -205,7 +206,9 @@ minibuffer."
205 (mapcar 206 (mapcar
206 (function 207 (function
207 (lambda (x) 208 (lambda (x)
208 (vector (car x) (list (car x)) t))) 209 (if (stringp x)
210 (vector x nil nil)
211 (vector (car x) (list (car x)) t))))
209 items))))) 212 items)))))
210 (setq val (and val 213 (setq val (and val
211 (listp (event-object val)) 214 (listp (event-object val))
@@ -213,6 +216,7 @@ minibuffer."
213 (car (event-object val)))) 216 (car (event-object val))))
214 (cdr (assoc val items)))) 217 (cdr (assoc val items))))
215 (t 218 (t
219 (setq items (remove-if 'stringp items))
216 (let ((val (completing-read (concat title ": ") items nil t))) 220 (let ((val (completing-read (concat title ": ") items nil t)))
217 (if (stringp val) 221 (if (stringp val)
218 (let ((try (try-completion val items))) 222 (let ((try (try-completion val items)))
@@ -235,6 +239,22 @@ This is only meaningful for radio buttons or checkboxes in a list."
235 (throw 'child child))) 239 (throw 'child child)))
236 nil))) 240 nil)))
237 241
242;;; Helper functions.
243;;
244;; These are widget specific.
245
246;;;###autoload
247(defun widget-prompt-value (widget prompt &optional value unbound)
248 "Prompt for a value matching WIDGET, using PROMPT.
249The current value is assumed to be VALUE, unless UNBOUND is non-nil."
250 (unless (listp widget)
251 (setq widget (list widget)))
252 (setq widget (widget-convert widget))
253 (let ((answer (widget-apply widget :prompt-value prompt value unbound)))
254 (unless (widget-apply widget :match answer)
255 (error "Value does not match %S type." (car widget)))
256 answer))
257
238;;; Widget text specifications. 258;;; Widget text specifications.
239;; 259;;
240;; These functions are for specifying text properties. 260;; These functions are for specifying text properties.
@@ -388,7 +408,8 @@ This is only meaningful for radio buttons or checkboxes in a list."
388 408
389(defmacro widget-specify-insert (&rest form) 409(defmacro widget-specify-insert (&rest form)
390 ;; Execute FORM without inheriting any text properties. 410 ;; Execute FORM without inheriting any text properties.
391 `(save-restriction 411 (`
412 (save-restriction
392 (let ((inhibit-read-only t) 413 (let ((inhibit-read-only t)
393 result 414 result
394 after-change-functions) 415 after-change-functions)
@@ -396,11 +417,11 @@ This is only meaningful for radio buttons or checkboxes in a list."
396 (narrow-to-region (- (point) 2) (point)) 417 (narrow-to-region (- (point) 2) (point))
397 (widget-specify-none (point-min) (point-max)) 418 (widget-specify-none (point-min) (point-max))
398 (goto-char (1+ (point-min))) 419 (goto-char (1+ (point-min)))
399 (setq result (progn ,@form)) 420 (setq result (progn (,@ form)))
400 (delete-region (point-min) (1+ (point-min))) 421 (delete-region (point-min) (1+ (point-min)))
401 (delete-region (1- (point-max)) (point-max)) 422 (delete-region (1- (point-max)) (point-max))
402 (goto-char (point-max)) 423 (goto-char (point-max))
403 result))) 424 result))))
404 425
405(defface widget-inactive-face '((((class grayscale color) 426(defface widget-inactive-face '((((class grayscale color)
406 (background dark)) 427 (background dark))
@@ -418,7 +439,8 @@ This is only meaningful for radio buttons or checkboxes in a list."
418 (unless (widget-get widget :inactive) 439 (unless (widget-get widget :inactive)
419 (let ((overlay (make-overlay from to nil t nil))) 440 (let ((overlay (make-overlay from to nil t nil)))
420 (overlay-put overlay 'face 'widget-inactive-face) 441 (overlay-put overlay 'face 'widget-inactive-face)
421 (overlay-put overlay 'evaporate 't) 442 (overlay-put overlay 'evaporate t)
443 (overlay-put overlay 'priority 100)
422 (overlay-put overlay (if (string-match "XEmacs" emacs-version) 444 (overlay-put overlay (if (string-match "XEmacs" emacs-version)
423 'read-only 445 'read-only
424 'modification-hooks) '(widget-overlay-inactive)) 446 'modification-hooks) '(widget-overlay-inactive))
@@ -503,7 +525,7 @@ ARGS are passed as extra arguments to the function."
503 (if (widget-apply widget :active) 525 (if (widget-apply widget :active)
504 (widget-apply widget :action event) 526 (widget-apply widget :action event)
505 (error "Attempt to perform action on inactive widget"))) 527 (error "Attempt to perform action on inactive widget")))
506 528
507;;; Glyphs. 529;;; Glyphs.
508 530
509(defcustom widget-glyph-directory (concat data-directory "custom/") 531(defcustom widget-glyph-directory (concat data-directory "custom/")
@@ -800,8 +822,9 @@ ARG may be negative to move backward."
800 (t 822 (t
801 (error "No buttons or fields found")))))) 823 (error "No buttons or fields found"))))))
802 (setq button (widget-at (point))) 824 (setq button (widget-at (point)))
803 (if (and button (widget-get button :tab-order) 825 (if (or (and button (widget-get button :tab-order)
804 (< (widget-get button :tab-order) 0)) 826 (< (widget-get button :tab-order) 0))
827 (and button (not (widget-apply button :active))))
805 (setq arg (1+ arg)))))) 828 (setq arg (1+ arg))))))
806 (while (< arg 0) 829 (while (< arg 0)
807 (if (= (point-min) (point)) 830 (if (= (point-min) (point))
@@ -838,8 +861,9 @@ ARG may be negative to move backward."
838 (button (goto-char button)) 861 (button (goto-char button))
839 (field (goto-char field))) 862 (field (goto-char field)))
840 (setq button (widget-at (point))) 863 (setq button (widget-at (point)))
841 (if (and button (widget-get button :tab-order) 864 (if (or (and button (widget-get button :tab-order)
842 (< (widget-get button :tab-order) 0)) 865 (< (widget-get button :tab-order) 0))
866 (and button (not (widget-apply button :active))))
843 (setq arg (1- arg))))) 867 (setq arg (1- arg)))))
844 (widget-echo-help (point)) 868 (widget-echo-help (point))
845 (run-hooks 'widget-move-hook)) 869 (run-hooks 'widget-move-hook))
@@ -1016,7 +1040,8 @@ With optional ARG, move across that many fields."
1016 :activate 'widget-specify-active 1040 :activate 'widget-specify-active
1017 :deactivate 'widget-default-deactivate 1041 :deactivate 'widget-default-deactivate
1018 :action 'widget-default-action 1042 :action 'widget-default-action
1019 :notify 'widget-default-notify) 1043 :notify 'widget-default-notify
1044 :prompt-value 'widget-default-prompt-value)
1020 1045
1021(defun widget-default-create (widget) 1046(defun widget-default-create (widget)
1022 "Create WIDGET at point in the current buffer." 1047 "Create WIDGET at point in the current buffer."
@@ -1087,7 +1112,8 @@ With optional ARG, move across that many fields."
1087 (set-marker-insertion-type from t) 1112 (set-marker-insertion-type from t)
1088 (set-marker-insertion-type to nil) 1113 (set-marker-insertion-type to nil)
1089 (widget-put widget :from from) 1114 (widget-put widget :from from)
1090 (widget-put widget :to to)))) 1115 (widget-put widget :to to)))
1116 (widget-clear-undo))
1091 1117
1092(defun widget-default-format-handler (widget escape) 1118(defun widget-default-format-handler (widget escape)
1093 ;; We recognize the %h escape by default. 1119 ;; We recognize the %h escape by default.
@@ -1149,7 +1175,8 @@ With optional ARG, move across that many fields."
1149 ;; Kludge: this doesn't need to be true for empty formats. 1175 ;; Kludge: this doesn't need to be true for empty formats.
1150 (delete-region from to)) 1176 (delete-region from to))
1151 (set-marker from nil) 1177 (set-marker from nil)
1152 (set-marker to nil))) 1178 (set-marker to nil))
1179 (widget-clear-undo))
1153 1180
1154(defun widget-default-value-set (widget value) 1181(defun widget-default-value-set (widget value)
1155 ;; Recreate widget with new value. 1182 ;; Recreate widget with new value.
@@ -1194,6 +1221,14 @@ With optional ARG, move across that many fields."
1194 ;; Pass notification to parent. 1221 ;; Pass notification to parent.
1195 (widget-default-action widget event)) 1222 (widget-default-action widget event))
1196 1223
1224(defun widget-default-prompt-value (widget prompt value unbound)
1225 ;; Read an arbitrary value. Stolen from `set-variable'.
1226;; (let ((initial (if unbound
1227;; nil
1228;; ;; It would be nice if we could do a `(cons val 1)' here.
1229;; (prin1-to-string (custom-quote value))))))
1230 (eval-minibuffer prompt ))
1231
1197;;; The `item' Widget. 1232;;; The `item' Widget.
1198 1233
1199(define-widget 'item 'default 1234(define-widget 'item 'default
@@ -1297,7 +1332,17 @@ With optional ARG, move across that many fields."
1297 1332
1298(defun widget-info-link-action (widget &optional event) 1333(defun widget-info-link-action (widget &optional event)
1299 "Open the info node specified by WIDGET." 1334 "Open the info node specified by WIDGET."
1300 (Info-goto-node (widget-value widget))) 1335 (Info-goto-node (widget-value widget))
1336 ;; Steal button release event.
1337 (if (and (fboundp 'button-press-event-p)
1338 (fboundp 'next-command-event))
1339 ;; XEmacs
1340 (and event
1341 (button-press-event-p event)
1342 (next-command-event))
1343 ;; Emacs
1344 (when (memq 'down (event-modifiers event))
1345 (read-event))))
1301 1346
1302;;; The `url-link' Widget. 1347;;; The `url-link' Widget.
1303 1348
@@ -1507,11 +1552,8 @@ With optional ARG, move across that many fields."
1507 (widget-value-set widget 1552 (widget-value-set widget
1508 (widget-apply current :value-to-external 1553 (widget-apply current :value-to-external
1509 (widget-get current :value))) 1554 (widget-get current :value)))
1510 (widget-apply widget :notify widget event) 1555 (widget-apply widget :notify widget event)
1511 (widget-setup))) 1556 (widget-setup))))
1512 ;; Notify parent.
1513 (widget-apply widget :notify widget event)
1514 (widget-clear-undo))
1515 1557
1516(defun widget-choice-validate (widget) 1558(defun widget-choice-validate (widget)
1517 ;; Valid if we have made a valid choice. 1559 ;; Valid if we have made a valid choice.
@@ -1567,7 +1609,7 @@ With optional ARG, move across that many fields."
1567 ;; Toggle value. 1609 ;; Toggle value.
1568 (widget-value-set widget (not (widget-value widget))) 1610 (widget-value-set widget (not (widget-value widget)))
1569 (widget-apply widget :notify widget event)) 1611 (widget-apply widget :notify widget event))
1570 1612
1571;;; The `checkbox' Widget. 1613;;; The `checkbox' Widget.
1572 1614
1573(define-widget 'checkbox 'toggle 1615(define-widget 'checkbox 'toggle
@@ -2222,9 +2264,14 @@ With optional ARG, move across that many fields."
2222 2264
2223(define-widget 'const 'item 2265(define-widget 'const 'item
2224 "An immutable sexp." 2266 "An immutable sexp."
2267 :prompt-value 'widget-const-prompt-value
2225 :format "%t\n%d") 2268 :format "%t\n%d")
2226 2269
2227(define-widget 'function-item 'item 2270(defun widget-const-prompt-value (widget prompt value unbound)
2271 ;; Return the value of the const.
2272 (widget-value widget))
2273
2274(define-widget 'function-item 'const
2228 "An immutable function name." 2275 "An immutable function name."
2229 :format "%v\n%h" 2276 :format "%v\n%h"
2230 :documentation-property (lambda (symbol) 2277 :documentation-property (lambda (symbol)
@@ -2232,28 +2279,67 @@ With optional ARG, move across that many fields."
2232 (documentation symbol t) 2279 (documentation symbol t)
2233 (error nil)))) 2280 (error nil))))
2234 2281
2235(define-widget 'variable-item 'item 2282(define-widget 'variable-item 'const
2236 "An immutable variable name." 2283 "An immutable variable name."
2237 :format "%v\n%h" 2284 :format "%v\n%h"
2238 :documentation-property 'variable-documentation) 2285 :documentation-property 'variable-documentation)
2239 2286
2240(define-widget 'string 'editable-field 2287(define-widget 'string 'editable-field
2241 "A string" 2288 "A string"
2289 :prompt-value 'widget-string-prompt-value
2242 :tag "String" 2290 :tag "String"
2243 :format "%[%t%]: %v") 2291 :format "%[%t%]: %v")
2244 2292
2293(defvar widget-string-prompt-value-history nil
2294 "History of input to `widget-string-prompt-value'.")
2295
2296(defun widget-string-prompt-value (widget prompt value unbound)
2297 ;; Read a string.
2298 (read-string prompt (if unbound nil (cons value 1))
2299 'widget-string-prompt-value-history))
2300
2245(define-widget 'regexp 'string 2301(define-widget 'regexp 'string
2246 "A regular expression." 2302 "A regular expression."
2247 ;; Should do validation. 2303 :match 'widget-regexp-match
2304 :validate 'widget-regexp-validate
2248 :tag "Regexp") 2305 :tag "Regexp")
2249 2306
2307(defun widget-regexp-match (widget value)
2308 ;; Match valid regexps.
2309 (and (stringp value)
2310 (condition-case data
2311 (prog1 t
2312 (string-match value ""))
2313 (error nil))))
2314
2315(defun widget-regexp-validate (widget)
2316 "Check that the value of WIDGET is a valid regexp."
2317 (let ((val (widget-value widget)))
2318 (condition-case data
2319 (prog1 nil
2320 (string-match val ""))
2321 (error (widget-put widget :error (error-message-string data))
2322 widget))))
2323
2250(define-widget 'file 'string 2324(define-widget 'file 'string
2251 "A file widget. 2325 "A file widget.
2252It will read a file name from the minibuffer when activated." 2326It will read a file name from the minibuffer when activated."
2327 :prompt-value 'widget-file-prompt-value
2253 :format "%[%t%]: %v" 2328 :format "%[%t%]: %v"
2254 :tag "File" 2329 :tag "File"
2255 :action 'widget-file-action) 2330 :action 'widget-file-action)
2256 2331
2332(defun widget-file-prompt-value (widget prompt value unbound)
2333 ;; Read file from minibuffer.
2334 (abbreviate-file-name
2335 (if unbound
2336 (read-file-name prompt)
2337 (let ((prompt2 (concat prompt "(default `" value "') "))
2338 (dir (file-name-directory value))
2339 (file (file-name-nondirectory value))
2340 (must-match (widget-get widget :must-match)))
2341 (read-file-name prompt2 dir nil must-match file)))))
2342
2257(defun widget-file-action (widget &optional event) 2343(defun widget-file-action (widget &optional event)
2258 ;; Read a file name from the minibuffer. 2344 ;; Read a file name from the minibuffer.
2259 (let* ((value (widget-value widget)) 2345 (let* ((value (widget-value widget))
@@ -2303,7 +2389,8 @@ It will read a directory name from the minibuffer when activated."
2303 :validate 'widget-sexp-validate 2389 :validate 'widget-sexp-validate
2304 :match (lambda (widget value) t) 2390 :match (lambda (widget value) t)
2305 :value-to-internal 'widget-sexp-value-to-internal 2391 :value-to-internal 'widget-sexp-value-to-internal
2306 :value-to-external (lambda (widget value) (read value))) 2392 :value-to-external (lambda (widget value) (read value))
2393 :prompt-value 'widget-sexp-prompt-value)
2307 2394
2308(defun widget-sexp-value-to-internal (widget value) 2395(defun widget-sexp-value-to-internal (widget value)
2309 ;; Use pp for printer representation. 2396 ;; Use pp for printer representation.
@@ -2337,6 +2424,24 @@ It will read a directory name from the minibuffer when activated."
2337 (error (widget-put widget :error (error-message-string data)) 2424 (error (widget-put widget :error (error-message-string data))
2338 widget))))) 2425 widget)))))
2339 2426
2427(defvar widget-sexp-prompt-value-history nil
2428 "History of input to `widget-sexp-prompt-value'.")
2429
2430(defun widget-sexp-prompt-value (widget prompt value unbound)
2431 ;; Read an arbitrary sexp.
2432 (let ((found (read-string prompt
2433 (if unbound nil (cons (prin1-to-string value) 1))
2434 'widget-sexp-prompt-value)))
2435 (let ((buffer (set-buffer (get-buffer-create " *Widget Scratch*"))))
2436 (erase-buffer)
2437 (insert found)
2438 (goto-char (point-min))
2439 (let ((answer (read buffer)))
2440 (unless (eobp)
2441 (error "Junk at end of expression: %s"
2442 (buffer-substring (point) (point-max))))
2443 answer))))
2444
2340(define-widget 'integer 'sexp 2445(define-widget 'integer 'sexp
2341 "An integer." 2446 "An integer."
2342 :tag "Integer" 2447 :tag "Integer"
@@ -2354,7 +2459,8 @@ It will read a directory name from the minibuffer when activated."
2354 :value 0 2459 :value 0
2355 :size 1 2460 :size 1
2356 :format "%{%t%}: %v\n" 2461 :format "%{%t%}: %v\n"
2357 :type-error "This field should contain a character" 2462 :valid-regexp "\\`.\\'"
2463 :error "This field should contain a single character"
2358 :value-to-internal (lambda (widget value) 2464 :value-to-internal (lambda (widget value)
2359 (if (integerp value) 2465 (if (integerp value)
2360 (char-to-string value) 2466 (char-to-string value)
@@ -2432,8 +2538,20 @@ It will read a directory name from the minibuffer when activated."
2432(define-widget 'boolean 'toggle 2538(define-widget 'boolean 'toggle
2433 "To be nil or non-nil, that is the question." 2539 "To be nil or non-nil, that is the question."
2434 :tag "Boolean" 2540 :tag "Boolean"
2541 :prompt-value 'widget-boolean-prompt-value
2435 :format "%{%t%}: %[%v%]\n") 2542 :format "%{%t%}: %[%v%]\n")
2436 2543
2544(defun widget-boolean-prompt-value (widget prompt value unbound)
2545 ;; Toggle a boolean.
2546 (cond (unbound
2547 (y-or-n-p prompt))
2548 (value
2549 (message "Off")
2550 nil)
2551 (t
2552 (message "On")
2553 t)))
2554
2437;;; The `color' Widget. 2555;;; The `color' Widget.
2438 2556
2439(define-widget 'color-item 'choice-item 2557(define-widget 'color-item 'choice-item
diff --git a/lisp/widget.el b/lisp/widget.el
index e4ee2ffd584..4905c06b70a 100644
--- a/lisp/widget.el
+++ b/lisp/widget.el
@@ -4,7 +4,7 @@
4;; 4;;
5;; Author: Per Abrahamsen <abraham@dina.kvl.dk> 5;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6;; Keywords: help, extensions, faces, hypermedia 6;; Keywords: help, extensions, faces, hypermedia
7;; Version: 1.84 7;; Version: 1.90
8;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ 8;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
9 9
10;; This file is part of GNU Emacs. 10;; This file is part of GNU Emacs.
@@ -44,8 +44,8 @@
44 (set (car keywords) (car keywords))) 44 (set (car keywords) (car keywords)))
45 (setq keywords (cdr keywords))))))) 45 (setq keywords (cdr keywords)))))))
46 46
47(define-widget-keywords :text-format :deactivate :active :inactive 47(define-widget-keywords :prompt-value :text-format :deactivate :active
48 :activate :sibling-args :delete-button-args 48 :inactive :activate :sibling-args :delete-button-args
49 :insert-button-args :append-button-args :button-args 49 :insert-button-args :append-button-args :button-args
50 :tag-glyph :off-glyph :on-glyph :valid-regexp 50 :tag-glyph :off-glyph :on-glyph :valid-regexp
51 :secret :sample-face :sample-face-get :case-fold :widget-doc 51 :secret :sample-face :sample-face-get :case-fold :widget-doc
@@ -66,9 +66,11 @@
66 (autoload 'widget-apply "wid-edit") 66 (autoload 'widget-apply "wid-edit")
67 (autoload 'widget-create "wid-edit") 67 (autoload 'widget-create "wid-edit")
68 (autoload 'widget-insert "wid-edit") 68 (autoload 'widget-insert "wid-edit")
69 (autoload 'widget-prompt-value "wid-edit")
69 (autoload 'widget-browse "wid-browse" nil t) 70 (autoload 'widget-browse "wid-browse" nil t)
70 (autoload 'widget-browse-other-window "wid-browse" nil t) 71 (autoload 'widget-browse-other-window "wid-browse" nil t)
71 (autoload 'widget-browse-at "wid-browse" nil t)) 72 (autoload 'widget-browse-at "wid-browse" nil t)
73 (autoload 'widget-minor-mode "wid-browse" nil t))
72 74
73(defun define-widget (name class doc &rest args) 75(defun define-widget (name class doc &rest args)
74 "Define a new widget type named NAME from CLASS. 76 "Define a new widget type named NAME from CLASS.
@@ -85,7 +87,8 @@ create identical widgets:
85 87
86The third argument DOC is a documentation string for the widget." 88The third argument DOC is a documentation string for the widget."
87 (put name 'widget-type (cons class args)) 89 (put name 'widget-type (cons class args))
88 (put name 'widget-documentation doc)) 90 (put name 'widget-documentation doc)
91 name)
89 92
90;;; The End. 93;;; The End.
91 94