comparison lisp/custom/custom-edit.el @ 18:d95e72db5c07 r19-15b92

Import from CVS: tag r19-15b92
author cvs
date Mon, 13 Aug 2007 08:49:43 +0200
parents
children 859a2309aef8
comparison
equal deleted inserted replaced
17:4579af9d8826 18:d95e72db5c07
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.24
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 (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 (goto-char (widget-get val :from))
930 (error "%s" (widget-get val :error)))
931 ((eq form 'lisp)
932 (set symbol (eval (setq val (widget-value child))))
933 (put symbol 'customized-value (list val)))
934 (t
935 (set symbol (widget-value child))
936 (put symbol 'customized-value (list (custom-quote val)))))
937 (custom-variable-state-set widget)
938 (custom-redraw-magic widget)))
939
940 (defun custom-variable-save (widget)
941 "Set the default value for the variable being edited by WIDGET."
942 (let ((form (widget-get widget :custom-form))
943 (state (widget-get widget :custom-state))
944 (child (car (widget-get widget :children)))
945 (symbol (widget-value widget))
946 val)
947 (cond ((eq state 'hidden)
948 (error "Cannot set hidden variable."))
949 ((setq val (widget-apply child :validate))
950 (goto-char (widget-get val :from))
951 (error "%s" (widget-get val :error)))
952 ((eq form 'lisp)
953 (put symbol 'saved-value (list (widget-value child)))
954 (set symbol (eval (widget-value child))))
955 (t
956 (put symbol
957 'saved-value (list (custom-quote (widget-value
958 child))))
959 (set symbol (widget-value child))))
960 (put symbol 'customized-value nil)
961 (custom-save-all)
962 (custom-variable-state-set widget)
963 (custom-redraw-magic widget)))
964
965 (defun custom-variable-reset-saved (widget)
966 "Restore the saved value for the variable being edited by WIDGET."
967 (let ((symbol (widget-value widget)))
968 (if (get symbol 'saved-value)
969 (condition-case nil
970 (set symbol (eval (car (get symbol 'saved-value))))
971 (error nil))
972 (error "No saved value for %s" symbol))
973 (put symbol 'customized-value nil)
974 (widget-put widget :custom-state 'unknown)
975 (custom-redraw widget)))
976
977 (defun custom-variable-reset-factory (widget)
978 "Restore the factory setting for the variable being edited by WIDGET."
979 (let ((symbol (widget-value widget)))
980 (if (get symbol 'factory-value)
981 (set symbol (eval (car (get symbol 'factory-value))))
982 (error "No factory default for %S" symbol))
983 (put symbol 'customized-value nil)
984 (when (get symbol 'saved-value)
985 (put symbol 'saved-value nil)
986 (custom-save-all))
987 (widget-put widget :custom-state 'unknown)
988 (custom-redraw widget)))
989
990 ;;; The `custom-face-edit' Widget.
991
992 (defvar custom-face-edit-args
993 (mapcar (lambda (att)
994 (list 'group
995 :inline t
996 (list 'const :format "" :value (nth 0 att))
997 (nth 1 att)))
998 custom-face-attributes))
999
1000 (define-widget 'custom-face-edit 'checklist
1001 "Edit face attributes."
1002 :format "%t: %v"
1003 :tag "Attributes"
1004 :extra-offset 12
1005 :args (mapcar (lambda (att)
1006 (list 'group
1007 :inline t
1008 (list 'const :format "" :value (nth 0 att))
1009 (nth 1 att)))
1010 custom-face-attributes))
1011
1012 ;;; The `custom-display' Widget.
1013
1014 (define-widget 'custom-display 'menu-choice
1015 "Select a display type."
1016 :tag "Display"
1017 :value t
1018 :args '((const :tag "all" t)
1019 (checklist :offset 0
1020 :extra-offset 9
1021 :args ((group (const :format "Type: " type)
1022 (checklist :inline t
1023 :offset 0
1024 (const :format "X "
1025 x)
1026 (const :format "PM "
1027 pm)
1028 (const :format "Win32 "
1029 win32)
1030 (const :format "DOS "
1031 pc)
1032 (const :format "TTY%n"
1033 tty)))
1034 (group (const :format "Class: " class)
1035 (checklist :inline t
1036 :offset 0
1037 (const :format "Color "
1038 color)
1039 (const :format
1040 "Grayscale "
1041 grayscale)
1042 (const :format "Monochrome%n"
1043 mono)))
1044 (group (const :format "Background: " background)
1045 (checklist :inline t
1046 :offset 0
1047 (const :format "Light "
1048 light)
1049 (const :format "Dark\n"
1050 dark)))))))
1051
1052 ;;; The `custom-face' Widget.
1053
1054 (defface custom-face-tag-face '((t (:underline t)))
1055 "Face used for face tags."
1056 :group 'customize)
1057
1058 (define-widget 'custom-face 'custom
1059 "Customize face."
1060 :format "%l%{%t%}: %s%m%h%a%v"
1061 :format-handler 'custom-face-format-handler
1062 :sample-face 'custom-face-tag-face
1063 :help-echo "Push me to set or reset this face."
1064 :documentation-property 'face-documentation
1065 :value-create 'custom-face-value-create
1066 :action 'custom-face-action
1067 :custom-set 'custom-face-set
1068 :custom-save 'custom-face-save
1069 :custom-reset-current 'custom-redraw
1070 :custom-reset-saved 'custom-face-reset-saved
1071 :custom-reset-factory 'custom-face-reset-factory
1072 :custom-menu 'custom-face-menu-create)
1073
1074 (defun custom-face-format-handler (widget escape)
1075 ;; We recognize extra escape sequences.
1076 (let (child
1077 (symbol (widget-get widget :value)))
1078 (cond ((eq escape ?s)
1079 (and (string-match "XEmacs" emacs-version)
1080 ;; XEmacs cannot display initialized faces.
1081 (not (custom-facep symbol))
1082 (copy-face 'custom-face-empty symbol))
1083 (setq child (widget-create-child-and-convert
1084 widget 'item
1085 :format "(%{%t%})\n"
1086 :sample-face symbol
1087 :tag "sample")))
1088 (t
1089 (custom-format-handler widget escape)))
1090 (when child
1091 (widget-put widget
1092 :buttons (cons child (widget-get widget :buttons))))))
1093
1094 (defun custom-face-value-create (widget)
1095 ;; Create a list of the display specifications.
1096 (unless (eq (preceding-char) ?\n)
1097 (insert "\n"))
1098 (when (not (eq (widget-get widget :custom-state) 'hidden))
1099 (custom-load-widget widget)
1100 (let* ((symbol (widget-value widget))
1101 (edit (widget-create-child-and-convert
1102 widget 'editable-list
1103 :entry-format "%i %d %v"
1104 :value (or (get symbol 'saved-face)
1105 (get symbol 'factory-face))
1106 '(group :format "%v"
1107 custom-display custom-face-edit))))
1108 (custom-face-state-set widget)
1109 (widget-put widget :children (list edit)))))
1110
1111 (defvar custom-face-menu
1112 '(("Set" . custom-face-set)
1113 ("Save" . custom-face-save)
1114 ("Reset to Saved" . custom-face-reset-saved)
1115 ("Reset to Factory Setting" . custom-face-reset-factory))
1116 "Alist of actions for the `custom-face' widget.
1117 The key is a string containing the name of the action, the value is a
1118 lisp function taking the widget as an element which will be called
1119 when the action is chosen.")
1120
1121 (defun custom-face-state-set (widget)
1122 "Set the state of WIDGET."
1123 (let ((symbol (widget-value widget)))
1124 (widget-put widget :custom-state (cond ((get symbol 'customized-face)
1125 'set)
1126 ((get symbol 'saved-face)
1127 'saved)
1128 ((get symbol 'factory-face)
1129 'factory)
1130 (t
1131 'rogue)))))
1132
1133 (defun custom-face-action (widget &optional event)
1134 "Show the menu for `custom-face' WIDGET.
1135 Optional EVENT is the location for the menu."
1136 (if (eq (widget-get widget :custom-state) 'hidden)
1137 (progn
1138 (widget-put widget :custom-state 'unknown)
1139 (custom-redraw widget))
1140 (let* ((completion-ignore-case t)
1141 (symbol (widget-get widget :value))
1142 (answer (widget-choose (symbol-name symbol)
1143 custom-face-menu event)))
1144 (if answer
1145 (funcall answer widget)))))
1146
1147 (defun custom-face-set (widget)
1148 "Make the face attributes in WIDGET take effect."
1149 (let* ((symbol (widget-value widget))
1150 (child (car (widget-get widget :children)))
1151 (value (widget-value child)))
1152 (put symbol 'customized-face value)
1153 (custom-face-display-set symbol value)
1154 (custom-face-state-set widget)
1155 (custom-redraw-magic widget)))
1156
1157 (defun custom-face-save (widget)
1158 "Make the face attributes in WIDGET default."
1159 (let* ((symbol (widget-value widget))
1160 (child (car (widget-get widget :children)))
1161 (value (widget-value child)))
1162 (custom-face-display-set symbol value)
1163 (put symbol 'saved-face value)
1164 (put symbol 'customized-face nil)
1165 (custom-face-state-set widget)
1166 (custom-redraw-magic widget)))
1167
1168 (defun custom-face-reset-saved (widget)
1169 "Restore WIDGET to the face's default attributes."
1170 (let* ((symbol (widget-value widget))
1171 (child (car (widget-get widget :children)))
1172 (value (get symbol 'saved-face)))
1173 (unless value
1174 (error "No saved value for this face"))
1175 (put symbol 'customized-face nil)
1176 (custom-face-display-set symbol value)
1177 (widget-value-set child value)
1178 (custom-face-state-set widget)
1179 (custom-redraw-magic widget)))
1180
1181 (defun custom-face-reset-factory (widget)
1182 "Restore WIDGET to the face's factory settings."
1183 (let* ((symbol (widget-value widget))
1184 (child (car (widget-get widget :children)))
1185 (value (get symbol 'factory-face)))
1186 (unless value
1187 (error "No factory default for this face"))
1188 (put symbol 'customized-face nil)
1189 (when (get symbol 'saved-face)
1190 (put symbol 'saved-face nil)
1191 (custom-save-all))
1192 (custom-face-display-set symbol value)
1193 (widget-value-set child value)
1194 (custom-face-state-set widget)
1195 (custom-redraw-magic widget)))
1196
1197 ;;; The `face' Widget.
1198
1199 (define-widget 'face 'default
1200 "Select and customize a face."
1201 :convert-widget 'widget-item-convert-widget
1202 :format "%[%t%]: %v"
1203 :tag "Face"
1204 :value 'default
1205 :value-create 'widget-face-value-create
1206 :value-delete 'widget-face-value-delete
1207 :value-get 'widget-item-value-get
1208 :validate 'widget-editable-list-validate
1209 :action 'widget-face-action
1210 :match '(lambda (widget value) (symbolp value)))
1211
1212 (defun widget-face-value-create (widget)
1213 ;; Create a `custom-face' child.
1214 (let* ((symbol (widget-value widget))
1215 (child (widget-create-child-and-convert
1216 widget 'custom-face
1217 :format "%t %s%m%h%v"
1218 :custom-level nil
1219 :value symbol)))
1220 (custom-magic-reset child)
1221 (setq custom-options (cons child custom-options))
1222 (widget-put widget :children (list child))))
1223
1224 (defun widget-face-value-delete (widget)
1225 ;; Remove the child from the options.
1226 (let ((child (car (widget-get widget :children))))
1227 (setq custom-options (delq child custom-options))
1228 (widget-children-value-delete widget)))
1229
1230 (defvar face-history nil
1231 "History of entered face names.")
1232
1233 (defun widget-face-action (widget &optional event)
1234 "Prompt for a face."
1235 (let ((answer (completing-read "Face: "
1236 (mapcar (lambda (face)
1237 (list (symbol-name face)))
1238 (face-list))
1239 nil nil nil
1240 'face-history)))
1241 (unless (zerop (length answer))
1242 (widget-value-set widget (intern answer))
1243 (widget-apply widget :notify widget event)
1244 (widget-setup))))
1245
1246 ;;; The `hook' Widget.
1247
1248 (define-widget 'hook 'list
1249 "A emacs lisp hook"
1250 :convert-widget 'custom-hook-convert-widget
1251 :tag "Hook")
1252
1253 (defun custom-hook-convert-widget (widget)
1254 ;; Handle `:custom-options'.
1255 (let* ((options (widget-get widget :options))
1256 (other `(editable-list :inline t
1257 :entry-format "%i %d%v"
1258 (function :format " %v")))
1259 (args (if options
1260 (list `(checklist :inline t
1261 ,@(mapcar (lambda (entry)
1262 `(function-item ,entry))
1263 options))
1264 other)
1265 (list other))))
1266 (widget-put widget :args args)
1267 widget))
1268
1269 ;;; The `custom-group' Widget.
1270
1271 (defcustom custom-group-tag-faces '(custom-group-tag-face-1)
1272 ;; In XEmacs, this ought to play games with font size.
1273 "Face used for group tags.
1274 The first member is used for level 1 groups, the second for level 2,
1275 and so forth. The remaining group tags are shown with
1276 `custom-group-tag-face'."
1277 :type '(repeat face)
1278 :group 'customize)
1279
1280 (defface custom-group-tag-face-1 '((((class color)
1281 (background dark))
1282 (:foreground "pink" :underline t))
1283 (((class color)
1284 (background light))
1285 (:foreground "red" :underline t))
1286 (t (:underline t)))
1287 "Face used for group tags.")
1288
1289 (defface custom-group-tag-face '((((class color)
1290 (background dark))
1291 (:foreground "light blue" :underline t))
1292 (((class color)
1293 (background light))
1294 (:foreground "blue" :underline t))
1295 (t (:underline t)))
1296 "Face used for low level group tags."
1297 :group 'customize)
1298
1299 (define-widget 'custom-group 'custom
1300 "Customize group."
1301 :format "%l%{%t%}:%L\n%m%h%a%v"
1302 :sample-face-get 'custom-group-sample-face-get
1303 :documentation-property 'group-documentation
1304 :help-echo "Push me to set or reset all members of this group."
1305 :value-create 'custom-group-value-create
1306 :action 'custom-group-action
1307 :custom-set 'custom-group-set
1308 :custom-save 'custom-group-save
1309 :custom-reset-current 'custom-group-reset-current
1310 :custom-reset-saved 'custom-group-reset-saved
1311 :custom-reset-factory 'custom-group-reset-factory
1312 :custom-menu 'custom-group-menu-create)
1313
1314 (defun custom-group-sample-face-get (widget)
1315 ;; Use :sample-face.
1316 (or (nth (1- (widget-get widget :custom-level)) custom-group-tag-faces)
1317 'custom-group-tag-face))
1318
1319 (defun custom-group-value-create (widget)
1320 (let ((state (widget-get widget :custom-state)))
1321 (unless (eq state 'hidden)
1322 (custom-load-widget widget)
1323 (let* ((level (widget-get widget :custom-level))
1324 (symbol (widget-value widget))
1325 (members (get symbol 'custom-group))
1326 (prefixes (widget-get widget :custom-prefixes))
1327 (custom-prefix-list (custom-prefix-add symbol prefixes))
1328 (children (mapcar (lambda (entry)
1329 (widget-insert "\n")
1330 (prog1
1331 (widget-create-child-and-convert
1332 widget (nth 1 entry)
1333 :group widget
1334 :tag (custom-unlispify-tag-name
1335 (nth 0 entry))
1336 :custom-prefixes custom-prefix-list
1337 :custom-level (1+ level)
1338 :value (nth 0 entry))
1339 (unless (eq (preceding-char) ?\n)
1340 (widget-insert "\n"))))
1341 members)))
1342 (mapcar 'custom-magic-reset children)
1343 (widget-put widget :children children)
1344 (custom-group-state-update widget)))))
1345
1346 (defvar custom-group-menu
1347 '(("Set" . custom-group-set)
1348 ("Save" . custom-group-save)
1349 ("Reset to Current" . custom-group-reset-current)
1350 ("Reset to Saved" . custom-group-reset-saved)
1351 ("Reset to Factory" . custom-group-reset-factory))
1352 "Alist of actions for the `custom-group' widget.
1353 The key is a string containing the name of the action, the value is a
1354 lisp function taking the widget as an element which will be called
1355 when the action is chosen.")
1356
1357 (defun custom-group-action (widget &optional event)
1358 "Show the menu for `custom-group' WIDGET.
1359 Optional EVENT is the location for the menu."
1360 (if (eq (widget-get widget :custom-state) 'hidden)
1361 (progn
1362 (widget-put widget :custom-state 'unknown)
1363 (custom-redraw widget))
1364 (let* ((completion-ignore-case t)
1365 (answer (widget-choose (symbol-name (widget-get widget :value))
1366 custom-group-menu
1367 event)))
1368 (if answer
1369 (funcall answer widget)))))
1370
1371 (defun custom-group-set (widget)
1372 "Set changes in all modified group members."
1373 (let ((children (widget-get widget :children)))
1374 (mapcar (lambda (child)
1375 (when (eq (widget-get child :custom-state) 'modified)
1376 (widget-apply child :custom-set)))
1377 children )))
1378
1379 (defun custom-group-save (widget)
1380 "Save all modified group members."
1381 (let ((children (widget-get widget :children)))
1382 (mapcar (lambda (child)
1383 (when (memq (widget-get child :custom-state) '(modified set))
1384 (widget-apply child :custom-save)))
1385 children )))
1386
1387 (defun custom-group-reset-current (widget)
1388 "Reset all modified group members."
1389 (let ((children (widget-get widget :children)))
1390 (mapcar (lambda (child)
1391 (when (eq (widget-get child :custom-state) 'modified)
1392 (widget-apply child :custom-reset-current)))
1393 children )))
1394
1395 (defun custom-group-reset-saved (widget)
1396 "Reset all modified or set group members."
1397 (let ((children (widget-get widget :children)))
1398 (mapcar (lambda (child)
1399 (when (memq (widget-get child :custom-state) '(modified set))
1400 (widget-apply child :custom-reset-saved)))
1401 children )))
1402
1403 (defun custom-group-reset-factory (widget)
1404 "Reset all modified, set, or saved group members."
1405 (let ((children (widget-get widget :children)))
1406 (mapcar (lambda (child)
1407 (when (memq (widget-get child :custom-state)
1408 '(modified set saved))
1409 (widget-apply child :custom-reset-factory)))
1410 children )))
1411
1412 (defun custom-group-state-update (widget)
1413 "Update magic."
1414 (unless (eq (widget-get widget :custom-state) 'hidden)
1415 (let* ((children (widget-get widget :children))
1416 (states (mapcar (lambda (child)
1417 (widget-get child :custom-state))
1418 children))
1419 (magics custom-magic-alist)
1420 (found 'factory))
1421 (while magics
1422 (let ((magic (car (car magics))))
1423 (if (and (not (eq magic 'hidden))
1424 (memq magic states))
1425 (setq found magic
1426 magics nil)
1427 (setq magics (cdr magics)))))
1428 (widget-put widget :custom-state found)))
1429 (custom-magic-reset widget))
1430
1431 ;;; The `custom-save-all' Function.
1432
1433 (defcustom custom-file "~/.emacs"
1434 "File used for storing customization information.
1435 If you change this from the default \"~/.emacs\" you need to
1436 explicitly load that file for the settings to take effect."
1437 :type 'file
1438 :group 'customize)
1439
1440 (defun custom-save-delete (symbol)
1441 "Delete the call to SYMBOL form `custom-file'.
1442 Leave point at the location of the call, or after the last expression."
1443 (set-buffer (find-file-noselect custom-file))
1444 (goto-char (point-min))
1445 (catch 'found
1446 (while t
1447 (let ((sexp (condition-case nil
1448 (read (current-buffer))
1449 (end-of-file (throw 'found nil)))))
1450 (when (and (listp sexp)
1451 (eq (car sexp) symbol))
1452 (delete-region (save-excursion
1453 (backward-sexp)
1454 (point))
1455 (point))
1456 (throw 'found nil))))))
1457
1458 (defun custom-save-variables ()
1459 "Save all customized variables in `custom-file'."
1460 (save-excursion
1461 (custom-save-delete 'custom-set-variables)
1462 (let ((standard-output (current-buffer)))
1463 (unless (bolp)
1464 (princ "\n"))
1465 (princ "(custom-set-variables")
1466 (mapatoms (lambda (symbol)
1467 (let ((value (get symbol 'saved-value)))
1468 (when value
1469 (princ "\n '(")
1470 (princ symbol)
1471 (princ " ")
1472 (prin1 (car value))
1473 (if (or (get symbol 'factory-value)
1474 (and (not (boundp symbol))
1475 (not (get symbol 'force-value))))
1476 (princ ")")
1477 (princ " t)"))))))
1478 (princ ")")
1479 (unless (eolp)
1480 (princ "\n")))))
1481
1482 (defun custom-save-faces ()
1483 "Save all customized faces in `custom-file'."
1484 (save-excursion
1485 (custom-save-delete 'custom-set-faces)
1486 (let ((standard-output (current-buffer)))
1487 (unless (bolp)
1488 (princ "\n"))
1489 (princ "(custom-set-faces")
1490 (mapatoms (lambda (symbol)
1491 (let ((value (get symbol 'saved-face)))
1492 (when value
1493 (princ "\n '(")
1494 (princ symbol)
1495 (princ " ")
1496 (prin1 value)
1497 (if (or (get symbol 'factory-face)
1498 (and (not (custom-facep symbol))
1499 (not (get symbol 'force-face))))
1500 (princ ")")
1501 (princ " t)"))))))
1502 (princ ")")
1503 (unless (eolp)
1504 (princ "\n")))))
1505
1506 (defun custom-save-all ()
1507 "Save all customizations in `custom-file'."
1508 (custom-save-variables)
1509 (custom-save-faces)
1510 (save-excursion
1511 (set-buffer (find-file-noselect custom-file))
1512 (save-buffer)))
1513
1514 ;;; The Customize Menu.
1515
1516 (defcustom custom-menu-nesting 2
1517 "Maximum nesting in custom menus."
1518 :type 'integer
1519 :group 'customize)
1520
1521 (defun custom-face-menu-create (widget symbol)
1522 "Ignoring WIDGET, create a menu entry for customization face SYMBOL."
1523 (vector (custom-unlispify-menu-entry symbol)
1524 `(custom-buffer-create '((,symbol custom-face)))
1525 t))
1526
1527 (defun custom-variable-menu-create (widget symbol)
1528 "Ignoring WIDGET, create a menu entry for customization variable SYMBOL."
1529 (let ((type (get symbol 'custom-type)))
1530 (unless (listp type)
1531 (setq type (list type)))
1532 (if (and type (widget-get type :custom-menu))
1533 (widget-apply type :custom-menu symbol)
1534 (vector (custom-unlispify-menu-entry symbol)
1535 `(custom-buffer-create '((,symbol custom-variable)))
1536 t))))
1537
1538 (widget-put (get 'boolean 'widget-type)
1539 :custom-menu (lambda (widget symbol)
1540 (vector (custom-unlispify-menu-entry symbol)
1541 `(custom-buffer-create
1542 '((,symbol custom-variable)))
1543 ':style 'toggle
1544 ':selected symbol)))
1545
1546 (defun custom-group-menu-create (widget symbol)
1547 "Ignoring WIDGET, create a menu entry for customization group SYMBOL."
1548 (custom-menu-create symbol))
1549
1550 (defun custom-menu-create (symbol &optional name)
1551 "Create menu for customization group SYMBOL.
1552 If optional NAME is given, use that as the name of the menu.
1553 Otherwise make up a name from SYMBOL.
1554 The menu is in a format applicable to `easy-menu-define'."
1555 (unless name
1556 (setq name (custom-unlispify-menu-entry symbol)))
1557 (let ((item (vector name
1558 `(custom-buffer-create '((,symbol custom-group)))
1559 t)))
1560 (if (and (> custom-menu-nesting 0)
1561 (< (length (get symbol 'custom-group)) widget-menu-max-size))
1562 (let ((custom-menu-nesting (1- custom-menu-nesting))
1563 (custom-prefix-list (custom-prefix-add symbol
1564 custom-prefix-list)))
1565 (custom-load-symbol symbol)
1566 `(,(custom-unlispify-menu-entry symbol t)
1567 ,item
1568 "--"
1569 ,@(mapcar (lambda (entry)
1570 (widget-apply (if (listp (nth 1 entry))
1571 (nth 1 entry)
1572 (list (nth 1 entry)))
1573 :custom-menu (nth 0 entry)))
1574 (get symbol 'custom-group))))
1575 item)))
1576
1577 ;;;###autoload
1578 (defun custom-menu-update ()
1579 "Update customize menu."
1580 (interactive)
1581 (add-hook 'custom-define-hook 'custom-menu-reset)
1582 (let ((menu `(,(car custom-help-menu)
1583 ,(widget-apply '(custom-group) :custom-menu 'emacs)
1584 ,@(cdr (cdr custom-help-menu)))))
1585 (if (fboundp 'add-submenu)
1586 (add-submenu '("Help") menu)
1587 (define-key global-map [menu-bar help-menu customize-menu]
1588 (cons (car menu) (easy-menu-create-keymaps (car menu) (cdr menu)))))))
1589
1590 ;;; Dependencies.
1591
1592 ;;;###autoload
1593 (defun custom-make-dependencies ()
1594 "Batch function to extract custom dependencies from .el files.
1595 Usage: emacs -batch *.el -f custom-make-dependencies > deps.el"
1596 (let ((buffers (buffer-list)))
1597 (while buffers
1598 (set-buffer (car buffers))
1599 (setq buffers (cdr buffers))
1600 (let ((file (buffer-file-name)))
1601 (when (and file (string-match "\\`\\(.*\\)\\.el\\'" file))
1602 (goto-char (point-min))
1603 (condition-case nil
1604 (let ((name (file-name-nondirectory (match-string 1 file))))
1605 (while t
1606 (let ((expr (read (current-buffer))))
1607 (when (and (listp expr)
1608 (memq (car expr) '(defcustom defface defgroup)))
1609 (eval expr)
1610 (put (nth 1 expr) 'custom-where name)))))
1611 (error nil))))))
1612 (mapatoms (lambda (symbol)
1613 (let ((members (get symbol 'custom-group))
1614 item where found)
1615 (when members
1616 (princ "(put '")
1617 (princ symbol)
1618 (princ " 'custom-loads '(")
1619 (while members
1620 (setq item (car (car members))
1621 members (cdr members)
1622 where (get item 'custom-where))
1623 (unless (or (null where)
1624 (member where found))
1625 (when found
1626 (princ " "))
1627 (prin1 where)
1628 (push where found)))
1629 (princ "))\n"))))))
1630
1631 ;;; The End.
1632
1633 (provide 'custom-edit)
1634
1635 ;; custom-edit.el ends here