comparison lisp/gnus/custom-edit.el @ 16:0293115a14e9 r19-15b91

Import from CVS: tag r19-15b91
author cvs
date Mon, 13 Aug 2007 08:49:20 +0200
parents
children
comparison
equal deleted inserted replaced
15:ad457d5f7d04 16:0293115a14e9
1 ;;; custom-edit.el --- Tools for customization Emacs.
2 ;;
3 ;; Copyright (C) 1996 Free Software Foundation, Inc.
4 ;;
5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6 ;; Keywords: help, faces
7 ;; Version: 1.20
8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
9
10 ;;; Commentary:
11 ;;
12 ;; See `custom.el'.
13
14 ;;; Code:
15
16 (require 'custom)
17 (require 'widget-edit)
18 (require 'easymenu)
19
20 (define-widget-keywords :custom-prefixes :custom-menu :custom-show
21 :custom-magic :custom-state :custom-level :custom-form
22 :custom-set :custom-save :custom-reset-current :custom-reset-saved
23 :custom-reset-factory)
24
25 ;;; Utilities.
26
27 (defun custom-quote (sexp)
28 "Quote SEXP iff it is not self quoting."
29 (if (or (memq sexp '(t nil))
30 (and (symbolp sexp)
31 (eq (aref (symbol-name sexp) 0) ?:))
32 (and (listp sexp)
33 (memq (car sexp) '(lambda)))
34 (stringp sexp)
35 (numberp sexp)
36 (and (fboundp 'characterp)
37 (funcall (intern "characterp") sexp)))
38 sexp
39 (list 'quote sexp)))
40
41 (defun custom-split-regexp-maybe (regexp)
42 "If REGEXP is a string, split it to a list at `\\|'.
43 You can get the original back with from the result with:
44 (mapconcat 'identity result \"\\|\")
45
46 IF REGEXP is not a string, return it unchanged."
47 (if (stringp regexp)
48 (let ((start 0)
49 all)
50 (while (string-match "\\\\|" regexp start)
51 (setq all (cons (substring regexp start (match-beginning 0)) all)
52 start (match-end 0)))
53 (nreverse (cons (substring regexp start) all)))
54 regexp))
55
56 (defvar custom-prefix-list nil
57 "List of prefixes that should be ignored by `custom-unlispify'")
58
59 (defcustom custom-unlispify-menu-entries t
60 "Display menu entries as words instead of symbols if non nil."
61 :group 'customize
62 :type 'boolean)
63
64 (defun custom-unlispify-menu-entry (symbol &optional no-suffix)
65 "Convert symbol into a menu entry."
66 (cond ((not custom-unlispify-menu-entries)
67 (symbol-name symbol))
68 ((get symbol 'custom-tag)
69 (if no-suffix
70 (get symbol 'custom-tag)
71 (concat (get symbol 'custom-tag) "...")))
72 (t
73 (save-excursion
74 (set-buffer (get-buffer-create " *Custom-Work*"))
75 (erase-buffer)
76 (princ symbol (current-buffer))
77 (goto-char (point-min))
78 (let ((prefixes custom-prefix-list)
79 prefix)
80 (while prefixes
81 (setq prefix (car prefixes))
82 (if (search-forward prefix (+ (point) (length prefix)) t)
83 (progn
84 (setq prefixes nil)
85 (delete-region (point-min) (point)))
86 (setq prefixes (cdr prefixes)))))
87 (subst-char-in-region (point-min) (point-max) ?- ?\ t)
88 (capitalize-region (point-min) (point-max))
89 (unless no-suffix
90 (goto-char (point-max))
91 (insert "..."))
92 (buffer-string)))))
93
94 (defcustom custom-unlispify-tag-names t
95 "Display tag names as words instead of symbols if non nil."
96 :group 'customize
97 :type 'boolean)
98
99 (defun custom-unlispify-tag-name (symbol)
100 "Convert symbol into a menu entry."
101 (let ((custom-unlispify-menu-entries custom-unlispify-tag-names))
102 (custom-unlispify-menu-entry symbol t)))
103
104 (defun custom-prefix-add (symbol prefixes)
105 ;; Addd SYMBOL to list of ignored PREFIXES.
106 (cons (or (get symbol 'custom-prefix)
107 (concat (symbol-name symbol) "-"))
108 prefixes))
109
110 ;;; The Custom Mode.
111
112 (defvar custom-options nil
113 "Customization widgets in the current buffer.")
114
115 (defvar custom-mode-map nil
116 "Keymap for `custom-mode'.")
117
118 (unless custom-mode-map
119 (setq custom-mode-map (make-sparse-keymap))
120 (set-keymap-parent custom-mode-map widget-keymap))
121
122 (easy-menu-define custom-mode-menu
123 custom-mode-map
124 "Menu used in customization buffers."
125 '("Custom"
126 ["Set" custom-set t]
127 ["Save" custom-save t]
128 ["Reset to Current" custom-reset-current t]
129 ["Reset to Saved" custom-reset-saved t]
130 ["Reset to Factory Settings" custom-reset-factory t]
131 ["Info" (Info-goto-node "(custom)The Customization Buffer") t]))
132
133 (defcustom custom-mode-hook nil
134 "Hook called when entering custom-mode."
135 :type 'hook
136 :group 'customize)
137
138 (defun custom-mode ()
139 "Major mode for editing customization buffers.
140
141 The following commands are available:
142
143 \\[widget-forward] Move to next button or editable field.
144 \\[widget-backward] Move to previous button or editable field.
145 \\[widget-button-click] Activate button under the mouse pointer.
146 \\[widget-button-press] Activate button under point.
147 \\[custom-set] Set all modifications.
148 \\[custom-save] Make all modifications default.
149 \\[custom-reset-current] Reset all modified options.
150 \\[custom-reset-saved] Reset all modified or set options.
151 \\[custom-reset-factory] Reset all options.
152
153 Entry to this mode calls the value of `custom-mode-hook'
154 if that value is non-nil."
155 (kill-all-local-variables)
156 (setq major-mode 'custom-mode
157 mode-name "Custom")
158 (use-local-map custom-mode-map)
159 (make-local-variable 'custom-options)
160 (run-hooks 'custom-mode-hook))
161
162 ;;; Custom Mode Commands.
163
164 (defun custom-set ()
165 "Set changes in all modified options."
166 (interactive)
167 (let ((children custom-options))
168 (mapcar (lambda (child)
169 (when (eq (widget-get child :custom-state) 'modified)
170 (widget-apply child :custom-set)))
171 children)))
172
173 (defun custom-save ()
174 "Set all modified group members and save them."
175 (interactive)
176 (let ((children custom-options))
177 (mapcar (lambda (child)
178 (when (memq (widget-get child :custom-state) '(modified set))
179 (widget-apply child :custom-save)))
180 children))
181 (custom-save-all))
182
183 (defvar custom-reset-menu
184 '(("Current" . custom-reset-current)
185 ("Saved" . custom-reset-saved)
186 ("Factory Settings" . custom-reset-factory))
187 "Alist of actions for the `Reset' button.
188 The key is a string containing the name of the action, the value is a
189 lisp function taking the widget as an element which will be called
190 when the action is chosen.")
191
192 (defun custom-reset (event)
193 "Select item from reset menu."
194 (let* ((completion-ignore-case t)
195 (answer (widget-choose "Reset to"
196 custom-reset-menu
197 event)))
198 (if answer
199 (funcall answer))))
200
201 (defun custom-reset-current ()
202 "Reset all modified group members to their current value."
203 (interactive)
204 (let ((children custom-options))
205 (mapcar (lambda (child)
206 (when (eq (widget-get child :custom-state) 'modified)
207 (widget-apply child :custom-reset-current)))
208 children)))
209
210 (defun custom-reset-saved ()
211 "Reset all modified or set group members to their saved value."
212 (interactive)
213 (let ((children custom-options))
214 (mapcar (lambda (child)
215 (when (eq (widget-get child :custom-state) 'modified)
216 (widget-apply child :custom-reset-current)))
217 children)))
218
219 (defun custom-reset-factory ()
220 "Reset all modified, set, or saved group members to their factory settings."
221 (interactive)
222 (let ((children custom-options))
223 (mapcar (lambda (child)
224 (when (eq (widget-get child :custom-state) 'modified)
225 (widget-apply child :custom-reset-current)))
226 children)))
227
228 ;;; The Customize Commands
229
230 ;;;###autoload
231 (defun customize (symbol)
232 "Customize SYMBOL, which must be a customization group."
233 (interactive (list (completing-read "Customize group: (default emacs) "
234 obarray
235 (lambda (symbol)
236 (get symbol 'custom-group))
237 t)))
238
239 (when (stringp symbol)
240 (if (string-equal "" symbol)
241 (setq symbol 'emacs)
242 (setq symbol (intern symbol))))
243 (custom-buffer-create (list (list symbol 'custom-group))))
244
245 ;;;###autoload
246 (defun customize-variable (symbol)
247 "Customize SYMBOL, which must be a variable."
248 (interactive
249 ;; Code stolen from `help.el'.
250 (let ((v (variable-at-point))
251 (enable-recursive-minibuffers t)
252 val)
253 (setq val (completing-read
254 (if v
255 (format "Customize variable (default %s): " v)
256 "Customize variable: ")
257 obarray 'boundp t))
258 (list (if (equal val "")
259 v (intern val)))))
260 (custom-buffer-create (list (list symbol 'custom-variable))))
261
262 ;;;###autoload
263 (defun customize-face (symbol)
264 "Customize FACE."
265 (interactive (list (completing-read "Customize face: "
266 obarray 'custom-facep)))
267 (if (stringp symbol)
268 (setq symbol (intern symbol)))
269 (unless (symbolp symbol)
270 (error "Should be a symbol %S" symbol))
271 (custom-buffer-create (list (list symbol 'custom-face))))
272
273 ;;;###autoload
274 (defun customize-customized ()
275 "Customize all already customized user options."
276 (interactive)
277 (let ((found nil))
278 (mapatoms (lambda (symbol)
279 (and (get symbol 'saved-face)
280 (custom-facep symbol)
281 (setq found (cons (list symbol 'custom-face) found)))
282 (and (get symbol 'saved-value)
283 (boundp symbol)
284 (setq found
285 (cons (list symbol 'custom-variable) found)))))
286 (if found
287 (custom-buffer-create found)
288 (error "No customized user options"))))
289
290 ;;;###autoload
291 (defun customize-apropos (regexp &optional all)
292 "Customize all user options matching REGEXP.
293 If ALL (e.g., started with a prefix key), include options which are not
294 user-settable."
295 (interactive "sCustomize regexp: \nP")
296 (let ((found nil))
297 (mapatoms (lambda (symbol)
298 (when (string-match regexp (symbol-name symbol))
299 (when (get symbol 'custom-group)
300 (setq found (cons (list symbol 'custom-group) found)))
301 (when (custom-facep symbol)
302 (setq found (cons (list symbol 'custom-face) found)))
303 (when (and (boundp symbol)
304 (or (get symbol 'saved-value)
305 (get symbol 'factory-value)
306 (if all
307 (get symbol 'variable-documentation)
308 (user-variable-p symbol))))
309 (setq found
310 (cons (list symbol 'custom-variable) found))))))
311 (if found
312 (custom-buffer-create found)
313 (error "No matches"))))
314
315 ;;;###autoload
316 (defun custom-buffer-create (options)
317 "Create a buffer containing OPTIONS.
318 OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where
319 SYMBOL is a customization option, and WIDGET is a widget for editing
320 that option."
321 (kill-buffer (get-buffer-create "*Customization*"))
322 (switch-to-buffer (get-buffer-create "*Customization*"))
323 (custom-mode)
324 (widget-insert "This is a customization buffer.
325 Push RET or click mouse-2 on the word ")
326 (widget-create 'info-link
327 :tag "help"
328 :help-echo "Push me for help."
329 "(custom)The Customization Buffer")
330 (widget-insert " for more information.\n\n")
331 (setq custom-options
332 (mapcar (lambda (entry)
333 (prog1
334 (if (> (length options) 1)
335 (widget-create (nth 1 entry)
336 :tag (custom-unlispify-tag-name
337 (nth 0 entry))
338 :value (nth 0 entry))
339 ;; If there is only one entry, don't hide it!
340 (widget-create (nth 1 entry)
341 :custom-state 'unknown
342 :tag (custom-unlispify-tag-name
343 (nth 0 entry))
344 :value (nth 0 entry)))
345 (unless (eq (preceding-char) ?\n)
346 (widget-insert "\n"))
347 (widget-insert "\n")))
348 options))
349 (mapcar 'custom-magic-reset custom-options)
350 (widget-create 'push-button
351 :tag "Set"
352 :help-echo "Push me to set all modifications."
353 :action (lambda (widget &optional event)
354 (custom-set)))
355 (widget-insert " ")
356 (widget-create 'push-button
357 :tag "Save"
358 :help-echo "Push me to make the modifications default."
359 :action (lambda (widget &optional event)
360 (custom-save)))
361 (widget-insert " ")
362 (widget-create 'push-button
363 :tag "Reset"
364 :help-echo "Push me to undo all modifications.."
365 :action (lambda (widget &optional event)
366 (custom-reset event)))
367 (widget-insert "\n")
368 (widget-setup))
369
370 ;;; Modification of Basic Widgets.
371 ;;
372 ;; We add extra properties to the basic widgets needed here. This is
373 ;; fine, as long as we are careful to stay within out own namespace.
374 ;;
375 ;; We want simple widgets to be displayed by default, but complex
376 ;; widgets to be hidden.
377
378 (widget-put (get 'item 'widget-type) :custom-show t)
379 (widget-put (get 'editable-field 'widget-type)
380 :custom-show (lambda (widget value)
381 (let ((pp (pp-to-string value)))
382 (cond ((string-match "\n" pp)
383 nil)
384 ((> (length pp) 40)
385 nil)
386 (t t)))))
387 (widget-put (get 'menu-choice 'widget-type) :custom-show t)
388
389 ;;; The `custom-manual' Widget.
390
391 (define-widget 'custom-manual 'info-link
392 "Link to the manual entry for this customization option."
393 :help-echo "Push me to read the manual."
394 :tag "Manual")
395
396 ;;; The `custom-magic' Widget.
397
398 (defface custom-invalid-face '((((class color))
399 (:foreground "yellow" :background "red"))
400 (t
401 (:bold t :italic t :underline t)))
402 "Face used when the customize item is invalid.")
403
404 (defface custom-rogue-face '((((class color))
405 (:foreground "pink" :background "black"))
406 (t
407 (:underline t)))
408 "Face used when the customize item is not defined for customization.")
409
410 (defface custom-modified-face '((((class color))
411 (:foreground "white" :background "blue"))
412 (t
413 (:italic t :bold)))
414 "Face used when the customize item has been modified.")
415
416 (defface custom-set-face '((((class color))
417 (:foreground "blue" :background "white"))
418 (t
419 (:italic t)))
420 "Face used when the customize item has been set.")
421
422 (defface custom-changed-face '((((class color))
423 (:foreground "white" :background "blue"))
424 (t
425 (:italic t)))
426 "Face used when the customize item has been changed.")
427
428 (defface custom-saved-face '((t (:underline t)))
429 "Face used when the customize item has been saved.")
430
431 (defcustom custom-magic-alist '((nil "#" underline "\
432 uninitialized, you should not see this.")
433 (unknown "?" italic "\
434 unknown, you should not see this.")
435 (hidden "-" default "\
436 hidden, press the state button to show.")
437 (invalid "x" custom-invalid-face "\
438 the value displayed for this item is invalid and cannot be set.")
439 (modified "*" custom-modified-face "\
440 you have edited the item, and can now set it.")
441 (set "+" custom-set-face "\
442 you have set this item, but not saved it.")
443 (changed ":" custom-changed-face "\
444 this item has been changed outside customize.")
445 (saved "!" custom-saved-face "\
446 this item has been saved.")
447 (rogue "@" custom-rogue-face "\
448 this item is not prepared for customization.")
449 (factory " " nil "\
450 this item is unchanged from its factory setting."))
451 "Alist of customize option states.
452 Each entry is of the form (STATE MAGIC FACE DESCRIPTION), where
453
454 STATE is one of the following symbols:
455
456 `nil'
457 For internal use, should never occur.
458 `unknown'
459 For internal use, should never occur.
460 `hidden'
461 This item is not being displayed.
462 `invalid'
463 This item is modified, but has an invalid form.
464 `modified'
465 This item is modified, and has a valid form.
466 `set'
467 This item has been set but not saved.
468 `changed'
469 The current value of this item has been changed temporarily.
470 `saved'
471 This item is marked for saving.
472 `rogue'
473 This item has no customization information.
474 `factory'
475 This item is unchanged from the factory default.
476
477 MAGIC is a string used to present that state.
478
479 FACE is a face used to present the state.
480
481 DESCRIPTION is a string describing the state.
482
483 The list should be sorted most significant first."
484 :type '(list (checklist :inline t
485 (group (const nil)
486 (string :tag "Magic")
487 face
488 (string :tag "Description"))
489 (group (const unknown)
490 (string :tag "Magic")
491 face
492 (string :tag "Description"))
493 (group (const hidden)
494 (string :tag "Magic")
495 face
496 (string :tag "Description"))
497 (group (const invalid)
498 (string :tag "Magic")
499 face
500 (string :tag "Description"))
501 (group (const modified)
502 (string :tag "Magic")
503 face
504 (string :tag "Description"))
505 (group (const set)
506 (string :tag "Magic")
507 face
508 (string :tag "Description"))
509 (group (const changed)
510 (string :tag "Magic")
511 face
512 (string :tag "Description"))
513 (group (const saved)
514 (string :tag "Magic")
515 face
516 (string :tag "Description"))
517 (group (const rogue)
518 (string :tag "Magic")
519 face
520 (string :tag "Description"))
521 (group (const factory)
522 (string :tag "Magic")
523 face
524 (string :tag "Description")))
525 (editable-list :inline t
526 (group symbol
527 (string :tag "Magic")
528 face
529 (string :tag "Description"))))
530 :group 'customize)
531
532 (defcustom custom-magic-show 'long
533 "Show long description of the state of each customization option."
534 :type '(choice (const :tag "no" nil)
535 (const short)
536 (const long))
537 :group 'customize)
538
539 (defcustom custom-magic-show-button t
540 "Show a magic button indicating the state of each customization option."
541 :type 'boolean
542 :group 'customize)
543
544 (define-widget 'custom-magic 'default
545 "Show and manipulate state for a customization option."
546 :format "%v"
547 :action 'widget-choice-item-action
548 :value-get 'ignore
549 :value-create 'custom-magic-value-create
550 :value-delete 'widget-children-value-delete)
551
552 (defun custom-magic-value-create (widget)
553 ;; Create compact status report for WIDGET.
554 (let* ((parent (widget-get widget :parent))
555 (state (widget-get parent :custom-state))
556 (entry (assq state custom-magic-alist))
557 (magic (nth 1 entry))
558 (face (nth 2 entry))
559 (text (nth 3 entry))
560 (lisp (eq (widget-get parent :custom-form) 'lisp))
561 children)
562 (when custom-magic-show
563 (push (widget-create-child-and-convert widget 'choice-item
564 :help-echo "\
565 Push me to change the state of this item."
566 :format "%[%t%]"
567 :tag "State")
568 children)
569 (insert ": ")
570 (if (eq custom-magic-show 'long)
571 (insert text)
572 (insert (symbol-name state)))
573 (when lisp
574 (insert " (lisp)"))
575 (insert "\n"))
576 (when custom-magic-show-button
577 (when custom-magic-show
578 (let ((indent (widget-get parent :indent)))
579 (when indent
580 (insert-char ? indent))))
581 (push (widget-create-child-and-convert widget 'choice-item
582 :button-face face
583 :help-echo "\
584 Push me to change the state."
585 :format "%[%t%]"
586 :tag (if lisp
587 (concat "(" magic ")")
588 (concat "[" magic "]")))
589 children)
590 (insert " "))
591 (widget-put widget :children children)))
592
593 (defun custom-magic-reset (widget)
594 "Redraw the :custom-magic property of WIDGET."
595 (let ((magic (widget-get widget :custom-magic)))
596 (widget-value-set magic (widget-value magic))))
597
598 ;;; The `custom-level' Widget.
599
600 (define-widget 'custom-level 'item
601 "The custom level buttons."
602 :format "%[%t%]"
603 :help-echo "Push me to expand or collapse this item."
604 :action 'custom-level-action)
605
606 (defun custom-level-action (widget &optional event)
607 "Toggle visibility for parent to WIDGET."
608 (let* ((parent (widget-get widget :parent))
609 (state (widget-get parent :custom-state)))
610 (cond ((memq state '(invalid modified))
611 (error "There are unset changes"))
612 ((eq state 'hidden)
613 (widget-put parent :custom-state 'unknown))
614 (t
615 (widget-put parent :custom-state 'hidden)))
616 (custom-redraw parent)))
617
618 ;;; The `custom' Widget.
619
620 (define-widget 'custom 'default
621 "Customize a user option."
622 :convert-widget 'custom-convert-widget
623 :format "%l%[%t%]: %v%m%h%a"
624 :format-handler 'custom-format-handler
625 :notify 'custom-notify
626 :custom-level 1
627 :custom-state 'hidden
628 :documentation-property 'widget-subclass-responsibility
629 :value-create 'widget-subclass-responsibility
630 :value-delete 'widget-children-value-delete
631 :value-get 'widget-item-value-get
632 :validate 'widget-editable-list-validate
633 :match (lambda (widget value) (symbolp value)))
634
635 (defun custom-convert-widget (widget)
636 ;; Initialize :value and :tag from :args in WIDGET.
637 (let ((args (widget-get widget :args)))
638 (when args
639 (widget-put widget :value (widget-apply widget
640 :value-to-internal (car args)))
641 (widget-put widget :tag (custom-unlispify-tag-name (car args)))
642 (widget-put widget :args nil)))
643 widget)
644
645 (defun custom-format-handler (widget escape)
646 ;; We recognize extra escape sequences.
647 (let* ((buttons (widget-get widget :buttons))
648 (state (widget-get widget :custom-state))
649 (level (widget-get widget :custom-level)))
650 (cond ((eq escape ?l)
651 (when level
652 (push (widget-create-child-and-convert
653 widget 'custom-level (make-string level ?*))
654 buttons)
655 (widget-insert " ")
656 (widget-put widget :buttons buttons)))
657 ((eq escape ?L)
658 (when (eq state 'hidden)
659 (widget-insert " ...")))
660 ((eq escape ?m)
661 (and (eq (preceding-char) ?\n)
662 (widget-get widget :indent)
663 (insert-char ? (widget-get widget :indent)))
664 (let ((magic (widget-create-child-and-convert
665 widget 'custom-magic nil)))
666 (widget-put widget :custom-magic magic)
667 (push magic buttons)
668 (widget-put widget :buttons buttons)))
669 ((eq escape ?a)
670 (let* ((symbol (widget-get widget :value))
671 (links (get symbol 'custom-links))
672 (many (> (length links) 2)))
673 (when links
674 (and (eq (preceding-char) ?\n)
675 (widget-get widget :indent)
676 (insert-char ? (widget-get widget :indent)))
677 (insert "See also ")
678 (while links
679 (push (widget-create-child-and-convert widget (car links))
680 buttons)
681 (setq links (cdr links))
682 (cond ((null links)
683 (insert ".\n"))
684 ((null (cdr links))
685 (if many
686 (insert ", and ")
687 (insert " and ")))
688 (t
689 (insert ", "))))
690 (widget-put widget :buttons buttons))))
691 (t
692 (widget-default-format-handler widget escape)))))
693
694 (defun custom-notify (widget &rest args)
695 "Keep track of changes."
696 (widget-put widget :custom-state 'modified)
697 (let ((buffer-undo-list t))
698 (custom-magic-reset widget))
699 (apply 'widget-default-notify widget args))
700
701 (defun custom-redraw (widget)
702 "Redraw WIDGET with current settings."
703 (widget-value-set widget (widget-value widget))
704 (custom-redraw-magic widget))
705
706 (defun custom-redraw-magic (widget)
707 "Redraw WIDGET state with current settings."
708 (while widget
709 (let ((magic (widget-get widget :custom-magic)))
710 (unless magic
711 (debug))
712 (widget-value-set magic (widget-value magic))
713 (when (setq widget (widget-get widget :group))
714 (custom-group-state-update widget))))
715 (widget-setup))
716
717 (defun custom-show (widget value)
718 "Non-nil if WIDGET should be shown with VALUE by default."
719 (let ((show (widget-get widget :custom-show)))
720 (cond ((null show)
721 nil)
722 ((eq t show)
723 t)
724 (t
725 (funcall show widget value)))))
726
727 (defun custom-load-symbol (symbol)
728 "Load all dependencies for SYMBOL."
729 (let ((loads (get symbol 'custom-loads))
730 load)
731 (while loads
732 (setq load (car loads)
733 loads (cdr loads))
734 (cond ((symbolp load)
735 (condition-case nil
736 (require load)
737 (error nil)))
738 ((assoc load load-history))
739 (t
740 (condition-case nil
741 (load-library load)
742 (error nil)))))))
743
744 (defun custom-load-widget (widget)
745 "Load all dependencies for WIDGET."
746 (custom-load-symbol (widget-value widget)))
747
748 ;;; The `custom-variable' Widget.
749
750 (defface custom-variable-sample-face '((t (:underline t)))
751 "Face used for unpushable variable tags."
752 :group 'customize)
753
754 (defface custom-variable-button-face '((t (:underline t :bold t)))
755 "Face used for pushable variable tags."
756 :group 'customize)
757
758 (define-widget 'custom-variable 'custom
759 "Customize variable."
760 :format "%l%v%m%h%a"
761 :help-echo "Push me to set or reset this variable."
762 :documentation-property 'variable-documentation
763 :custom-state nil
764 :custom-menu 'custom-variable-menu-create
765 :custom-form 'edit
766 :value-create 'custom-variable-value-create
767 :action 'custom-variable-action
768 :custom-set 'custom-variable-set
769 :custom-save 'custom-variable-save
770 :custom-reset-current 'custom-redraw
771 :custom-reset-saved 'custom-variable-reset-saved
772 :custom-reset-factory 'custom-variable-reset-factory)
773
774 (defun custom-variable-value-create (widget)
775 "Here is where you edit the variables value."
776 (custom-load-widget widget)
777 (let* ((buttons (widget-get widget :buttons))
778 (children (widget-get widget :children))
779 (form (widget-get widget :custom-form))
780 (state (widget-get widget :custom-state))
781 (symbol (widget-get widget :value))
782 (options (get symbol 'custom-options))
783 (child-type (or (get symbol 'custom-type) 'sexp))
784 (tag (widget-get widget :tag))
785 (type (let ((tmp (if (listp child-type)
786 (copy-list child-type)
787 (list child-type))))
788 (when options
789 (widget-put tmp :options options))
790 tmp))
791 (conv (widget-convert type))
792 (value (if (default-boundp symbol)
793 (default-value symbol)
794 (widget-get conv :value))))
795 ;; If the widget is new, the child determine whether it is hidden.
796 (cond (state)
797 ((custom-show type value)
798 (setq state 'unknown))
799 (t
800 (setq state 'hidden)))
801 ;; If we don't know the state, see if we need to edit it in lisp form.
802 (when (eq state 'unknown)
803 (unless (widget-apply conv :match value)
804 ;; (widget-apply (widget-convert type) :match value)
805 (setq form 'lisp)))
806 ;; Now we can create the child widget.
807 (cond ((eq state 'hidden)
808 ;; Indicate hidden value.
809 (push (widget-create-child-and-convert
810 widget 'item
811 :format "%{%t%}: ..."
812 :sample-face 'custom-variable-sample-face
813 :tag tag
814 :parent widget)
815 children))
816 ((eq form 'lisp)
817 ;; In lisp mode edit the saved value when possible.
818 (let* ((value (cond ((get symbol 'saved-value)
819 (car (get symbol 'saved-value)))
820 ((get symbol 'factory-value)
821 (car (get symbol 'factory-value)))
822 ((default-boundp symbol)
823 (custom-quote (default-value symbol)))
824 (t
825 (custom-quote (widget-get conv :value))))))
826 (push (widget-create-child-and-convert
827 widget 'sexp
828 :button-face 'custom-variable-button-face
829 :tag (symbol-name symbol)
830 :parent widget
831 :value value)
832 children)))
833 (t
834 ;; Edit mode.
835 (push (widget-create-child-and-convert
836 widget type
837 :tag tag
838 :button-face 'custom-variable-button-face
839 :sample-face 'custom-variable-sample-face
840 :value value)
841 children)))
842 ;; Now update the state.
843 (unless (eq (preceding-char) ?\n)
844 (widget-insert "\n"))
845 (if (eq state 'hidden)
846 (widget-put widget :custom-state state)
847 (custom-variable-state-set widget))
848 (widget-put widget :custom-form form)
849 (widget-put widget :buttons buttons)
850 (widget-put widget :children children)))
851
852 (defun custom-variable-state-set (widget)
853 "Set the state of WIDGET."
854 (let* ((symbol (widget-value widget))
855 (value (if (default-boundp symbol)
856 (default-value symbol)
857 (widget-get widget :value)))
858 tmp
859 (state (cond ((setq tmp (get symbol 'customized-value))
860 (if (condition-case nil
861 (equal value (eval (car tmp)))
862 (error nil))
863 'saved
864 'set))
865 ((setq tmp (get symbol 'saved-value))
866 (if (condition-case nil
867 (equal value (eval (car tmp)))
868 (error nil))
869 'saved
870 'set))
871 ((setq tmp (get symbol 'factory-value))
872 (if (condition-case nil
873 (equal value (eval (car tmp)))
874 (error nil))
875 'factory
876 'set))
877 (t 'rogue))))
878 (widget-put widget :custom-state state)))
879
880 (defvar custom-variable-menu
881 '(("Edit" . custom-variable-edit)
882 ("Edit Lisp" . custom-variable-edit-lisp)
883 ("Set" . custom-variable-set)
884 ("Save" . custom-variable-save)
885 ("Reset to Current" . custom-redraw)
886 ("Reset to Saved" . custom-variable-reset-saved)
887 ("Reset to Factory Settings" . custom-variable-reset-factory))
888 "Alist of actions for the `custom-variable' widget.
889 The key is a string containing the name of the action, the value is a
890 lisp function taking the widget as an element which will be called
891 when the action is chosen.")
892
893 (defun custom-variable-action (widget &optional event)
894 "Show the menu for `custom-variable' WIDGET.
895 Optional EVENT is the location for the menu."
896 (if (eq (widget-get widget :custom-state) 'hidden)
897 (progn
898 (widget-put widget :custom-state 'unknown)
899 (custom-redraw widget))
900 (let* ((completion-ignore-case t)
901 (answer (widget-choose (symbol-name (widget-get widget :value))
902 custom-variable-menu
903 event)))
904 (if answer
905 (funcall answer widget)))))
906
907 (defun custom-variable-edit (widget)
908 "Edit value of WIDGET."
909 (widget-put widget :custom-state 'unknown)
910 (widget-put widget :custom-form 'edit)
911 (custom-redraw widget))
912
913 (defun custom-variable-edit-lisp (widget)
914 "Edit the lisp representation of the value of WIDGET."
915 (widget-put widget :custom-state 'unknown)
916 (widget-put widget :custom-form 'lisp)
917 (custom-redraw widget))
918
919 (defun custom-variable-set (widget)
920 "Set the current value for the variable being edited by WIDGET."
921 (let ((form (widget-get widget :custom-form))
922 (state (widget-get widget :custom-state))
923 (child (car (widget-get widget :children)))
924 (symbol (widget-value widget))
925 val)
926 (cond ((eq state 'hidden)
927 (error "Cannot set hidden variable."))
928 ((setq val (widget-apply child :validate))
929 (error "Invalid %S" val))
930 ((eq form 'lisp)
931 (set symbol (eval (setq val (widget-value child))))
932 (put symbol 'customized-value (list val)))
933 (t
934 (set symbol (widget-value child))
935 (put symbol 'customized-value (list (custom-quote val)))))
936 (custom-variable-state-set widget)
937 (custom-redraw-magic widget)))
938
939 (defun custom-variable-save (widget)
940 "Set the default value for the variable being edited by WIDGET."
941 (let ((form (widget-get widget :custom-form))
942 (state (widget-get widget :custom-state))
943 (child (car (widget-get widget :children)))
944 (symbol (widget-value widget))
945 val)
946 (cond ((eq state 'hidden)
947 (error "Cannot set hidden variable."))
948 ((setq val (widget-apply child :validate))
949 (error "Invalid %S" val))
950 ((eq form 'lisp)
951 (put symbol 'saved-value (list (widget-value child)))
952 (set symbol (eval (widget-value child))))
953 (t
954 (put symbol
955 'saved-value (list (custom-quote (widget-value
956 child))))
957 (set symbol (widget-value child))))
958 (put symbol 'customized-value nil)
959 (custom-save-all)
960 (custom-variable-state-set widget)
961 (custom-redraw-magic widget)))
962
963 (defun custom-variable-reset-saved (widget)
964 "Restore the saved value for the variable being edited by WIDGET."
965 (let ((symbol (widget-value widget)))
966 (if (get symbol 'saved-value)
967 (condition-case nil
968 (set symbol (eval (car (get symbol 'saved-value))))
969 (error nil))
970 (error "No saved value for %s" symbol))
971 (put symbol 'customized-value nil)
972 (widget-put widget :custom-state 'unknown)
973 (custom-redraw widget)))
974
975 (defun custom-variable-reset-factory (widget)
976 "Restore the factory setting for the variable being edited by WIDGET."
977 (let ((symbol (widget-value widget)))
978 (if (get symbol 'factory-value)
979 (set symbol (eval (car (get symbol 'factory-value))))
980 (error "No factory default for %S" symbol))
981 (put symbol 'customized-value nil)
982 (when (get symbol 'saved-value)
983 (put symbol 'saved-value nil)
984 (custom-save-all))
985 (widget-put widget :custom-state 'unknown)
986 (custom-redraw widget)))
987
988 ;;; The `custom-face-edit' Widget.
989
990 (defvar custom-face-edit-args
991 (mapcar (lambda (att)
992 (list 'group
993 :inline t
994 (list 'const :format "" :value (nth 0 att))
995 (nth 1 att)))
996 custom-face-attributes))
997
998 (define-widget 'custom-face-edit 'checklist
999 "Edit face attributes."
1000 :format "%t: %v"
1001 :tag "Attributes"
1002 :extra-offset 12
1003 :args (mapcar (lambda (att)
1004 (list 'group
1005 :inline t
1006 (list 'const :format "" :value (nth 0 att))
1007 (nth 1 att)))
1008 custom-face-attributes))
1009
1010 ;;; The `custom-display' Widget.
1011
1012 (define-widget 'custom-display 'menu-choice
1013 "Select a display type."
1014 :tag "Display"
1015 :value t
1016 :args '((const :tag "all" t)
1017 (checklist :offset 0
1018 :extra-offset 9
1019 :args ((group (const :format "Type: " type)
1020 (checklist :inline t
1021 :offset 0
1022 (const :format "X "
1023 x)
1024 (const :format "PM "
1025 pm)
1026 (const :format "Win32 "
1027 win32)
1028 (const :format "DOS "
1029 pc)
1030 (const :format "TTY%n"
1031 tty)))
1032 (group (const :format "Class: " class)
1033 (checklist :inline t
1034 :offset 0
1035 (const :format "Color "
1036 color)
1037 (const :format
1038 "Grayscale "
1039 grayscale)
1040 (const :format "Monochrome%n"
1041 mono)))
1042 (group (const :format "Background: " background)
1043 (checklist :inline t
1044 :offset 0
1045 (const :format "Light "
1046 light)
1047 (const :format "Dark\n"
1048 dark)))))))
1049
1050 ;;; The `custom-face' Widget.
1051
1052 (defface custom-face-tag-face '((t (:underline t)))
1053 "Face used for face tags."
1054 :group 'customize)
1055
1056 (define-widget 'custom-face 'custom
1057 "Customize face."
1058 :format "%l%{%t%}: %s%m%h%a%v"
1059 :format-handler 'custom-face-format-handler
1060 :sample-face 'custom-face-tag-face
1061 :help-echo "Push me to set or reset this face."
1062 :documentation-property 'face-documentation
1063 :value-create 'custom-face-value-create
1064 :action 'custom-face-action
1065 :custom-set 'custom-face-set
1066 :custom-save 'custom-face-save
1067 :custom-reset-current 'custom-redraw
1068 :custom-reset-saved 'custom-face-reset-saved
1069 :custom-reset-factory 'custom-face-reset-factory
1070 :custom-menu 'custom-face-menu-create)
1071
1072 (defun custom-face-format-handler (widget escape)
1073 ;; We recognize extra escape sequences.
1074 (let (child
1075 (state (widget-get widget :custom-state))
1076 (symbol (widget-get widget :value)))
1077 (cond ((eq escape ?s)
1078 (and (string-match "XEmacs" emacs-version)
1079 ;; XEmacs cannot display initialized faces.
1080 (not (custom-facep symbol))
1081 (copy-face 'custom-face-empty symbol))
1082 (setq child (widget-create-child-and-convert
1083 widget 'item
1084 :format "(%{%t%})\n"
1085 :sample-face symbol
1086 :tag "sample")))
1087 (t
1088 (custom-format-handler widget escape)))
1089 (when child
1090 (widget-put widget
1091 :buttons (cons child (widget-get widget :buttons))))))
1092
1093 (defun custom-face-value-create (widget)
1094 ;; Create a list of the display specifications.
1095 (unless (eq (preceding-char) ?\n)
1096 (insert "\n"))
1097 (when (not (eq (widget-get widget :custom-state) 'hidden))
1098 (custom-load-widget widget)
1099 (let* ((symbol (widget-value widget))
1100 (edit (widget-create-child-and-convert
1101 widget 'editable-list
1102 :entry-format "%i %d %v"
1103 :value (or (get symbol 'saved-face)
1104 (get symbol 'factory-face))
1105 '(group :format "%v"
1106 custom-display custom-face-edit))))
1107 (custom-face-state-set widget)
1108 (widget-put widget :children (list edit)))))
1109
1110 (defvar custom-face-menu
1111 '(("Set" . custom-face-set)
1112 ("Save" . custom-face-save)
1113 ("Reset to Saved" . custom-face-reset-saved)
1114 ("Reset to Factory Setting" . custom-face-reset-factory))
1115 "Alist of actions for the `custom-face' widget.
1116 The key is a string containing the name of the action, the value is a
1117 lisp function taking the widget as an element which will be called
1118 when the action is chosen.")
1119
1120 (defun custom-face-state-set (widget)
1121 "Set the state of WIDGET."
1122 (let ((symbol (widget-value widget)))
1123 (widget-put widget :custom-state (cond ((get symbol 'customized-face)
1124 'set)
1125 ((get symbol 'saved-face)
1126 'saved)
1127 ((get symbol 'factory-face)
1128 'factory)
1129 (t
1130 'rogue)))))
1131
1132 (defun custom-face-action (widget &optional event)
1133 "Show the menu for `custom-face' WIDGET.
1134 Optional EVENT is the location for the menu."
1135 (if (eq (widget-get widget :custom-state) 'hidden)
1136 (progn
1137 (widget-put widget :custom-state 'unknown)
1138 (custom-redraw widget))
1139 (let* ((completion-ignore-case t)
1140 (symbol (widget-get widget :value))
1141 (answer (widget-choose (symbol-name symbol)
1142 custom-face-menu event)))
1143 (if answer
1144 (funcall answer widget)))))
1145
1146 (defun custom-face-set (widget)
1147 "Make the face attributes in WIDGET take effect."
1148 (let* ((symbol (widget-value widget))
1149 (child (car (widget-get widget :children)))
1150 (value (widget-value child)))
1151 (put symbol 'customized-face value)
1152 (custom-face-display-set symbol value)
1153 (custom-face-state-set widget)
1154 (custom-redraw-magic widget)))
1155
1156 (defun custom-face-save (widget)
1157 "Make the face attributes in WIDGET default."
1158 (let* ((symbol (widget-value widget))
1159 (child (car (widget-get widget :children)))
1160 (value (widget-value child)))
1161 (custom-face-display-set symbol value)
1162 (put symbol 'saved-face value)
1163 (put symbol 'customized-face nil)
1164 (custom-face-state-set widget)
1165 (custom-redraw-magic widget)))
1166
1167 (defun custom-face-reset-saved (widget)
1168 "Restore WIDGET to the face's default attributes."
1169 (let* ((symbol (widget-value widget))
1170 (child (car (widget-get widget :children)))
1171 (value (get symbol 'saved-face)))
1172 (unless value
1173 (error "No saved value for this face"))
1174 (put symbol 'customized-face nil)
1175 (custom-face-display-set symbol value)
1176 (widget-value-set child value)
1177 (custom-face-state-set widget)
1178 (custom-redraw-magic widget)))
1179
1180 (defun custom-face-reset-factory (widget)
1181 "Restore WIDGET to the face's factory settings."
1182 (let* ((symbol (widget-value widget))
1183 (child (car (widget-get widget :children)))
1184 (value (get symbol 'factory-face)))
1185 (unless value
1186 (error "No factory default for this face"))
1187 (put symbol 'customized-face nil)
1188 (when (get symbol 'saved-face)
1189 (put symbol 'saved-face nil)
1190 (custom-save-all))
1191 (custom-face-display-set symbol value)
1192 (widget-value-set child value)
1193 (custom-face-state-set widget)
1194 (custom-redraw-magic widget)))
1195
1196 ;;; The `face' Widget.
1197
1198 (define-widget 'face 'default
1199 "Select and customize a face."
1200 :convert-widget 'widget-item-convert-widget
1201 :format "%[%t%]: %v"
1202 :tag "Face"
1203 :value 'default
1204 :value-create 'widget-face-value-create
1205 :value-delete 'widget-face-value-delete
1206 :value-get 'widget-item-value-get
1207 :validate 'widget-editable-list-validate
1208 :action 'widget-face-action
1209 :match '(lambda (widget value) (symbolp value)))
1210
1211 (defun widget-face-value-create (widget)
1212 ;; Create a `custom-face' child.
1213 (let* ((symbol (widget-value widget))
1214 (child (widget-create-child-and-convert
1215 widget 'custom-face
1216 :format "%t %s%m%h%v"
1217 :custom-level nil
1218 :value symbol)))
1219 (custom-magic-reset child)
1220 (setq custom-options (cons child custom-options))
1221 (widget-put widget :children (list child))))
1222
1223 (defun widget-face-value-delete (widget)
1224 ;; Remove the child from the options.
1225 (let ((child (car (widget-get widget :children))))
1226 (setq custom-options (delq child custom-options))
1227 (widget-children-value-delete widget)))
1228
1229 (defvar face-history nil
1230 "History of entered face names.")
1231
1232 (defun widget-face-action (widget &optional event)
1233 "Prompt for a face."
1234 (let ((answer (completing-read "Face: "
1235 (mapcar (lambda (face)
1236 (list (symbol-name face)))
1237 (face-list))
1238 nil nil nil
1239 'face-history)))
1240 (unless (zerop (length answer))
1241 (widget-value-set widget (intern answer))
1242 (widget-apply widget :notify widget event)
1243 (widget-setup))))
1244
1245 ;;; The `hook' Widget.
1246
1247 (define-widget 'hook 'list
1248 "A emacs lisp hook"
1249 :convert-widget 'custom-hook-convert-widget
1250 :tag "Hook")
1251
1252 (defun custom-hook-convert-widget (widget)
1253 ;; Handle `:custom-options'.
1254 (let* ((options (widget-get widget :options))
1255 (other `(editable-list :inline t
1256 :entry-format "%i %d%v"
1257 (function :format " %v")))
1258 (args (if options
1259 (list `(checklist :inline t
1260 ,@(mapcar (lambda (entry)
1261 `(function-item ,entry))
1262 options))
1263 other)
1264 (list other))))
1265 (widget-put widget :args args)
1266 widget))
1267
1268 ;;; The `custom-group' Widget.
1269
1270 (defcustom custom-group-tag-faces '(custom-group-tag-face-1)
1271 ;; In XEmacs, this ought to play games with font size.
1272 "Face used for group tags.
1273 The first member is used for level 1 groups, the second for level 2,
1274 and so forth. The remaining group tags are shown with
1275 `custom-group-tag-face'."
1276 :type '(repeat face)
1277 :group 'customize)
1278
1279 (defface custom-group-tag-face-1 '((((class color)
1280 (background dark))
1281 (:foreground "pink" :underline t))
1282 (((class color)
1283 (background light))
1284 (:foreground "red" :underline t))
1285 (t (:underline t)))
1286 "Face used for group tags.")
1287
1288 (defface custom-group-tag-face '((((class color)
1289 (background dark))
1290 (:foreground "light blue" :underline t))
1291 (((class color)
1292 (background light))
1293 (:foreground "blue" :underline t))
1294 (t (:underline t)))
1295 "Face used for low level group tags."
1296 :group 'customize)
1297
1298 (define-widget 'custom-group 'custom
1299 "Customize group."
1300 :format "%l%{%t%}:%L\n%m%h%a%v"
1301 :sample-face-get 'custom-group-sample-face-get
1302 :documentation-property 'group-documentation
1303 :help-echo "Push me to set or reset all members of this group."
1304 :value-create 'custom-group-value-create
1305 :action 'custom-group-action
1306 :custom-set 'custom-group-set
1307 :custom-save 'custom-group-save
1308 :custom-reset-current 'custom-group-reset-current
1309 :custom-reset-saved 'custom-group-reset-saved
1310 :custom-reset-factory 'custom-group-reset-factory
1311 :custom-menu 'custom-group-menu-create)
1312
1313 (defun custom-group-sample-face-get (widget)
1314 ;; Use :sample-face.
1315 (or (nth (1- (widget-get widget :custom-level)) custom-group-tag-faces)
1316 'custom-group-tag-face))
1317
1318 (defun custom-group-value-create (widget)
1319 (let ((state (widget-get widget :custom-state)))
1320 (unless (eq state 'hidden)
1321 (custom-load-widget widget)
1322 (let* ((level (widget-get widget :custom-level))
1323 (symbol (widget-value widget))
1324 (members (get symbol 'custom-group))
1325 (prefixes (widget-get widget :custom-prefixes))
1326 (custom-prefix-list (custom-prefix-add symbol prefixes))
1327 (children (mapcar (lambda (entry)
1328 (widget-insert "\n")
1329 (prog1
1330 (widget-create-child-and-convert
1331 widget (nth 1 entry)
1332 :group widget
1333 :tag (custom-unlispify-tag-name
1334 (nth 0 entry))
1335 :custom-prefixes custom-prefix-list
1336 :custom-level (1+ level)
1337 :value (nth 0 entry))
1338 (unless (eq (preceding-char) ?\n)
1339 (widget-insert "\n"))))
1340 members)))
1341 (mapcar 'custom-magic-reset children)
1342 (widget-put widget :children children)
1343 (custom-group-state-update widget)))))
1344
1345 (defvar custom-group-menu
1346 '(("Set" . custom-group-set)
1347 ("Save" . custom-group-save)
1348 ("Reset to Current" . custom-group-reset-current)
1349 ("Reset to Saved" . custom-group-reset-saved)
1350 ("Reset to Factory" . custom-group-reset-factory))
1351 "Alist of actions for the `custom-group' widget.
1352 The key is a string containing the name of the action, the value is a
1353 lisp function taking the widget as an element which will be called
1354 when the action is chosen.")
1355
1356 (defun custom-group-action (widget &optional event)
1357 "Show the menu for `custom-group' WIDGET.
1358 Optional EVENT is the location for the menu."
1359 (if (eq (widget-get widget :custom-state) 'hidden)
1360 (progn
1361 (widget-put widget :custom-state 'unknown)
1362 (custom-redraw widget))
1363 (let* ((completion-ignore-case t)
1364 (answer (widget-choose (symbol-name (widget-get widget :value))
1365 custom-group-menu
1366 event)))
1367 (if answer
1368 (funcall answer widget)))))
1369
1370 (defun custom-group-set (widget)
1371 "Set changes in all modified group members."
1372 (let ((children (widget-get widget :children)))
1373 (mapcar (lambda (child)
1374 (when (eq (widget-get child :custom-state) 'modified)
1375 (widget-apply child :custom-set)))
1376 children )))
1377
1378 (defun custom-group-save (widget)
1379 "Save all modified group members."
1380 (let ((children (widget-get widget :children)))
1381 (mapcar (lambda (child)
1382 (when (memq (widget-get child :custom-state) '(modified set))
1383 (widget-apply child :custom-save)))
1384 children )))
1385
1386 (defun custom-group-reset-current (widget)
1387 "Reset all modified group members."
1388 (let ((children (widget-get widget :children)))
1389 (mapcar (lambda (child)
1390 (when (eq (widget-get child :custom-state) 'modified)
1391 (widget-apply child :custom-reset-current)))
1392 children )))
1393
1394 (defun custom-group-reset-saved (widget)
1395 "Reset all modified or set group members."
1396 (let ((children (widget-get widget :children)))
1397 (mapcar (lambda (child)
1398 (when (memq (widget-get child :custom-state) '(modified set))
1399 (widget-apply child :custom-reset-saved)))
1400 children )))
1401
1402 (defun custom-group-reset-factory (widget)
1403 "Reset all modified, set, or saved group members."
1404 (let ((children (widget-get widget :children)))
1405 (mapcar (lambda (child)
1406 (when (memq (widget-get child :custom-state)
1407 '(modified set saved))
1408 (widget-apply child :custom-reset-factory)))
1409 children )))
1410
1411 (defun custom-group-state-update (widget)
1412 "Update magic."
1413 (unless (eq (widget-get widget :custom-state) 'hidden)
1414 (let* ((children (widget-get widget :children))
1415 (states (mapcar (lambda (child)
1416 (widget-get child :custom-state))
1417 children))
1418 (magics custom-magic-alist)
1419 (found 'factory))
1420 (while magics
1421 (let ((magic (car (car magics))))
1422 (if (and (not (eq magic 'hidden))
1423 (memq magic states))
1424 (setq found magic
1425 magics nil)
1426 (setq magics (cdr magics)))))
1427 (widget-put widget :custom-state found)))
1428 (custom-magic-reset widget))
1429
1430 ;;; The `custom-save-all' Function.
1431
1432 (defcustom custom-file "~/.emacs"
1433 "File used for storing customization information.
1434 If you change this from the default \"~/.emacs\" you need to
1435 explicitly load that file for the settings to take effect."
1436 :type 'file
1437 :group 'customize)
1438
1439 (defun custom-save-delete (symbol)
1440 "Delete the call to SYMBOL form `custom-file'.
1441 Leave point at the location of the call, or after the last expression."
1442 (set-buffer (find-file-noselect custom-file))
1443 (goto-char (point-min))
1444 (catch 'found
1445 (while t
1446 (let ((sexp (condition-case nil
1447 (read (current-buffer))
1448 (end-of-file (throw 'found nil)))))
1449 (when (and (listp sexp)
1450 (eq (car sexp) symbol))
1451 (delete-region (save-excursion
1452 (backward-sexp)
1453 (point))
1454 (point))
1455 (throw 'found nil))))))
1456
1457 (defun custom-save-variables ()
1458 "Save all customized variables in `custom-file'."
1459 (save-excursion
1460 (custom-save-delete 'custom-set-variables)
1461 (let ((standard-output (current-buffer)))
1462 (unless (bolp)
1463 (princ "\n"))
1464 (princ "(custom-set-variables")
1465 (mapatoms (lambda (symbol)
1466 (let ((value (get symbol 'saved-value)))
1467 (when value
1468 (princ "\n '(")
1469 (princ symbol)
1470 (princ " ")
1471 (prin1 (car value))
1472 (if (or (get symbol 'factory-value)
1473 (and (not (boundp symbol))
1474 (not (get symbol 'force-value))))
1475 (princ ")")
1476 (princ " t)"))))))
1477 (princ ")")
1478 (unless (eolp)
1479 (princ "\n")))))
1480
1481 (defun custom-save-faces ()
1482 "Save all customized faces in `custom-file'."
1483 (save-excursion
1484 (custom-save-delete 'custom-set-faces)
1485 (let ((standard-output (current-buffer)))
1486 (unless (bolp)
1487 (princ "\n"))
1488 (princ "(custom-set-faces")
1489 (mapatoms (lambda (symbol)
1490 (let ((value (get symbol 'saved-face)))
1491 (when value
1492 (princ "\n '(")
1493 (princ symbol)
1494 (princ " ")
1495 (prin1 value)
1496 (if (or (get symbol 'factory-face)
1497 (and (not (custom-facep symbol))
1498 (not (get symbol 'force-face))))
1499 (princ ")")
1500 (princ " t)"))))))
1501 (princ ")")
1502 (unless (eolp)
1503 (princ "\n")))))
1504
1505 (defun custom-save-all ()
1506 "Save all customizations in `custom-file'."
1507 (custom-save-variables)
1508 (custom-save-faces)
1509 (save-excursion
1510 (set-buffer (find-file-noselect custom-file))
1511 (save-buffer)))
1512
1513 ;;; The Customize Menu.
1514
1515 (defcustom custom-menu-nesting 2
1516 "Maximum nesting in custom menus."
1517 :type 'integer
1518 :group 'customize)
1519
1520 (defun custom-face-menu-create (widget symbol)
1521 "Ignoring WIDGET, create a menu entry for customization face SYMBOL."
1522 (vector (custom-unlispify-menu-entry symbol)
1523 `(custom-buffer-create '((,symbol custom-face)))
1524 t))
1525
1526 (defun custom-variable-menu-create (widget symbol)
1527 "Ignoring WIDGET, create a menu entry for customization variable SYMBOL."
1528 (let ((type (get symbol 'custom-type)))
1529 (unless (listp type)
1530 (setq type (list type)))
1531 (if (and type (widget-get type :custom-menu))
1532 (widget-apply type :custom-menu symbol)
1533 (vector (custom-unlispify-menu-entry symbol)
1534 `(custom-buffer-create '((,symbol custom-variable)))
1535 t))))
1536
1537 (widget-put (get 'boolean 'widget-type)
1538 :custom-menu (lambda (widget symbol)
1539 (vector (custom-unlispify-menu-entry symbol)
1540 `(custom-buffer-create
1541 '((,symbol custom-variable)))
1542 ':style 'toggle
1543 ':selected symbol)))
1544
1545 (defun custom-group-menu-create (widget symbol)
1546 "Ignoring WIDGET, create a menu entry for customization group SYMBOL."
1547 (custom-menu-create symbol))
1548
1549 (defun custom-menu-create (symbol &optional name)
1550 "Create menu for customization group SYMBOL.
1551 If optional NAME is given, use that as the name of the menu.
1552 Otherwise make up a name from SYMBOL.
1553 The menu is in a format applicable to `easy-menu-define'."
1554 (unless name
1555 (setq name (custom-unlispify-menu-entry symbol)))
1556 (let ((item (vector name
1557 `(custom-buffer-create '((,symbol custom-group)))
1558 t)))
1559 (if (and (> custom-menu-nesting 0)
1560 (< (length (get symbol 'custom-group)) widget-menu-max-size))
1561 (let ((custom-menu-nesting (1- custom-menu-nesting))
1562 (custom-prefix-list (custom-prefix-add symbol
1563 custom-prefix-list)))
1564 (custom-load-symbol symbol)
1565 `(,(custom-unlispify-menu-entry symbol t)
1566 ,item
1567 "--"
1568 ,@(mapcar (lambda (entry)
1569 (widget-apply (if (listp (nth 1 entry))
1570 (nth 1 entry)
1571 (list (nth 1 entry)))
1572 :custom-menu (nth 0 entry)))
1573 (get symbol 'custom-group))))
1574 item)))
1575
1576 ;;;###autoload
1577 (defun custom-menu-update ()
1578 "Update customize menu."
1579 (interactive)
1580 (add-hook 'custom-define-hook 'custom-menu-reset)
1581 (let ((menu `(,(car custom-help-menu)
1582 ,(widget-apply '(custom-group) :custom-menu 'emacs)
1583 ,@(cdr (cdr custom-help-menu)))))
1584 (if (fboundp 'add-submenu)
1585 (add-submenu '("Help") menu)
1586 (define-key global-map [menu-bar help-menu customize-menu]
1587 (cons (car menu) (easy-menu-create-keymaps (car menu) (cdr menu)))))))
1588
1589 ;;; Dependencies.
1590
1591 ;;;###autoload
1592 (defun custom-make-dependencies ()
1593 "Batch function to extract custom dependencies from .el files.
1594 Usage: emacs -batch *.el -f custom-make-dependencies > deps.el"
1595 (let ((buffers (buffer-list)))
1596 (while buffers
1597 (set-buffer (car buffers))
1598 (setq buffers (cdr buffers))
1599 (let ((file (buffer-file-name)))
1600 (when (and file (string-match "\\`\\(.*\\)\\.el\\'" file))
1601 (goto-char (point-min))
1602 (condition-case nil
1603 (let ((name (file-name-nondirectory (match-string 1 file))))
1604 (while t
1605 (let ((expr (read (current-buffer))))
1606 (when (and (listp expr)
1607 (memq (car expr) '(defcustom defface defgroup)))
1608 (eval expr)
1609 (put (nth 1 expr) 'custom-where name)))))
1610 (error nil))))))
1611 (mapatoms (lambda (symbol)
1612 (let ((members (get symbol 'custom-group))
1613 item where found)
1614 (when members
1615 (princ "(put '")
1616 (princ symbol)
1617 (princ " 'custom-loads '(")
1618 (while members
1619 (setq item (car (car members))
1620 members (cdr members)
1621 where (get item 'custom-where))
1622 (unless (or (null where)
1623 (member where found))
1624 (when found
1625 (princ " "))
1626 (prin1 where)
1627 (push where found)))
1628 (princ "))\n"))))))
1629
1630 ;;; The End.
1631
1632 (provide 'custom-edit)
1633
1634 ;; custom-edit.el ends here