Merge remote-tracking branch 'origin/master' into for-steve
[sxemacs] / lisp / cus-edit.el
1 ;;; cus-edit.el --- Tools for customizating Emacs and Lisp packages.
2 ;;
3 ;; Copyright (C) 2007 Didier Verna
4 ;; Copyright (C) 2003 Ben Wing
5 ;; Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc.
6 ;;
7 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
8 ;; Maintainer: Didier Verna <didier@xemacs.org>
9 ;; Keywords: help, faces
10 ;; Version: 1.9960-x
11 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
12
13 ;; This file is part of SXEmacs.
14
15 ;; SXEmacs is free software: you can redistribute it and/or modify
16 ;; it under the terms of the GNU General Public License as published by
17 ;; the Free Software Foundation, either version 3 of the License, or
18 ;; (at your option) any later version.
19
20 ;; SXEmacs is distributed in the hope that it will be useful,
21 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 ;; GNU General Public License for more details.
24
25 ;; You should have received a copy of the GNU General Public License
26 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
27
28 ;;; Commentary:
29 ;;
30 ;; This file implements the code to create and edit customize buffers.
31 ;;
32 ;; See `custom.el'.
33
34 ;; No commands should have names starting with `custom-' because
35 ;; that interferes with completion.  Use `customize-' for commands
36 ;; that the user will run with M-x, and `Custom-' for interactive commands.
37
38 ;; NOTE: In many places within this file we use `mapatoms', which is
39 ;; very slow in an average XEmacs because of the large number of
40 ;; symbols requiring a large number of funcalls -- XEmacs with Gnus
41 ;; can grow to some 17000 symbols without ever doing anything fancy.
42 ;; It would probably pay off to make a hash table of symbols known to
43 ;; Custom, similar to custom-group-hash-table.
44
45 ;; This is not top priority, because none of the functions that do
46 ;; mapatoms are speed-critical (the one that was now uses
47 ;; custom-group-hash-table), but it would be nice to have.
48
49 \f
50 ;;; Code:
51
52 (require 'cus-face)
53 (require 'wid-edit)
54 (require 'easymenu)
55
56 (require 'cus-load)
57 (require 'cus-start)
58 (require 'cus-file)
59
60 ;; Huh?  This looks dirty!
61 (put 'custom-define-hook 'custom-type 'hook)
62 (put 'custom-define-hook 'standard-value '(nil))
63 (custom-add-to-group 'customize 'custom-define-hook 'custom-variable)
64
65 ;;; Customization Groups.
66
67 (defgroup emacs nil
68   "Customization of the One True Editor."
69   :link '(custom-manual "(XEmacs)Top"))
70
71 ;; Most of these groups are stolen from `finder.el',
72 (defgroup editing nil
73   "Basic text editing facilities."
74   :group 'emacs)
75
76 (defgroup matching nil
77   "Various sorts of searching and matching."
78   :group 'editing)
79
80 (defgroup emulations nil
81   "Emulations of other editors."
82   :group 'editing)
83
84 (defgroup outlines nil
85   "Support for hierarchical outlining."
86   :group 'editing)
87
88 (defgroup external nil
89   "Interfacing to external utilities."
90   :group 'emacs)
91
92 (defgroup bib nil
93   "Code related to the `bib' bibliography processor."
94   :tag "Bibliography"
95   :group 'external)
96
97 (defgroup programming nil
98   "Support for programming in other languages."
99   :group 'emacs)
100
101 (defgroup languages nil
102   "Specialized modes for editing programming languages."
103   :group 'programming)
104
105 ;; #### This should be in cc-vars.el
106 (defgroup c nil
107   "Support for the C language and related languages."
108   :group 'languages)
109
110 (defgroup tools nil
111   "Programming tools."
112   :group 'programming)
113
114 (defgroup oop nil
115   "Support for object-oriented programming."
116   :group 'programming)
117
118 (defgroup applications nil
119   "Applications written in Emacs."
120   :group 'emacs)
121
122 ;; #### This should be in calendar.el
123 (defgroup calendar nil
124   "Calendar and time management support."
125   :group 'applications)
126
127 (defgroup mail nil
128   "Modes for electronic-mail handling."
129   :group 'applications)
130
131 (defgroup news nil
132   "Support for netnews reading and posting."
133   :group 'applications)
134
135 (defgroup games nil
136   "Games, jokes and amusements."
137   :group 'applications)
138
139 (defgroup development nil
140   "Support for further development of Emacs."
141   :group 'emacs)
142
143 (defgroup docs nil
144   "Support for Emacs documentation."
145   :group 'development)
146
147 (defgroup extensions nil
148   "Emacs Lisp language extensions."
149   :group 'development)
150
151 (defgroup internal nil
152   "Code for Emacs internals, build process, defaults."
153   :group 'development)
154
155 (defgroup maint nil
156   "Maintenance aids for the Emacs development group."
157   :tag "Maintenance"
158   :group 'development)
159
160 (defgroup environment nil
161   "Fitting Emacs with its environment."
162   :group 'emacs)
163
164 (defgroup comm nil
165   "Communications, networking, remote access to files."
166   :tag "Communication"
167   :group 'environment)
168
169 (defgroup hardware nil
170   "Support for interfacing with exotic hardware."
171   :group 'environment)
172
173 (defgroup terminals nil
174   "Support for terminal types."
175   :group 'environment)
176
177 (defgroup unix nil
178   "Front-ends/assistants for, or emulators of, UNIX features."
179   :group 'environment)
180
181 (defgroup i18n nil
182   "Internationalization and alternate character-set support."
183   :group 'environment
184   :group 'editing)
185
186 (defgroup data nil
187   "Support editing files of data."
188   :group 'emacs)
189
190 (defgroup wp nil
191   "Word processing."
192   :group 'emacs)
193
194 (defgroup tex nil
195   "Code related to the TeX formatter."
196   :group 'wp)
197
198 (defgroup hypermedia nil
199   "Support for links between text or other media types."
200   :group 'emacs)
201
202 (defgroup local nil
203   "Code local to your site."
204   :group 'emacs)
205
206 (defgroup customize '((widgets custom-group))
207   "Customization of the Customization support."
208   :link '(custom-manual "(custom)Top")
209   :link '(url-link :tag "Development Page"
210                    "http://www.dina.kvl.dk/~abraham/custom/")
211   :prefix "custom-"
212   :group 'help)
213
214 (defgroup custom-faces nil
215   "Faces used by customize."
216   :group 'customize
217   :group 'faces)
218
219 (defgroup custom-browse nil
220   "Control customize browser."
221   :prefix "custom-"
222   :group 'customize)
223
224 (defgroup custom-buffer nil
225   "Control customize buffers."
226   :prefix "custom-"
227   :group 'customize)
228
229 (defgroup custom-menu nil
230   "Control customize menus."
231   :prefix "custom-"
232   :group 'customize)
233
234 (defgroup alloc nil
235   "Storage allocation and gc for XEmacs Lisp interpreter."
236   :tag "Storage Allocation"
237   :group 'internal)
238
239 (defgroup undo nil
240   "Undoing changes in buffers."
241   :group 'editing)
242
243 (defgroup editing-basics nil
244   "Most basic editing facilities."
245   :group 'editing)
246
247 (defgroup display nil
248   "How characters are displayed in buffers."
249   :group 'environment)
250
251 (defgroup installation nil
252   "The Emacs installation."
253   :group 'environment)
254
255 (defgroup limits nil
256   "Internal Emacs limits."
257   :group 'internal)
258
259 (defgroup debug nil
260   "Debugging Emacs itself."
261   :group 'development)
262
263 (defgroup mule nil
264   "Mule XEmacs internationalization."
265   :group 'i18n)
266
267 \f
268 ;;; Utilities.
269
270 (defun custom-quote (sexp)
271   "Quote SEXP iff it is not self quoting."
272   (if (or (memq sexp '(t nil))
273           (keywordp sexp)
274           (eq (car-safe sexp) 'lambda)
275           (stringp sexp)
276           (numberp sexp)
277           (characterp sexp)
278           (vectorp sexp)
279           (bit-vector-p sexp))
280       sexp
281     (list 'quote sexp)))
282
283 (defun custom-split-regexp-maybe (regexp)
284   "If REGEXP is a string, split it to a list at `\\|'.
285 You can get the original back with from the result with:
286   (mapconcat #'identity result \"\\|\")
287
288 IF REGEXP is not a string, return it unchanged."
289   (if (stringp regexp)
290       (split-string regexp #r"\\|")
291     regexp))
292
293 (defun custom-variable-prompt ()
294   ;; Code stolen from `help.el'.
295   "Prompt for a variable, defaulting to the variable at point.
296 Return a list suitable for use in `interactive'."
297    (let ((v (variable-at-point))
298          (enable-recursive-minibuffers t)
299          val)
300      (setq val (completing-read
301                 (if (symbolp v)
302                     (format "Customize variable: (default %s) " v)
303                   "Customize variable: ")
304                 obarray (lambda (symbol)
305                           (and (boundp symbol)
306                                (or (get symbol 'custom-type)
307                                    (user-variable-p symbol))))
308                 t nil nil (and v (symbol-name v))))
309      (list (if (equal val "")
310                (if (symbolp v) v nil)
311              (intern val)))))
312
313 ;; Here we take not only the actual groups, but the loads, too.
314 (defun custom-group-prompt (prompt)
315   "Read group from minibuffer."
316   (let ((completion-ignore-case t))
317     (list (completing-read
318            prompt obarray
319            (lambda (symbol)
320              (or (get symbol 'custom-group)
321                  (get symbol 'custom-loads)))
322            t))))
323
324 (defun custom-menu-filter (menu widget)
325   "Convert MENU to the form used by `widget-choose'.
326 MENU should be in the same format as `custom-variable-menu'.
327 WIDGET is the widget to apply the filter entries of MENU on."
328   (let ((result nil)
329         current name action filter)
330     (while menu
331       (setq current (car menu)
332             name (nth 0 current)
333             action (nth 1 current)
334             filter (nth 2 current)
335             menu (cdr menu))
336       (if (or (null filter) (funcall filter widget))
337           (push (cons name action) result)
338         (push name result)))
339     (nreverse result)))
340
341 \f
342 ;;; Unlispify.
343
344 (defvar custom-prefix-list nil
345   "List of prefixes that should be ignored by `custom-unlispify'")
346
347 (defcustom custom-save-pretty-print t
348   "Non-nil means pretty-print values of customized variables if available."
349   :group 'customize
350   :type 'boolean)
351
352
353 (defcustom custom-unlispify-menu-entries t
354   "Display menu entries as words instead of symbols if non nil."
355   :group 'custom-menu
356   :type 'boolean)
357
358 (defcustom custom-unlispify-remove-prefixes t
359   "Non-nil means remove group prefixes from option names in buffers and menus.
360 This only has an effect when `custom-unlispify-tag-names' or
361 `custom-unlispify-menu-entries' is on."
362   :group 'custom-menu
363   :type 'boolean)
364
365 (defun custom-unlispify-menu-entry (symbol &optional no-suffix)
366   "Convert symbol into a menu entry."
367   (cond ((not custom-unlispify-menu-entries)
368          (symbol-name symbol))
369         ((get symbol 'custom-tag)
370          (if no-suffix
371              (get symbol 'custom-tag)
372            (concat (get symbol 'custom-tag) "...")))
373         (t
374          (with-current-buffer (get-buffer-create " *Custom-Work*")
375            (erase-buffer)
376            (princ symbol (current-buffer))
377            (goto-char (point-min))
378            (when (and (eq (get symbol 'custom-type) 'boolean)
379                       (re-search-forward "-p\\'" nil t))
380              (replace-match "" t t)
381              (goto-char (point-min)))
382            (when custom-unlispify-remove-prefixes
383              (let ((prefixes custom-prefix-list)
384                    prefix)
385                (while prefixes
386                  (setq prefix (car prefixes))
387                  (if (search-forward prefix (+ (point) (length prefix)) t)
388                      (progn
389                        (setq prefixes nil)
390                        (delete-region (point-min) (point)))
391                    (setq prefixes (cdr prefixes))))))
392            (subst-char-in-region (point-min) (point-max) ?- ?\  t)
393            (capitalize-region (point-min) (point-max))
394            (unless no-suffix
395              (goto-char (point-max))
396              (insert "..."))
397            (buffer-string)))))
398
399 (defcustom custom-unlispify-tag-names t
400   "Display tag names as words instead of symbols if non nil."
401   :group 'custom-buffer
402   :type 'boolean)
403
404 (defun custom-unlispify-tag-name (symbol)
405   "Convert symbol into a menu entry."
406   (let ((custom-unlispify-menu-entries custom-unlispify-tag-names))
407     (custom-unlispify-menu-entry symbol t)))
408
409 (defun custom-prefix-add (symbol prefixes)
410   ;; Add SYMBOL to list of ignored PREFIXES.
411   (cons (or (get symbol 'custom-prefix)
412             (concat (symbol-name symbol) "-"))
413         prefixes))
414
415 \f
416 ;;; Guess.
417
418 (defcustom custom-guess-name-alist
419   '(("-p\\'" boolean)
420     ("-hooks?\\'" hook)
421     ("-face\\'" face)
422     ("-file\\'" file)
423     ("-function\\'" function)
424     ("-functions\\'" (repeat function))
425     ("-list\\'" (repeat sexp))
426     ("-alist\\'" (repeat (cons sexp sexp))))
427   "Alist of (MATCH TYPE).
428
429 MATCH should be a regexp matching the name of a symbol, and TYPE should
430 be a widget suitable for editing the value of that symbol.  The TYPE
431 of the first entry where MATCH matches the name of the symbol will be
432 used.
433
434 This is used for guessing the type of variables not declared with
435 customize."
436   :type '(repeat (group (regexp :tag "Match") (sexp :tag "Type")))
437   :group 'customize)
438
439 (defcustom custom-guess-doc-alist
440   '((#r"\`\*?Non-nil " boolean))
441   "Alist of (MATCH TYPE).
442
443 MATCH should be a regexp matching a documentation string, and TYPE
444 should be a widget suitable for editing the value of a variable with
445 that documentation string.  The TYPE of the first entry where MATCH
446 matches the name of the symbol will be used.
447
448 This is used for guessing the type of variables not declared with
449 customize."
450   :type '(repeat (group (regexp :tag "Match") (sexp :tag "Type")))
451   :group 'customize)
452
453 (defun custom-guess-type (symbol)
454   "Guess a widget suitable for editing the value of SYMBOL.
455 This is done by matching SYMBOL with `custom-guess-name-alist' and
456 if that fails, the doc string with `custom-guess-doc-alist'."
457   (let ((name (symbol-name symbol))
458         (names custom-guess-name-alist)
459         current found)
460     (while names
461       (setq current (car names)
462             names (cdr names))
463       (when (string-match (nth 0 current) name)
464         (setq found (nth 1 current)
465               names nil)))
466     (unless found
467       (let ((doc (documentation-property symbol 'variable-documentation))
468             (docs custom-guess-doc-alist))
469         (when doc
470           (while docs
471             (setq current (car docs)
472                   docs (cdr docs))
473             (when (string-match (nth 0 current) doc)
474               (setq found (nth 1 current)
475                     docs nil))))))
476     found))
477
478 \f
479 ;;; Sorting.
480
481 (defcustom custom-browse-sort-alphabetically nil
482   "If non-nil, sort members of each customization group alphabetically."
483   :type 'boolean
484   :group 'custom-browse)
485
486 (defcustom custom-browse-order-groups nil
487   "If non-nil, order group members within each customization group.
488 If `first', order groups before non-groups.
489 If `last', order groups after non-groups."
490   :type '(choice (const first)
491                  (const last)
492                  (const :tag "none" nil))
493   :group 'custom-browse)
494
495 (defcustom custom-browse-only-groups nil
496   "If non-nil, show group members only within each customization group."
497   :type 'boolean
498   :group 'custom-browse)
499
500 (defcustom custom-buffer-sort-alphabetically nil
501   "If non-nil, sort members of each customization group alphabetically."
502   :type 'boolean
503   :group 'custom-buffer)
504
505 (defcustom custom-buffer-order-groups 'last
506   "If non-nil, order group members within each customization group.
507 If `first', order groups before non-groups.
508 If `last', order groups after non-groups."
509   :type '(choice (const first)
510                  (const last)
511                  (const :tag "none" nil))
512   :group 'custom-buffer)
513
514 (defcustom custom-menu-sort-alphabetically nil
515   "If non-nil, sort members of each customization group alphabetically."
516   :type 'boolean
517   :group 'custom-menu)
518
519 (defcustom custom-menu-order-groups 'first
520   "If non-nil, order group members within each customization group.
521 If `first', order groups before non-groups.
522 If `last', order groups after non-groups."
523   :type '(choice (const first)
524                  (const last)
525                  (const :tag "none" nil))
526   :group 'custom-menu)
527
528 (defun custom-sort-items (items sort-alphabetically order-groups)
529   "Return a sorted copy of ITEMS.
530 ITEMS should be a `custom-group' property.
531 If SORT-ALPHABETICALLY non-nil, sort alphabetically.
532 If ORDER-GROUPS is `first' order groups before non-groups, if `last' order
533 groups after non-groups, if nil do not order groups at all."
534   (sort (copy-sequence items)
535    (lambda (a b)
536      (let ((typea (nth 1 a)) (typeb (nth 1 b))
537            (namea (symbol-name (nth 0 a))) (nameb (symbol-name (nth 0 b))))
538        (cond ((not order-groups)
539               ;; Since we don't care about A and B order, maybe sort.
540               (when sort-alphabetically
541                 (string-lessp namea nameb)))
542              ((eq typea 'custom-group)
543               ;; If B is also a group, maybe sort.  Otherwise, order A and B.
544               (if (eq typeb 'custom-group)
545                   (when sort-alphabetically
546                     (string-lessp namea nameb))
547                 (eq order-groups 'first)))
548              ((eq typeb 'custom-group)
549               ;; Since A cannot be a group, order A and B.
550               (eq order-groups 'last))
551              (sort-alphabetically
552               ;; Since A and B cannot be groups, sort.
553               (string-lessp namea nameb)))))))
554
555 \f
556 ;;; Custom Mode Commands.
557
558 (defvar custom-options nil
559   "Customization widgets in the current buffer.")
560
561 (defun Custom-set ()
562   "Set changes in all modified options."
563   (interactive)
564   (let ((children custom-options))
565     (mapc (lambda (child)
566             (when (eq (widget-get child :custom-state) 'modified)
567               (widget-apply child :custom-set)))
568           children)))
569
570 (defun Custom-save ()
571   "Set all modified options and save them."
572   (interactive)
573   (let ((all-children custom-options)
574         children)
575     (mapc (lambda (child)
576             (when (memq (widget-get child :custom-state) '(modified set))
577               (push child children)))
578           all-children)
579     (let ((the-children children)
580           child)
581       (while (setq child (pop the-children))
582         (widget-apply child :custom-pre-save)))
583     (custom-save-all)
584     (let ((the-children children)
585           child)
586       (while (setq child (pop the-children))
587         (widget-apply child :custom-post-save)))
588     ))
589
590 (defvar custom-reset-menu
591   '(("Current" . Custom-reset-current)
592     ("Saved" . Custom-reset-saved)
593     ("Standard Settings" . Custom-reset-standard))
594   "Alist of actions for the `Reset' button.
595 The key is a string containing the name of the action, the value is a
596 lisp function taking the widget as an element which will be called
597 when the action is chosen.")
598
599 (defun custom-reset (event)
600   "Select item from reset menu."
601   (let* ((completion-ignore-case t)
602          (answer (widget-choose "Reset to"
603                                 custom-reset-menu
604                                 event)))
605     (if answer
606         (funcall answer))))
607
608 (defun Custom-reset-current (&rest ignore)
609   "Reset all modified group members to their current value."
610   (interactive)
611   (let ((children custom-options))
612     (mapc (lambda (child)
613             (when (eq (widget-get child :custom-state) 'modified)
614               (widget-apply child :custom-reset-current)))
615           children)))
616
617 (defun Custom-reset-saved (&rest ignore)
618   "Reset all modified or set group members to their saved value."
619   (interactive)
620   (let ((children custom-options))
621     (mapc (lambda (child)
622             (when (eq (widget-get child :custom-state) 'modified)
623               (widget-apply child :custom-reset-saved)))
624           children)))
625
626 (defun Custom-reset-standard (&rest ignore)
627   "Reset all modified, set, or saved group members to their standard settings."
628   (interactive)
629   (let ((all-children custom-options)
630         children must-save)
631     (mapc (lambda (child)
632             (when (memq (widget-get child :custom-state) '(modified set saved))
633               (push child children)))
634           all-children)
635     (let ((the-children children)
636           child)
637       (while (setq child (pop the-children))
638         (and (widget-apply child :custom-pre-reset-standard)
639              (setq must-save t))))
640     (and must-save (custom-save-all))
641     (let ((the-children children)
642           child)
643       (while (setq child (pop the-children))
644         (widget-apply child :custom-post-reset-standard)))
645     ))
646
647 \f
648 ;;; The Customize Commands
649
650 (defun custom-prompt-variable (prompt-var prompt-val &optional comment)
651   "Prompt for a variable and a value and return them as a list.
652 PROMPT-VAR is the prompt for the variable, and PROMPT-VAL is the
653 prompt for the value.  The %s escape in PROMPT-VAL is replaced with
654 the name of the variable.
655
656 If the variable has a `variable-interactive' property, that is used as if
657 it were the arg to `interactive' (which see) to interactively read the value.
658
659 If the variable has a `custom-type' property, it must be a widget and the
660 `:prompt-value' property of that widget will be used for reading the value.
661
662 If optional COMMENT argument is non nil, also prompt for a comment and return
663 it as the third element in the list."
664   (let* ((var (read-variable (concat prompt-var ": ")))
665          (minibuffer-help-form '(describe-variable var))
666          (val
667           (let ((prop (get var 'variable-interactive))
668                 (type (get var 'custom-type))
669                 (prompt (format prompt-val var)))
670             (unless (listp type)
671               (setq type (list type)))
672             (cond (prop
673                    ;; Use VAR's `variable-interactive' property
674                    ;; as an interactive spec for prompting.
675                    (call-interactively (list 'lambda '(arg)
676                                              (list 'interactive prop)
677                                              'arg)))
678                   (type
679                    (widget-prompt-value type
680                                         prompt
681                                         (if (boundp var)
682                                             (symbol-value var))
683                                         (not (boundp var))))
684                   (t
685                    (eval-minibuffer (concat prompt ": ")))))))
686     (if comment
687         (list var val
688               (read-string "Comment: " (get var 'variable-comment)))
689       (list var val))))
690
691 ;;;###autoload
692 (defun customize-set-value (var val &optional comment)
693   "Set VARIABLE to VALUE.  VALUE is a Lisp object.
694
695 If VARIABLE has a `variable-interactive' property, that is used as if
696 it were the arg to `interactive' (which see) to interactively read the value.
697
698 If VARIABLE has a `custom-type' property, it must be a widget and the
699 `:prompt-value' property of that widget will be used for reading the value.
700
701 If given a prefix (or a COMMENT argument), also prompt for a comment."
702   (interactive (custom-prompt-variable "Set variable"
703                                        "Set value of %s"
704                                        current-prefix-arg))
705
706   (set var val)
707   (cond ((string= comment "")
708          (put var 'variable-comment nil))
709         (comment
710          (put var 'variable-comment comment))))
711
712 ;;;###autoload
713 (defun customize-set-variable (variable value &optional comment)
714   "Set the default for VARIABLE to VALUE.  VALUE is any Lisp object.
715
716 If VARIABLE has a `custom-set' property, that is used for setting
717 VARIABLE, otherwise `set-default' is used.
718
719 The `customized-value' property of the VARIABLE will be set to a list
720 with a quoted VALUE as its sole list member.
721
722 If VARIABLE has a `variable-interactive' property, that is used as if
723 it were the arg to `interactive' (which see) to interactively read the value.
724
725 If VARIABLE has a `custom-type' property, it must be a widget and the
726 `:prompt-value' property of that widget will be used for reading the value.
727
728 If given a prefix (or a COMMENT argument), also prompt for a comment."
729   (interactive (custom-prompt-variable "Set variable"
730                                        "Set customized value of %s"
731                                        current-prefix-arg))
732   (funcall (or (get variable 'custom-set) 'set-default) variable value)
733   (put variable 'customized-value (list (custom-quote value)))
734   (cond ((string= comment "")
735          (put variable 'variable-comment nil)
736          (put variable 'customized-variable-comment nil))
737         (comment
738          (put variable 'variable-comment comment)
739          (put variable 'customized-variable-comment comment))))
740
741
742 ;;;###autoload
743 (defun customize-save-variable (variable value &optional comment)
744   "Set the default for VARIABLE to VALUE, and save it for future sessions.
745 If VARIABLE has a `custom-set' property, that is used for setting
746 VARIABLE, otherwise `set-default' is used.
747
748 The `customized-value' property of the VARIABLE will be set to a list
749 with a quoted VALUE as its sole list member.
750
751 If VARIABLE has a `variable-interactive' property, that is used as if
752 it were the arg to `interactive' (which see) to interactively read the value.
753
754 If VARIABLE has a `custom-type' property, it must be a widget and the
755 `:prompt-value' property of that widget will be used for reading the value.
756
757 If given a prefix (or a COMMENT argument), also prompt for a comment."
758   (interactive (custom-prompt-variable "Set and save variable"
759                                        "Set and save value of %s"
760                                        current-prefix-arg))
761   (funcall (or (get variable 'custom-set) 'set-default) variable value)
762   (put variable 'saved-value (list (custom-quote value)))
763   (custom-push-theme 'theme-value variable 'user 'set (list (custom-quote value)))
764   (cond ((string= comment "")
765          (put variable 'variable-comment nil)
766          (put variable 'saved-variable-comment nil))
767         (comment
768          (put variable 'variable-comment comment)
769          (put variable 'saved-variable-comment comment)))
770   (custom-save-all))
771
772 ;;;###autoload
773 (defun customize (group)
774   "Select a customization buffer which you can use to set user options.
775 User options are structured into \"groups\".
776 The default group is `Emacs'."
777   (interactive (custom-group-prompt
778                 "Customize group: (default emacs) "))
779   (when (stringp group)
780     (if (string-equal "" group)
781         (setq group 'emacs)
782       (setq group (intern group))))
783   (let ((name (format "*Customize Group: %s*"
784                       (custom-unlispify-tag-name group))))
785     (if (get-buffer name)
786         (switch-to-buffer name)
787       (custom-buffer-create (list (list group 'custom-group))
788                             name
789                             (concat " for group "
790                                     (custom-unlispify-tag-name group))))))
791
792 ;;;###autoload
793 (defalias 'customize-group 'customize)
794
795 ;;;###autoload
796 (defun customize-other-window (symbol)
797   "Customize SYMBOL, which must be a customization group."
798   (interactive (custom-group-prompt
799                 "Customize group: (default emacs) "))
800   (when (stringp symbol)
801     (if (string-equal "" symbol)
802         (setq symbol 'emacs)
803       (setq symbol (intern symbol))))
804   (custom-buffer-create-other-window
805    (list (list symbol 'custom-group))
806    (format "*Customize Group: %s*" (custom-unlispify-tag-name symbol))))
807
808 ;;;###autoload
809 (defalias 'customize-group-other-window 'customize-other-window)
810
811 ;;;###autoload
812 (defalias 'customize-option 'customize-variable)
813
814 ;;;###autoload
815 (defun customize-variable (symbol)
816   "Customize SYMBOL, which must be a user option variable."
817   (interactive (custom-variable-prompt))
818   (custom-buffer-create (list (list symbol 'custom-variable))
819                         (format "*Customize Variable: %s*"
820                                 (custom-unlispify-tag-name symbol))))
821
822 ;;;###autoload
823 (defun customize-changed-options (since-version)
824   "Customize all user option variables whose default values changed recently.
825 This means, in other words, variables defined with a `:version' keyword."
826   (interactive
827    "sCustomize options changed, since version (default all versions): ")
828   (if (equal since-version "")
829       (setq since-version nil))
830   (let ((found nil))
831     (mapatoms (lambda (symbol)
832                 (and (boundp symbol)
833                      (let ((version (get symbol 'custom-version)))
834                        (and version
835                             (or (null since-version)
836                                 (customize-version-lessp since-version
837                                                          version))))
838                      (push (list symbol 'custom-variable) found))))
839     (unless found
840       (error "No user options have changed defaults %s"
841              (if since-version
842                  (format "since XEmacs %s" since-version)
843                "in recent Emacs versions")))
844     (custom-buffer-create (custom-sort-items found t nil)
845                           "*Customize Changed Options*")))
846
847 (defun customize-version-lessp (version1 version2)
848   (let (major1 major2 minor1 minor2)
849     (string-match #r"\([0-9]+\)[.]\([0-9]+\)" version1)
850     (setq major1 (read (match-string 1 version1)))
851     (setq minor1 (read (match-string 2 version1)))
852     (string-match #r"\([0-9]+\)[.]\([0-9]+\)" version2)
853     (setq major2 (read (match-string 1 version2)))
854     (setq minor2 (read (match-string 2 version2)))
855     (or (< major1 major2)
856         (and (= major1 major2)
857              (< minor1 minor2)))))
858
859 ;;;###autoload
860 (defalias 'customize-variable-other-window 'customize-option-other-window)
861
862 ;;;###autoload
863 (defun customize-option-other-window (symbol)
864   "Customize SYMBOL, which must be a user option variable.
865 Show the buffer in another window, but don't select it."
866   (interactive (custom-variable-prompt))
867   (custom-buffer-create-other-window
868    (list (list symbol 'custom-variable))
869    (format "*Customize Option: %s*" (custom-unlispify-tag-name symbol))))
870
871 ;;;###autoload
872 (defun customize-face (&optional symbol)
873   "Customize SYMBOL, which should be a face name or nil.
874 If SYMBOL is nil, customize all faces."
875   (interactive (list (completing-read "Customize face: (default all) "
876                                       obarray 'find-face)))
877   (if (or (null symbol) (and (stringp symbol) (zerop (length symbol))))
878       (custom-buffer-create (custom-sort-items
879                              (mapcar (lambda (symbol)
880                                        (list symbol 'custom-face))
881                                      (face-list))
882                              t nil)
883                             "*Customize Faces*")
884     (when (stringp symbol)
885       (setq symbol (intern symbol)))
886     (check-argument-type 'symbolp symbol)
887     (custom-buffer-create (list (list symbol 'custom-face))
888                           (format "*Customize Face: %s*"
889                                   (custom-unlispify-tag-name symbol)))))
890
891 ;;;###autoload
892 (defun customize-face-other-window (&optional symbol)
893   "Show customization buffer for FACE in other window."
894   (interactive (list (completing-read "Customize face: "
895                                       obarray 'find-face)))
896   (if (or (null symbol) (and (stringp symbol) (zerop (length symbol))))
897       ()
898     (if (stringp symbol)
899         (setq symbol (intern symbol)))
900     (check-argument-type 'symbolp symbol)
901     (custom-buffer-create-other-window
902      (list (list symbol 'custom-face))
903      (format "*Customize Face: %s*" (custom-unlispify-tag-name symbol)))))
904
905 ;;;###autoload
906 (defun customize-customized ()
907   "Customize all user options set since the last save in this session."
908   (interactive)
909   (let ((found nil))
910     (mapatoms (lambda (symbol)
911                 (and (or (get symbol 'customized-face)
912                          (get symbol 'customized-face-comment))
913                      (find-face symbol)
914                      (push (list symbol 'custom-face) found))
915                 (and (or (get symbol 'customized-value)
916                          (get symbol 'customized-variable-comment))
917                      (boundp symbol)
918                      (push (list symbol 'custom-variable) found))))
919     (if (not found)
920         (error "No customized user options")
921       (custom-buffer-create (custom-sort-items found t nil)
922                             "*Customize Customized*"))))
923
924 ;;;###autoload
925 (defun customize-saved ()
926   "Customize all already saved user options."
927   (interactive)
928   (let ((found nil))
929     (mapatoms (lambda (symbol)
930                 (and (or (get symbol 'saved-face)
931                          (get symbol 'saved-face-comment))
932                      (find-face symbol)
933                      (push (list symbol 'custom-face) found))
934                 (and (or (get symbol 'saved-value)
935                          (get symbol 'saved-variable-comment))
936                      (boundp symbol)
937                      (push (list symbol 'custom-variable) found))))
938     (if (not found )
939         (error "No saved user options")
940       (custom-buffer-create (custom-sort-items found t nil)
941                             "*Customize Saved*"))))
942
943 ;;;###autoload
944 (defalias 'apropos-customize 'customize-apropos)
945
946 ;;;###autoload
947 (defun customize-apropos (regexp &optional all)
948   "Customize all user options matching REGEXP.
949 If ALL is `options', include only options.
950 If ALL is `faces', include only faces.
951 If ALL is `groups', include only groups.
952 If ALL is t (interactively, with prefix arg), include options which are not
953 user-settable, as well as faces and groups."
954   (interactive "sCustomize regexp: \nP")
955   (let ((found nil))
956     (mapatoms (lambda (symbol)
957                 (when (string-match regexp (symbol-name symbol))
958                   (when (and (not (memq all '(faces options)))
959                              (get symbol 'custom-group))
960                     (push (list symbol 'custom-group) found))
961                   (when (and (not (memq all '(options groups)))
962                              (find-face symbol))
963                     (push (list symbol 'custom-face) found))
964                   (when (and (not (memq all '(groups faces)))
965                              (boundp symbol)
966                              (or (get symbol 'saved-value)
967                                  (get symbol 'standard-value)
968                                  (if (memq all '(nil options))
969                                      (user-variable-p symbol)
970                                    (get symbol 'variable-documentation))))
971                     (push (list symbol 'custom-variable) found)))))
972     (if (not found)
973         (error "No matches")
974       (custom-buffer-create (custom-sort-items found t
975                                                custom-buffer-order-groups)
976                             "*Customize Apropos*"))))
977
978 ;;;###autoload
979 (defun customize-apropos-options (regexp &optional arg)
980   "Customize all user options matching REGEXP.
981 With prefix arg, include options which are not user-settable."
982   (interactive "sCustomize regexp: \nP")
983   (customize-apropos regexp (or arg 'options)))
984
985 ;;;###autoload
986 (defun customize-apropos-faces (regexp)
987   "Customize all user faces matching REGEXP."
988   (interactive "sCustomize regexp: \n")
989   (customize-apropos regexp 'faces))
990
991 ;;;###autoload
992 (defun customize-apropos-groups (regexp)
993   "Customize all user groups matching REGEXP."
994   (interactive "sCustomize regexp: \n")
995   (customize-apropos regexp 'groups))
996
997 \f
998 ;;; Buffer.
999
1000 (defcustom custom-buffer-style 'links
1001   "*Control the presentation style for customization buffers.
1002 The value should be a symbol, one of:
1003
1004 brackets: groups nest within each other with big horizontal brackets.
1005 links: groups have links to subgroups."
1006   :type '(radio (const :tag "brackets: Groups nest within each others" brackets)
1007                 (const :tag "links: Group have links to subgroups" links))
1008   :group 'custom-buffer)
1009
1010 (defcustom custom-buffer-done-function 'kill-buffer
1011   "*Function to be used to remove the buffer when the user is done with it.
1012 Choices include `kill-buffer' (the default) and `bury-buffer'.
1013 The function will be called with one argument, the buffer to remove."
1014   :type '(radio (function-item kill-buffer)
1015                 (function-item bury-buffer)
1016                 (function :tag "Other" nil))
1017   :group 'custom-buffer)
1018
1019 (defcustom custom-buffer-indent 3
1020   "Number of spaces to indent nested groups."
1021   :type 'integer
1022   :group 'custom-buffer)
1023
1024 ;;;###autoload
1025 (defun custom-buffer-create (options &optional name description)
1026   "Create a buffer containing OPTIONS.
1027 Optional NAME is the name of the buffer.
1028 OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where
1029 SYMBOL is a customization option, and WIDGET is a widget for editing
1030 that option."
1031   (unless name (setq name "*Customization*"))
1032   (kill-buffer (get-buffer-create name))
1033   (switch-to-buffer (get-buffer-create name))
1034   (custom-buffer-create-internal options description))
1035
1036 ;;;###autoload
1037 (defun custom-buffer-create-other-window (options &optional name description)
1038   "Create a buffer containing OPTIONS.
1039 Optional NAME is the name of the buffer.
1040 OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where
1041 SYMBOL is a customization option, and WIDGET is a widget for editing
1042 that option."
1043   (unless name (setq name "*Customization*"))
1044   (kill-buffer (get-buffer-create name))
1045   (let ((window (selected-window)))
1046     (switch-to-buffer-other-window (get-buffer-create name))
1047     (custom-buffer-create-internal options description)
1048     (select-window window)))
1049
1050 (defcustom custom-reset-button-menu t
1051   "If non-nil, only show a single reset button in customize buffers.
1052 This button will have a menu with all three reset operations."
1053   :type 'boolean
1054   :group 'custom-buffer)
1055
1056 (defconst custom-skip-messages 5)
1057
1058 (defun Custom-buffer-done ()
1059   "Remove current buffer.
1060 This works by calling the function specified by
1061  `custom-buffer-done-function'."
1062   (interactive)
1063   (funcall custom-buffer-done-function (current-buffer)))
1064
1065 (defun custom-buffer-create-buttons ()
1066   (message "Creating customization buttons...")
1067   (widget-insert "\nOperate on everything in this buffer:\n ")
1068   (widget-create 'push-button
1069                  :tag "Set"
1070                  :help-echo "Make your editing in this buffer take effect for this session"
1071                  :action (lambda (widget &optional event)
1072                            (Custom-set)))
1073   (widget-insert " ")
1074   (widget-create 'push-button
1075                  :tag "Save"
1076                  :help-echo "Make your editing in this buffer take effect for future Emacs sessions"
1077                  :action (lambda (widget &optional event)
1078                            (Custom-save)))
1079   (if custom-reset-button-menu
1080       (progn
1081         (widget-insert " ")
1082         (widget-create 'push-button
1083                        :tag "Reset"
1084                        :tag-glyph '("reset-up" "reset-down")
1085                        :help-echo "Show a menu with reset operations"
1086                        :mouse-down-action (lambda (&rest junk) t)
1087                        :action (lambda (widget &optional event)
1088                                  (custom-reset event))))
1089     (widget-insert " ")
1090     (widget-create 'push-button
1091                    :tag "Reset"
1092                    :help-echo "Reset all edited text in this buffer to reflect current values"
1093                    :action 'Custom-reset-current)
1094     (widget-insert " ")
1095     (widget-create 'push-button
1096                    :tag "Reset to Saved"
1097                    :help-echo "Reset all values in this buffer to their saved settings"
1098                    :action 'Custom-reset-saved)
1099     (widget-insert " ")
1100     (widget-create 'push-button
1101                    :tag "Reset to Standard"
1102                    :help-echo "Reset all values in this buffer to their standard settings"
1103                    :action 'Custom-reset-standard))
1104   (widget-insert "  ")
1105   (widget-create 'push-button
1106                  :tag "Done"
1107                  :help-echo "Remove the buffer"
1108                  :action (lambda (widget &optional event)
1109                            (Custom-buffer-done)))
1110   (widget-insert "\n"))
1111
1112 (defcustom custom-novice t
1113   "If non-nil, show help message at top of customize buffers."
1114   :type 'boolean
1115   :group 'custom-buffer)
1116
1117 (defcustom custom-display-global-buttons 'top
1118   "If `nil' don't display the global buttons.  If `top' display at the
1119 beginning of custom buffers.  If `bottom', display at the end."
1120   :type '(choice (const top)
1121                  (const bottom)
1122                  (const :tag "don't" nil))
1123   :group 'custom-buffer)
1124
1125 (defun custom-buffer-create-internal (options &optional description)
1126   (message "Creating customization buffer...")
1127   (custom-mode)
1128   (widget-insert "This is a customization buffer")
1129   (if description
1130       (widget-insert description))
1131   (when custom-novice
1132       (widget-insert ".\n\
1133 Type RET or click button2 on an active field to invoke its action.
1134 Invoke ")
1135       (widget-create 'info-link
1136                      :tag "Help"
1137                      :help-echo "Read the online help"
1138                      "(XEmacs)Easy Customization")
1139       (widget-insert " for more information."))
1140   (widget-insert "\n")
1141   (if (equal custom-display-global-buttons 'top)
1142       (custom-buffer-create-buttons))
1143   (widget-insert "\n")
1144   (message "Creating customization items...")
1145   (setq custom-options
1146         (if (= (length options) 1)
1147             (mapcar (lambda (entry)
1148                       (widget-create (nth 1 entry)
1149                                      :documentation-shown t
1150                                      :custom-state 'unknown
1151                                      :tag (custom-unlispify-tag-name
1152                                            (nth 0 entry))
1153                                      :value (nth 0 entry)))
1154                     options)
1155           (let ((count 0)
1156                 (length (length options)))
1157             (mapcar (lambda (entry)
1158                       (prog2
1159                           (display-message
1160                            'progress
1161                            (format "Creating customization items %2d%%..."
1162                                    (/ (* 100.0 count) length)))
1163                           (widget-create (nth 1 entry)
1164                                          :tag (custom-unlispify-tag-name
1165                                                (nth 0 entry))
1166                                          :value (nth 0 entry))
1167                         (incf count)
1168                         (unless (eq (preceding-char) ?\n)
1169                           (widget-insert "\n"))
1170                         (widget-insert "\n")))
1171                     options))))
1172   (unless (eq (preceding-char) ?\n)
1173     (widget-insert "\n"))
1174   (if (equal custom-display-global-buttons 'bottom)
1175       (custom-buffer-create-buttons))
1176   (display-message 'progress
1177                    (format
1178                     "Creating customization items %2d%%...done" 100))
1179   (unless (eq custom-buffer-style 'tree)
1180     (mapc 'custom-magic-reset custom-options))
1181   (message "Creating customization setup...")
1182   (widget-setup)
1183   (goto-char (point-min))
1184   (message "Creating customization buffer...done"))
1185
1186 \f
1187 ;;; The Tree Browser.
1188
1189 ;;;###autoload
1190 (defun customize-browse (&optional group)
1191   "Create a tree browser for the customize hierarchy."
1192   (interactive)
1193   (unless group
1194     (setq group 'emacs))
1195   (let ((name "*Customize Browser*"))
1196     (kill-buffer (get-buffer-create name))
1197     (switch-to-buffer (get-buffer-create name)))
1198   (custom-mode)
1199   (widget-insert "Square brackets show active fields; type RET or click button2
1200 on an active field to invoke its action.
1201 Invoke [+] below to expand a group, and [-] to collapse an expanded group.\n")
1202   (if custom-browse-only-groups
1203       (widget-insert "Invoke the [Group] button below to edit that item in another window.\n\n")
1204     (widget-insert "Invoke the ")
1205     (widget-create 'item
1206                    :format "%t"
1207                    :tag "[Group]"
1208                    :tag-glyph "folder")
1209     (widget-insert ", ")
1210     (widget-create 'item
1211                    :format "%t"
1212                    :tag "[Face]"
1213                    :tag-glyph "face")
1214     (widget-insert ", and ")
1215     (widget-create 'item
1216                    :format "%t"
1217                    :tag "[Option]"
1218                    :tag-glyph "option")
1219     (widget-insert " buttons below to edit that
1220 item in another window.\n\n"))
1221   (let ((custom-buffer-style 'tree))
1222     (widget-create 'custom-group
1223                    :custom-last t
1224                    :custom-state 'unknown
1225                    :tag (custom-unlispify-tag-name group)
1226                    :value group))
1227   (widget-add-change)
1228   (goto-char (point-min)))
1229
1230 (define-widget 'custom-browse-visibility 'item
1231   "Control visibility of items in the customize tree browser."
1232   :format "%[[%t]%]"
1233   :action 'custom-browse-visibility-action)
1234
1235 (defun custom-browse-visibility-action (widget &rest ignore)
1236   (let ((custom-buffer-style 'tree))
1237     (custom-toggle-parent widget)))
1238
1239 (define-widget 'custom-browse-group-tag 'push-button
1240   "Show parent in other window when activated."
1241   :tag "Group"
1242   :tag-glyph "folder"
1243   :action 'custom-browse-group-tag-action)
1244
1245 (defun custom-browse-group-tag-action (widget &rest ignore)
1246   (let ((parent (widget-get widget :parent)))
1247     (customize-group-other-window (widget-value parent))))
1248
1249 (define-widget 'custom-browse-variable-tag 'push-button
1250   "Show parent in other window when activated."
1251   :tag "Option"
1252   :tag-glyph "option"
1253   :action 'custom-browse-variable-tag-action)
1254
1255 (defun custom-browse-variable-tag-action (widget &rest ignore)
1256   (let ((parent (widget-get widget :parent)))
1257     (customize-variable-other-window (widget-value parent))))
1258
1259 (define-widget 'custom-browse-face-tag 'push-button
1260   "Show parent in other window when activated."
1261   :tag "Face"
1262   :tag-glyph "face"
1263   :action 'custom-browse-face-tag-action)
1264
1265 (defun custom-browse-face-tag-action (widget &rest ignore)
1266   (let ((parent (widget-get widget :parent)))
1267     (customize-face-other-window (widget-value parent))))
1268
1269 (defconst custom-browse-alist '(("   " "space")
1270                                 (" | " "vertical")
1271                                 ("-\\ " "top")
1272                                 (" |-" "middle")
1273                                 (" `-" "bottom")))
1274
1275 (defun custom-browse-insert-prefix (prefix)
1276   "Insert PREFIX.  On XEmacs convert it to line graphics."
1277   ;; #### Unfinished.
1278   (if nil ; (string-match "XEmacs" emacs-version)
1279       (progn
1280         (insert "*")
1281         (while (not (string-equal prefix ""))
1282           (let ((entry (substring prefix 0 3)))
1283             (setq prefix (substring prefix 3))
1284             (let ((overlay (make-overlay (1- (point)) (point) nil t nil))
1285                   (name (nth 1 (assoc entry custom-browse-alist))))
1286               (overlay-put overlay 'end-glyph (widget-glyph-find name entry))
1287               (overlay-put overlay 'start-open t)
1288               (overlay-put overlay 'end-open t)))))
1289     (insert prefix)))
1290
1291 \f
1292 ;;; Modification of Basic Widgets.
1293 ;;
1294 ;; We add extra properties to the basic widgets needed here.  This is
1295 ;; fine, as long as we are careful to stay within out own namespace.
1296 ;;
1297 ;; We want simple widgets to be displayed by default, but complex
1298 ;; widgets to be hidden.
1299
1300 (widget-put (get 'item 'widget-type) :custom-show t)
1301 (widget-put (get 'editable-field 'widget-type)
1302             :custom-show (lambda (widget value)
1303                            ;; This used to call pp-to-string
1304                            (let ((pp (widget-prettyprint-to-string value)))
1305                              (cond ((string-match "\n" pp)
1306                                     nil)
1307                                    ((> (length pp) 40)
1308                                     nil)
1309                                    (t t)))))
1310 (widget-put (get 'menu-choice 'widget-type) :custom-show t)
1311
1312 ;;; The `custom-manual' Widget.
1313
1314 (define-widget 'custom-manual 'info-link
1315   "Link to the manual entry for this customization option."
1316   :tag "Manual")
1317
1318 ;;; The `custom-magic' Widget.
1319
1320 (defgroup custom-magic-faces nil
1321   "Faces used by the magic button."
1322   :group 'custom-faces
1323   :group 'custom-buffer)
1324
1325 (defface custom-invalid-face '((((class color))
1326                                 (:foreground "yellow" :background "red"))
1327                                (t
1328                                 (:bold t :italic t :underline t)))
1329   "Face used when the customize item is invalid."
1330   :group 'custom-magic-faces)
1331
1332 (defface custom-rogue-face '((((class color))
1333                               (:foreground "pink" :background "black"))
1334                              (t
1335                               (:underline t)))
1336   "Face used when the customize item is not defined for customization."
1337   :group 'custom-magic-faces)
1338
1339 (defface custom-modified-face '((((class color))
1340                                  (:foreground "white" :background "blue"))
1341                                 (t
1342                                  (:italic t :bold)))
1343   "Face used when the customize item has been modified."
1344   :group 'custom-magic-faces)
1345
1346 (defface custom-set-face '((((class color))
1347                                 (:foreground "blue" :background "white"))
1348                                (t
1349                                 (:italic t)))
1350   "Face used when the customize item has been set."
1351   :group 'custom-magic-faces)
1352
1353 (defface custom-changed-face '((((class color))
1354                                 (:foreground "white" :background "blue"))
1355                                (t
1356                                 (:italic t)))
1357   "Face used when the customize item has been changed."
1358   :group 'custom-magic-faces)
1359
1360 (defface custom-saved-face '((t (:underline t)))
1361   "Face used when the customize item has been saved."
1362   :group 'custom-magic-faces)
1363
1364 (defconst custom-magic-alist
1365   '((nil "#" underline "uninitialized, you should not see this.")
1366     (unknown "?" italic "unknown, you should not see this.")
1367     (hidden "-" default
1368             "hidden, invoke \"Show\" button in the previous line to show."
1369             "group now hidden, invoke the above \"Show\" button to show contents.")
1370     (invalid "x" custom-invalid-face
1371              "the value displayed for this %c is invalid and cannot be set.")
1372     (modified "*" custom-modified-face
1373               "you have edited the value as text, but you have not set the %c."
1374               "you have edited something in this group, but not set it.")
1375     (set "+" custom-set-face
1376          "you have set this %c, but not saved it for future sessions."
1377          "something in this group has been set, but not saved.")
1378     (changed ":" custom-changed-face
1379              "this %c has been changed outside the customize buffer."
1380              "something in this group has been changed outside customize.")
1381     (saved "!" custom-saved-face
1382            "this %c has been set and saved."
1383            "something in this group has been set and saved.")
1384     (rogue "@" custom-rogue-face
1385            "this %c has not been changed with customize."
1386            "something in this group is not prepared for customization.")
1387     (standard " " nil
1388               "this %c is unchanged from its standard setting."
1389               "visible group members are all at standard settings."))
1390   "Alist of customize option states.
1391 Each entry is of the form (STATE MAGIC FACE ITEM-DESC [ GROUP-DESC ]), where
1392
1393 STATE is one of the following symbols:
1394
1395 `nil'
1396    For internal use, should never occur.
1397 `unknown'
1398    For internal use, should never occur.
1399 `hidden'
1400    This item is not being displayed.
1401 `invalid'
1402    This item is modified, but has an invalid form.
1403 `modified'
1404    This item is modified, and has a valid form.
1405 `set'
1406    This item has been set but not saved.
1407 `changed'
1408    The current value of this item has been changed temporarily.
1409 `saved'
1410    This item is marked for saving.
1411 `rogue'
1412    This item has no customization information.
1413 `standard'
1414    This item is unchanged from the standard setting.
1415
1416 MAGIC is a string used to present that state.
1417
1418 FACE is a face used to present the state.
1419
1420 ITEM-DESC is a string describing the state for options.
1421
1422 GROUP-DESC is a string describing the state for groups.  If this is
1423 left out, ITEM-DESC will be used.
1424
1425 The string %c in either description will be replaced with the
1426 category of the item.  These are `group'. `option', and `face'.
1427
1428 The list should be sorted most significant first.")
1429
1430 (defcustom custom-magic-show 'long
1431   "If non-nil, show textual description of the state.
1432 If `long', show a full-line description, not just one word."
1433   :type '(choice (const :tag "no" nil)
1434                  (const short)
1435                  (const long))
1436   :group 'custom-buffer)
1437
1438 (defcustom custom-magic-show-hidden '(option face)
1439   "Control whether the State button is shown for hidden items.
1440 The value should be a list with the custom categories where the State
1441 button should be visible.  Possible categories are `group', `option',
1442 and `face'."
1443   :type '(set (const group) (const option) (const face))
1444   :group 'custom-buffer)
1445
1446 (defcustom custom-magic-show-button nil
1447   "Show a \"magic\" button indicating the state of each customization option."
1448   :type 'boolean
1449   :group 'custom-buffer)
1450
1451 (define-widget 'custom-magic 'default
1452   "Show and manipulate state for a customization option."
1453   :format "%v"
1454   :action 'widget-parent-action
1455   :notify 'ignore
1456   :value-get 'ignore
1457   :value-create 'custom-magic-value-create
1458   :value-delete 'widget-children-value-delete)
1459
1460 (defun widget-magic-mouse-down-action (widget &optional event)
1461   ;; Non-nil unless hidden.
1462   (not (eq (widget-get (widget-get (widget-get widget :parent) :parent)
1463                        :custom-state)
1464            'hidden)))
1465
1466 (defun custom-magic-value-create (widget)
1467   ;; Create compact status report for WIDGET.
1468   (let* ((parent (widget-get widget :parent))
1469          (state (widget-get parent :custom-state))
1470          (hidden (eq state 'hidden))
1471          (entry (assq state custom-magic-alist))
1472          (magic (nth 1 entry))
1473          (face (nth 2 entry))
1474          (category (widget-get parent :custom-category))
1475          (text (or (and (eq category 'group)
1476                         (nth 4 entry))
1477                    (nth 3 entry)))
1478          (form (widget-get parent :custom-form))
1479          children)
1480     (while (string-match #r"\`\(.*\)%c\(.*\)\'" text)
1481       (setq text (concat (match-string 1 text)
1482                          (symbol-name category)
1483                          (match-string 2 text))))
1484     (when (and custom-magic-show
1485                (or (not hidden)
1486                    (memq category custom-magic-show-hidden)))
1487       (insert "   ")
1488       (when (and (eq category 'group)
1489                  (not (and (eq custom-buffer-style 'links)
1490                            (> (widget-get parent :custom-level) 1))))
1491         (insert-char ?\  (* custom-buffer-indent
1492                             (widget-get parent :custom-level))))
1493       (push (widget-create-child-and-convert
1494              widget 'choice-item
1495              :help-echo "Change the state of this item"
1496              :format (if hidden "%t" "%[%t%]")
1497              :button-prefix 'widget-push-button-prefix
1498              :button-suffix 'widget-push-button-suffix
1499              :mouse-down-action 'widget-magic-mouse-down-action
1500              :tag "State"
1501              ;;:tag-glyph (or hidden '("state-up" "state-down"))
1502              )
1503             children)
1504       (insert ": ")
1505       (let ((start (point)))
1506         (if (eq custom-magic-show 'long)
1507             (insert text)
1508           (insert (symbol-name state)))
1509         (cond ((eq form 'lisp)
1510                (insert " (lisp)"))
1511               ((eq form 'mismatch)
1512                (insert " (mismatch)")))
1513         (put-text-property start (point) 'face 'custom-state-face))
1514       (insert "\n"))
1515     (when (and (eq category 'group)
1516                (not (and (eq custom-buffer-style 'links)
1517                          (> (widget-get parent :custom-level) 1))))
1518       (insert-char ?\  (* custom-buffer-indent
1519                           (widget-get parent :custom-level))))
1520     (when custom-magic-show-button
1521       (when custom-magic-show
1522         (let ((indent (widget-get parent :indent)))
1523           (when indent
1524             (insert-char ?\  indent))))
1525       (push (widget-create-child-and-convert
1526              widget 'choice-item
1527              :mouse-down-action 'widget-magic-mouse-down-action
1528              :button-face face
1529              :button-prefix ""
1530              :button-suffix ""
1531              :help-echo "Change the state"
1532              :format (if hidden "%t" "%[%t%]")
1533              :tag (if (memq form '(lisp mismatch))
1534                       (concat "(" magic ")")
1535                     (concat "[" magic "]")))
1536             children)
1537       (insert " "))
1538     (widget-put widget :children children)))
1539
1540 (defun custom-magic-reset (widget)
1541   "Redraw the :custom-magic property of WIDGET."
1542   (let ((magic (widget-get widget :custom-magic)))
1543     (widget-value-set magic (widget-value magic))))
1544
1545 ;;; The `custom' Widget.
1546
1547 (defface custom-button-face '((t (:bold t)))
1548   "Face used for buttons in customization buffers."
1549   :group 'custom-faces)
1550
1551 (defface custom-documentation-face nil
1552   "Face used for documentation strings in customization buffers."
1553   :group 'custom-faces)
1554
1555 (defface custom-state-face '((((class color)
1556                                (background dark))
1557                               (:foreground "lime green"))
1558                              (((class color)
1559                                (background light))
1560                               (:foreground "dark green"))
1561                              (t nil))
1562   "Face used for State descriptions in the customize buffer."
1563   :group 'custom-faces)
1564
1565 (define-widget 'custom 'default
1566   "Customize a user option."
1567   :format "%v"
1568   :convert-widget 'custom-convert-widget
1569   :notify 'custom-notify
1570   :custom-prefix ""
1571   :custom-level 1
1572   :custom-state 'hidden
1573   :documentation-property 'widget-subclass-responsibility
1574   :value-create 'widget-subclass-responsibility
1575   :value-delete 'widget-children-value-delete
1576   :value-get 'widget-value-value-get
1577   :validate 'widget-children-validate
1578   :match (lambda (widget value) (symbolp value)))
1579
1580 (defun custom-convert-widget (widget)
1581   ;; Initialize :value and :tag from :args in WIDGET.
1582   (let ((args (widget-get widget :args)))
1583     (when args
1584       (widget-put widget :value (widget-apply widget
1585                                               :value-to-internal (car args)))
1586       (widget-put widget :tag (custom-unlispify-tag-name (car args)))
1587       (widget-put widget :args nil)))
1588   widget)
1589
1590 (defun custom-notify (widget &rest args)
1591   "Keep track of changes."
1592   (let ((state (widget-get widget :custom-state)))
1593     (unless (eq state 'modified)
1594       (unless (memq state '(nil unknown hidden))
1595         (widget-put widget :custom-state 'modified))
1596       (custom-magic-reset widget)
1597       (apply 'widget-default-notify widget args))))
1598
1599 (defun custom-redraw (widget)
1600   "Redraw WIDGET with current settings."
1601   (let ((line (count-lines (point-min) (point)))
1602         (column (current-column))
1603         (pos (point))
1604         (from (marker-position (widget-get widget :from)))
1605         (to (marker-position (widget-get widget :to))))
1606     (save-excursion
1607       (widget-value-set widget (widget-value widget))
1608       (custom-redraw-magic widget))
1609     (when (and (>= pos from) (<= pos to))
1610       (condition-case nil
1611           (progn
1612             (if (> column 0)
1613                 (goto-line line)
1614               (goto-line (1+ line)))
1615             (move-to-column column))
1616         (error nil)))))
1617
1618 (defun custom-redraw-magic (widget)
1619   "Redraw WIDGET state with current settings."
1620   (while widget
1621     (let ((magic (widget-get widget :custom-magic)))
1622       (cond (magic
1623              (widget-value-set magic (widget-value magic))
1624              (when (setq widget (widget-get widget :group))
1625                (custom-group-state-update widget)))
1626             (t
1627              (setq widget nil)))))
1628   (widget-setup))
1629
1630 (defun custom-show (widget value)
1631   "Non-nil if WIDGET should be shown with VALUE by default."
1632   (let ((show (widget-get widget :custom-show)))
1633     (cond ((null show)
1634            nil)
1635           ((eq t show)
1636            t)
1637           (t
1638            (funcall show widget value)))))
1639
1640 (defvar custom-load-recursion nil
1641   "Hack to avoid recursive dependencies.")
1642
1643 (defun custom-load-symbol (symbol)
1644   "Load all dependencies for SYMBOL."
1645   (unless custom-load-recursion
1646     (let ((custom-load-recursion t)
1647           (loads (get symbol 'custom-loads))
1648           load)
1649       (while loads
1650         (setq load (car loads)
1651               loads (cdr loads))
1652         (custom-load-symbol-1 load)))))
1653
1654 (defun custom-load-symbol-1 (load)
1655   (cond ((symbolp load)
1656          (condition-case nil
1657              (require load)
1658            (error nil)))
1659         ;; Don't reload a file already loaded.
1660         ((and (boundp 'preloaded-file-list)
1661               (member load preloaded-file-list)))
1662         ((assoc load load-history))
1663         ((assoc (locate-library load) load-history))
1664         (t
1665          (condition-case nil
1666              ;; Without this, we would load cus-edit recursively.
1667              ;; We are still loading it when we call this,
1668              ;; and it is not in load-history yet.
1669              (or (equal load "cus-edit")
1670                  (load-library load))
1671            (error nil)))))
1672
1673 (defvar custom-already-loaded-custom-defines nil
1674   "List of already-loaded `custom-defines' files.")
1675 (defvar custom-define-current-source-file nil)
1676 (defvar custom-warn-when-reloading-necessary nil
1677   "For package-debugging purposes: Warn when an error hit in custom-defines.el.
1678 When this happens, the file from which the defcustom or defgroup was taken
1679 is loaded, and custom-defines.el is then reloaded.  This works in most
1680 cases, but may not be completely safe.  It's better if the package itself
1681 arranges for the necessary functions and variables to be available, using
1682 \;;;###autoload declarations.  When this variable is non-nil, warnings are
1683 issued (with backtrace), to aid in tracking down the problems.")
1684
1685 (defun custom-load-custom-defines (symbol)
1686   "Load custom-defines for SYMBOL."
1687   (unless custom-load-recursion
1688     (let ((custom-load-recursion t)
1689           (loads (get symbol 'custom-loads))
1690           load)
1691       (while loads
1692         (setq load (car loads)
1693               loads (cdr loads))
1694         (let* ((found (locate-library
1695                        (if (symbolp load) (symbol-name load) load)))
1696                (dir (and found (file-name-directory found))))
1697           ;; If we find a custom-defines file, assume the package is smart
1698           ;; enough to have put all its defcustoms and defgroups here, and
1699           ;; load it instead of the file itself.  Otherwise, do it the
1700           ;; hard way.
1701           (if (and found (or (file-exists-p
1702                               (expand-file-name "custom-defines.elc" dir))
1703                              (file-exists-p
1704                               (expand-file-name "custom-defines.el" dir))))
1705               (when (not (member dir custom-already-loaded-custom-defines))
1706                 (push dir custom-already-loaded-custom-defines)
1707                 (custom-load-custom-defines-1 dir))))))))
1708
1709 (defun custom-load-custom-defines-1 (dir)
1710   ;; Actually load the custom-defines.el file in DIR.
1711
1712   ;; If we get an error loading the custom-defines, it may be because of a
1713   ;; reference to something (e.g. a constant) that hasn't yet been defined
1714   ;; yet.  Properly, these should have been marked, so they either go into
1715   ;; the custom-defines.el file or are autoloaded.  But not everyone is so
1716   ;; careful, so for the moment we try to load the file that the
1717   ;; error-generating defcustom came from, and then reload the
1718   ;; custom-defines.el file.  We might loop a number of times if we have
1719   ;; various files that need loading.  If at any point we get an error that
1720   ;; can't be solved just by loading the appropriate file (e.g. we hit the
1721   ;; same error as before, the file is already loaded, etc.) then we signal
1722   ;; it as a real error.
1723   (let (source)
1724     ;; here's how this works: if we get an error loading custom-defines,
1725     ;; the condition handler is called; if we need to reload, we
1726     ;; `return-from', which throws out of the handler and returns nil from
1727     ;; the `block', which continues the while statement, executing the
1728     ;; `load' at the bottom of this function and then entering the block
1729     ;; again.  if the condition handler doesn't throw, but instead returns
1730     ;; normally, `signal' will continue as if nothing happened, and end up
1731     ;; signalling the error normally.
1732     (while
1733         (not
1734          (block custom-load
1735            ;; Use call-with-condition-handler so the error can be seen
1736            ;; with the stack intact.
1737            (call-with-condition-handler
1738                #'(lambda (__custom_load_cd1__)
1739                    (when (and
1740                           custom-define-current-source-file
1741                           (progn
1742                             (setq source (expand-file-name
1743                                           custom-define-current-source-file
1744                                           dir))
1745                             (let ((nondir (file-name-nondirectory source)))
1746                               (and (file-exists-p source)
1747                                    (not (assoc source load-history))
1748                                    (not (assoc nondir load-history))
1749                                    (not (and (boundp 'preloaded-file-list)
1750                                              (member nondir
1751                                                      preloaded-file-list)))))))
1752                      (if custom-warn-when-reloading-necessary
1753                          (lwarn 'custom-defines 'warning
1754                            "Error while loading custom-defines, fetching source and reloading ...\n
1755 Error: %s\n
1756 Source file: %s\n\n
1757 Backtrace follows:\n\n%s"
1758                            (error-message-string __custom_load_cd1__)
1759                            source
1760                            (backtrace-in-condition-handler-eliminating-handler
1761                             '__custom_load_cd1__)))
1762                      (return-from custom-load nil)))
1763                #'(lambda ()
1764                    (load (expand-file-name "custom-defines" dir))))))
1765       ;; we get here only from the `return-from'; see above
1766       (load source))))
1767
1768 (defun custom-load-widget (widget)
1769   "Load all dependencies for WIDGET."
1770   (custom-load-symbol (widget-value widget)))
1771
1772 (defun custom-unloaded-symbol-p (symbol)
1773   "Return non-nil if the dependencies of SYMBOL has not yet been loaded."
1774   (let ((found nil)
1775         (loads (get symbol 'custom-loads))
1776         load)
1777     (while loads
1778       (setq load (car loads)
1779             loads (cdr loads))
1780       (cond ((symbolp load)
1781              (unless (featurep load)
1782                (setq found t)))
1783             ((assoc load load-history))
1784             ((assoc (locate-library load) load-history)
1785              ;; #### WTF???
1786              (message nil))
1787             (t
1788              (setq found t))))
1789     found))
1790
1791 (defun custom-unloaded-widget-p (widget)
1792   "Return non-nil if the dependencies of WIDGET has not yet been loaded."
1793   (custom-unloaded-symbol-p (widget-value widget)))
1794
1795 (defun custom-toggle-hide (widget)
1796   "Toggle visibility of WIDGET."
1797   (custom-load-widget widget)
1798   (let ((state (widget-get widget :custom-state)))
1799     (cond ((memq state '(invalid modified))
1800            (error "There are unset changes"))
1801           ((eq state 'hidden)
1802            (widget-put widget :custom-state 'unknown))
1803           (t
1804            (widget-put widget :documentation-shown nil)
1805            (widget-put widget :custom-state 'hidden)))
1806     (custom-redraw widget)
1807     (widget-setup)))
1808
1809 (defun custom-toggle-parent (widget &rest ignore)
1810   "Toggle visibility of parent of WIDGET."
1811   (custom-toggle-hide (widget-get widget :parent)))
1812
1813 (defun custom-add-see-also (widget &optional prefix)
1814   "Add `See also ...' to WIDGET if there are any links.
1815 Insert PREFIX first if non-nil."
1816   (let* ((symbol (widget-get widget :value))
1817          (links (get symbol 'custom-links))
1818          (many (> (length links) 2))
1819          (buttons (widget-get widget :buttons))
1820          (indent (widget-get widget :indent)))
1821     (when links
1822       (when indent
1823         (insert-char ?\  indent))
1824       (when prefix
1825         (insert prefix))
1826       (insert "See also ")
1827       (while links
1828         (push (widget-create-child-and-convert widget (car links))
1829               buttons)
1830         (setq links (cdr links))
1831         (cond ((null links)
1832                (insert ".\n"))
1833               ((null (cdr links))
1834                (if many
1835                    (insert ", and ")
1836                  (insert " and ")))
1837               (t
1838                (insert ", "))))
1839       (widget-put widget :buttons buttons))))
1840
1841 (defun custom-add-parent-links (widget &optional initial-string)
1842   "Add \"Parent groups: ...\" to WIDGET if the group has parents.
1843 The value if non-nil if any parents were found.
1844 If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
1845   (let ((name (widget-value widget))
1846         (type (widget-type widget))
1847         (buttons (widget-get widget :buttons))
1848         (start (point))
1849         found)
1850     (insert (or initial-string "Parent groups:"))
1851     (maphash (lambda (group ignore)
1852                (let ((entry (assq name (get group 'custom-group))))
1853                  (when (eq (nth 1 entry) type)
1854                    (insert " ")
1855                    (push (widget-create-child-and-convert
1856                           widget 'custom-group-link
1857                           :tag (custom-unlispify-tag-name group)
1858                           group)
1859                          buttons)
1860                    (setq found t))))
1861              custom-group-hash-table)
1862     (widget-put widget :buttons buttons)
1863     (if found
1864         (insert "\n")
1865       (delete-region start (point)))
1866     found))
1867
1868 ;;; The `custom-comment' Widget.
1869
1870 ;; like the editable field
1871 (defface custom-comment-face '((((class grayscale color)
1872                                  (background light))
1873                                 (:background "gray85"))
1874                                (((class grayscale color)
1875                                  (background dark))
1876                                 (:background "dim gray"))
1877                                (t
1878                                 (:italic t)))
1879   "Face used for comments on variables or faces"
1880   :group 'custom-faces)
1881
1882 ;; like font-lock-comment-face
1883 (defface custom-comment-tag-face
1884   '((((class color) (background dark)) (:foreground "gray80"))
1885     (((class color) (background light)) (:foreground "blue4"))
1886     (((class grayscale) (background light))
1887      (:foreground "DimGray" :bold t :italic t))
1888     (((class grayscale) (background dark))
1889      (:foreground "LightGray" :bold t :italic t))
1890     (t (:bold t)))
1891   "Face used for variables or faces comment tags"
1892   :group 'custom-faces)
1893
1894 (define-widget 'custom-comment 'string
1895   "User comment"
1896   :tag "Comment"
1897   :help-echo "Edit a comment here"
1898   :sample-face 'custom-comment-tag-face
1899   :value-face 'custom-comment-face
1900   :value-set 'custom-comment-value-set
1901   :create 'custom-comment-create
1902   :delete 'custom-comment-delete)
1903
1904 (defun custom-comment-create (widget)
1905   (let (ext)
1906     (widget-default-create widget)
1907     (widget-put widget :comment-extent
1908                 (setq ext (make-extent (widget-get widget :from)
1909                                        (widget-get widget :to))))
1910     (set-extent-property ext 'start-open t)
1911     (when (equal (widget-get widget :value) "")
1912       (set-extent-property ext 'invisible t))
1913     ))
1914
1915 (defun custom-comment-delete (widget)
1916   (widget-default-delete widget)
1917   (delete-extent (widget-get widget :comment-extent)))
1918
1919 (defun custom-comment-value-set (widget value)
1920   (widget-default-value-set widget value)
1921   (if (equal value "")
1922       (set-extent-property (widget-get widget :comment-extent)
1923                            'invisible t)
1924     (set-extent-property (widget-get widget :comment-extent)
1925                          'invisible nil)))
1926
1927 ;; Those functions are for the menu. WIDGET is NOT the comment widget. It's
1928 ;; the global custom one
1929 (defun custom-comment-show (widget)
1930   (set-extent-property
1931    (widget-get (widget-get widget :comment-widget) :comment-extent)
1932    'invisible nil))
1933
1934 (defun custom-comment-invisible-p (widget)
1935   (extent-property
1936    (widget-get (widget-get widget :comment-widget) :comment-extent)
1937    'invisible))
1938
1939 ;;; The `custom-variable' Widget.
1940
1941 (defface custom-variable-tag-face '((((class color)
1942                                       (background dark))
1943                                      (:foreground "light blue" :underline t))
1944                                     (((class color)
1945                                       (background light))
1946                                      (:foreground "blue" :underline t))
1947                                     (t (:underline t)))
1948   "Face used for unpushable variable tags."
1949   :group 'custom-faces)
1950
1951 (defface custom-variable-button-face '((t (:underline t :bold t)))
1952   "Face used for pushable variable tags."
1953   :group 'custom-faces)
1954
1955 (defcustom custom-variable-default-form 'edit
1956   "Default form of displaying variable values."
1957   :type '(choice (const edit)
1958                  (const lisp))
1959   :group 'custom-buffer)
1960
1961 (define-widget 'custom-variable 'custom
1962   "Customize variable."
1963   :format "%v"
1964   :help-echo "Set or reset this variable"
1965   :documentation-property 'variable-documentation
1966   :custom-category 'option
1967   :custom-state nil
1968   :custom-menu 'custom-variable-menu-create
1969   :custom-form nil ; defaults to value of `custom-variable-default-form'
1970   :value-create 'custom-variable-value-create
1971   :action 'custom-variable-action
1972   :custom-set 'custom-variable-set
1973   :custom-pre-save 'custom-variable-pre-save
1974   :custom-save 'custom-variable-save
1975   :custom-post-save 'custom-variable-post-save
1976   :custom-reset-current 'custom-redraw
1977   :custom-reset-saved 'custom-variable-reset-saved
1978   :custom-pre-reset-standard 'custom-variable-pre-reset-standard
1979   :custom-reset-standard 'custom-variable-reset-standard
1980   :custom-post-reset-standard 'custom-variable-post-reset-standard)
1981
1982 (defun custom-variable-type (symbol)
1983   "Return a widget suitable for editing the value of SYMBOL.
1984 If SYMBOL has a `custom-type' property, use that.
1985 Otherwise, look up symbol in `custom-guess-type-alist'."
1986   (let* ((type (or (get symbol 'custom-type)
1987                    (and (not (get symbol 'standard-value))
1988                         (custom-guess-type symbol))
1989                    'sexp))
1990          (options (get symbol 'custom-options))
1991          (tmp (if (listp type)
1992                   (copy-sequence type)
1993                 (list type))))
1994     (when options
1995       (widget-put tmp :options options))
1996     tmp))
1997
1998 (defun custom-variable-value-create (widget)
1999   "Here is where you edit the variables value."
2000   (custom-load-widget widget)
2001   (unless (widget-get widget :custom-form)
2002     (widget-put widget :custom-form custom-variable-default-form))
2003   (let* ((buttons (widget-get widget :buttons))
2004          (children (widget-get widget :children))
2005          (form (widget-get widget :custom-form))
2006          (state (widget-get widget :custom-state))
2007          (symbol (widget-get widget :value))
2008          (tag (widget-get widget :tag))
2009          (type (custom-variable-type symbol))
2010          (conv (widget-convert type))
2011          (get (or (get symbol 'custom-get) 'default-value))
2012          (prefix (widget-get widget :custom-prefix))
2013          (last (widget-get widget :custom-last))
2014          (value (if (default-boundp symbol)
2015                     (funcall get symbol)
2016                   (widget-get conv :value))))
2017     ;; If the widget is new, the child determine whether it is hidden.
2018     (cond (state)
2019           ((custom-show type value)
2020            (setq state 'unknown))
2021           (t
2022            (setq state 'hidden)))
2023     ;; If we don't know the state, see if we need to edit it in lisp form.
2024     (when (eq state 'unknown)
2025       (unless (widget-apply conv :match value)
2026         ;; (widget-apply (widget-convert type) :match value)
2027         (setq form 'mismatch)))
2028     ;; Now we can create the child widget.
2029     (cond ((eq custom-buffer-style 'tree)
2030            (insert prefix (if last " `--- " " |--- "))
2031            (push (widget-create-child-and-convert
2032                   widget 'custom-browse-variable-tag)
2033                  buttons)
2034            (insert " " tag "\n")
2035            (widget-put widget :buttons buttons))
2036           ((eq state 'hidden)
2037            ;; Indicate hidden value.
2038            (push (widget-create-child-and-convert
2039                   widget 'item
2040                   :format "%{%t%}: "
2041                   :sample-face 'custom-variable-tag-face
2042                   :tag tag
2043                   :parent widget)
2044                  buttons)
2045            (push (widget-create-child-and-convert
2046                   widget 'visibility
2047                   :help-echo "Show the value of this option"
2048                   :action 'custom-toggle-parent
2049                   nil)
2050                  buttons))
2051           ((memq form '(lisp mismatch))
2052            ;; In lisp mode edit the saved value when possible.
2053            (let* ((value (cond ((get symbol 'saved-value)
2054                                 (car (get symbol 'saved-value)))
2055                                ((get symbol 'standard-value)
2056                                 (car (get symbol 'standard-value)))
2057                                ((default-boundp symbol)
2058                                 (custom-quote (funcall get symbol)))
2059                                (t
2060                                 (custom-quote (widget-get conv :value))))))
2061              (insert (symbol-name symbol) ": ")
2062              (push (widget-create-child-and-convert
2063                     widget 'visibility
2064                     :help-echo "Hide the value of this option"
2065                     :action 'custom-toggle-parent
2066                     t)
2067                    buttons)
2068              (insert " ")
2069              (push (widget-create-child-and-convert
2070                     widget 'sexp
2071                     :button-face 'custom-variable-button-face
2072                     :format "%v"
2073                     :tag (symbol-name symbol)
2074                     :parent widget
2075                     :value value)
2076                    children)))
2077           (t
2078            ;; Edit mode.
2079            (let* ((format (widget-get type :format))
2080                   tag-format value-format)
2081              (while (not (string-match ":" format))
2082                (setq format (signal 'error (list "Bad format" format))))
2083              (setq tag-format (substring format 0 (match-end 0)))
2084              (setq value-format (substring format (match-end 0)))
2085              (push (widget-create-child-and-convert
2086                     widget 'item
2087                     :format tag-format
2088                     :action 'custom-tag-action
2089                     :help-echo "Change value of this option"
2090                     :mouse-down-action 'custom-tag-mouse-down-action
2091                     :button-face 'custom-variable-button-face
2092                     :sample-face 'custom-variable-tag-face
2093                     tag)
2094                    buttons)
2095              (insert " ")
2096              (push (widget-create-child-and-convert
2097                   widget 'visibility
2098                   :help-echo "Hide the value of this option"
2099                   :action 'custom-toggle-parent
2100                   t)
2101                  buttons)
2102              (push (widget-create-child-and-convert
2103                     widget type
2104                     :format value-format
2105                     :value value)
2106                    children))))
2107     (unless (eq custom-buffer-style 'tree)
2108       (unless (eq (preceding-char) ?\n)
2109         (widget-insert "\n"))
2110       ;; Create the magic button.
2111       (let ((magic (widget-create-child-and-convert
2112                     widget 'custom-magic nil)))
2113         (widget-put widget :custom-magic magic)
2114         (push magic buttons))
2115       ;; Insert documentation.
2116       ;; #### NOTE: this is ugly!!!! I need to do update the :buttons property
2117       ;; before the call to `widget-default-format-handler'. Otherwise, I
2118       ;; lose my current `buttons'. This function shouldn't be called like
2119       ;; this anyway. The doc string widget should be added like the others.
2120       ;; --dv
2121       (widget-put widget :buttons buttons)
2122       (widget-default-format-handler widget ?h)
2123       ;; The comment field
2124       (unless (eq state 'hidden)
2125         (let* ((comment (get symbol 'variable-comment))
2126                (comment-widget
2127                 (widget-create-child-and-convert
2128                  widget 'custom-comment
2129                  :parent widget
2130                  :value (or comment ""))))
2131           (widget-put widget :comment-widget comment-widget)
2132           ;; Don't push it !!! Custom assumes that the first child is the
2133           ;; value one.
2134           (setq children (append children (list comment-widget)))))
2135       ;; Update the rest of the properties.
2136       (widget-put widget :custom-form form)
2137       (widget-put widget :children children)
2138       ;; Now update the state.
2139       (if (eq state 'hidden)
2140           (widget-put widget :custom-state state)
2141         (custom-variable-state-set widget))
2142       ;; See also.
2143       (unless (eq state 'hidden)
2144         (when (eq (widget-get widget :custom-level) 1)
2145           (custom-add-parent-links widget))
2146         (custom-add-see-also widget)))))
2147
2148 (defun custom-tag-action (widget &rest args)
2149   "Pass :action to first child of WIDGET's parent."
2150   (apply 'widget-apply (car (widget-get (widget-get widget :parent) :children))
2151          :action args))
2152
2153 (defun custom-tag-mouse-down-action (widget &rest args)
2154   "Pass :mouse-down-action to first child of WIDGET's parent."
2155   (apply 'widget-apply (car (widget-get (widget-get widget :parent) :children))
2156          :mouse-down-action args))
2157
2158 (defun custom-variable-state-set (widget)
2159   "Set the state of WIDGET."
2160   (let* ((symbol (widget-value widget))
2161          (get (or (get symbol 'custom-get) 'default-value))
2162          (value (if (default-boundp symbol)
2163                     (funcall get symbol)
2164                   (widget-get widget :value)))
2165          (comment (get symbol 'variable-comment))
2166          tmp
2167          temp
2168          (state (cond ((progn (setq tmp (get symbol 'customized-value))
2169                               (setq temp
2170                                     (get symbol 'customized-variable-comment))
2171                               (or tmp temp))
2172                        (if (condition-case nil
2173                                (and (equal value (eval (car tmp)))
2174                                     (equal comment temp))
2175                              (error nil))
2176                            'set
2177                          'changed))
2178                       ((progn (setq tmp (get symbol 'saved-value))
2179                               (setq temp (get symbol 'saved-variable-comment))
2180                               (or tmp temp))
2181                        (if (condition-case nil
2182                                (and (equal value (eval (car tmp)))
2183                                     (equal comment temp))
2184                              (error nil))
2185                            'saved
2186                          'changed))
2187                       ((setq tmp (get symbol 'standard-value))
2188                        (if (condition-case nil
2189                                (and (equal value (eval (car tmp)))
2190                                     (equal comment nil))
2191                              (error nil))
2192                            'standard
2193                          'changed))
2194                       (t 'rogue))))
2195     (widget-put widget :custom-state state)))
2196
2197 (defvar custom-variable-menu
2198   `(("Set for Current Session" custom-variable-set
2199      ,#'(lambda (widget)
2200           (eq (widget-get widget :custom-state) 'modified)))
2201     ("Save for Future Sessions" custom-variable-save
2202      ,#'(lambda (widget)
2203           (memq (widget-get widget :custom-state)
2204                 '(modified set changed rogue))))
2205     ("Reset to Current" custom-redraw
2206      ,#'(lambda (widget)
2207           (and (default-boundp (widget-value widget))
2208                (memq (widget-get widget :custom-state) '(modified changed)))))
2209     ("Reset to Saved" custom-variable-reset-saved
2210      ,#'(lambda (widget)
2211           (and (or (get (widget-value widget) 'saved-value)
2212                    (get (widget-value widget) 'saved-variable-comment))
2213                (memq (widget-get widget :custom-state)
2214                      '(modified set changed rogue)))))
2215     ("Reset to Standard Settings" custom-variable-reset-standard
2216      ,#'(lambda (widget)
2217           (and (get (widget-value widget) 'standard-value)
2218                (memq (widget-get widget :custom-state)
2219                      '(modified set changed saved rogue)))))
2220     ("---" ignore ignore)
2221     ("Add Comment" custom-comment-show custom-comment-invisible-p)
2222     ("---" ignore ignore)
2223     ("Don't show as Lisp expression" custom-variable-edit
2224      ,#'(lambda (widget)
2225           (eq (widget-get widget :custom-form) 'lisp)))
2226     ("Show as Lisp expression" custom-variable-edit-lisp
2227      ,#'(lambda (widget)
2228           (eq (widget-get widget :custom-form) 'edit))))
2229   "Alist of actions for the `custom-variable' widget.
2230 Each entry has the form (NAME ACTION FILTER) where NAME is the name of
2231 the menu entry, ACTION is the function to call on the widget when the
2232 menu is selected, and FILTER is a predicate which takes a `custom-variable'
2233 widget as an argument, and returns non-nil if ACTION is valid on that
2234 widget. If FILTER is nil, ACTION is always valid.")
2235
2236 (defun custom-variable-action (widget &optional event)
2237   "Show the menu for `custom-variable' WIDGET.
2238 Optional EVENT is the location for the menu."
2239   (if (eq (widget-get widget :custom-state) 'hidden)
2240       (custom-toggle-hide widget)
2241     (unless (eq (widget-get widget :custom-state) 'modified)
2242       (custom-variable-state-set widget))
2243     ;; Redrawing magic also depresses the state glyph.
2244     ;(custom-redraw-magic widget)
2245     (let* ((completion-ignore-case t)
2246            (answer (widget-choose (concat "Operation on "
2247                                           (custom-unlispify-tag-name
2248                                            (widget-get widget :value)))
2249                                   (custom-menu-filter custom-variable-menu
2250                                                       widget)
2251                                   event)))
2252       (if answer
2253           (funcall answer widget)))))
2254
2255 (defun custom-variable-edit (widget)
2256   "Edit value of WIDGET."
2257   (widget-put widget :custom-state 'unknown)
2258   (widget-put widget :custom-form 'edit)
2259   (custom-redraw widget))
2260
2261 (defun custom-variable-edit-lisp (widget)
2262   "Edit the lisp representation of the value of WIDGET."
2263   (widget-put widget :custom-state 'unknown)
2264   (widget-put widget :custom-form 'lisp)
2265   (custom-redraw widget))
2266
2267 (defun custom-variable-set (widget)
2268   "Set the current value for the variable being edited by WIDGET."
2269   (let* ((form (widget-get widget :custom-form))
2270          (state (widget-get widget :custom-state))
2271          (child (car (widget-get widget :children)))
2272          (symbol (widget-value widget))
2273          (set (or (get symbol 'custom-set) 'set-default))
2274          (comment-widget (widget-get widget :comment-widget))
2275          (comment (widget-value comment-widget))
2276          val)
2277     (cond ((eq state 'hidden)
2278            (error "Cannot set hidden variable"))
2279           ((setq val (widget-apply child :validate))
2280            (goto-char (widget-get val :from))
2281            (error "%s" (widget-get val :error)))
2282           ((memq form '(lisp mismatch))
2283            (when (equal comment "")
2284              (setq comment nil)
2285              ;; Make the comment invisible by hand if it's empty
2286              (set-extent-property (widget-get comment-widget :comment-extent)
2287                                   'invisible t))
2288            (funcall set symbol (eval (setq val (widget-value child))))
2289            (put symbol 'customized-value (list val))
2290            (put symbol 'variable-comment comment)
2291            (put symbol 'customized-variable-comment comment))
2292           (t
2293            (when (equal comment "")
2294              (setq comment nil)
2295              ;; Make the comment invisible by hand if it's empty
2296              (set-extent-property (widget-get comment-widget :comment-extent)
2297                                   'invisible t))
2298            (funcall set symbol (setq val (widget-value child)))
2299            (put symbol 'customized-value (list (custom-quote val)))
2300            (put symbol 'variable-comment comment)
2301            (put symbol 'customized-variable-comment comment)))
2302     (custom-variable-state-set widget)
2303     (custom-redraw-magic widget)))
2304
2305 (defun custom-variable-pre-save (widget)
2306   "Prepare for saving the value for the variable being edited by WIDGET."
2307   (let* ((form (widget-get widget :custom-form))
2308          (state (widget-get widget :custom-state))
2309          (child (car (widget-get widget :children)))
2310          (symbol (widget-value widget))
2311          (set (or (get symbol 'custom-set) 'set-default))
2312          (comment-widget (widget-get widget :comment-widget))
2313          (comment (widget-value comment-widget))
2314          val)
2315     (cond ((eq state 'hidden)
2316            (error "Cannot set hidden variable"))
2317           ((setq val (widget-apply child :validate))
2318            (goto-char (widget-get val :from))
2319            (error "%s" (widget-get val :error)))
2320           ((memq form '(lisp mismatch))
2321            (when (equal comment "")
2322              (setq comment nil)
2323              ;; Make the comment invisible by hand if it's empty
2324              (set-extent-property (widget-get comment-widget :comment-extent)
2325                                   'invisible t))
2326            (put symbol 'saved-value (list (widget-value child)))
2327            (custom-push-theme 'theme-value symbol 'user
2328                               'set (list (widget-value child)))
2329            (funcall set symbol (eval (widget-value child)))
2330            (put symbol 'variable-comment comment)
2331            (put symbol 'saved-variable-comment comment))
2332           (t
2333            (when (equal comment "")
2334              (setq comment nil)
2335              ;; Make the comment invisible by hand if it's empty
2336              (set-extent-property (widget-get comment-widget :comment-extent)
2337                                   'invisible t))
2338            (put symbol
2339                 'saved-value (list (custom-quote (widget-value
2340                                                   child))))
2341            (custom-push-theme 'theme-value symbol 'user
2342                               'set (list (custom-quote (widget-value
2343                                                   child))))
2344            (funcall set symbol (widget-value child))
2345            (put symbol 'variable-comment comment)
2346            (put symbol 'saved-variable-comment comment)))
2347     (put symbol 'customized-value nil)
2348     (put symbol 'customized-variable-comment nil)
2349     ))
2350
2351 (defun custom-variable-post-save (widget)
2352   "Finish saving the variable being edited by WIDGET."
2353   (custom-variable-state-set widget)
2354   (custom-redraw-magic widget))
2355
2356 (defun custom-variable-save (widget)
2357   "Set and save the value for the variable being edited by WIDGET."
2358   (custom-variable-pre-save widget)
2359   (custom-save-all)
2360   (custom-variable-post-save widget))
2361
2362 (defun custom-variable-reset-saved (widget)
2363   "Restore the saved value for the variable being edited by WIDGET."
2364   (let* ((symbol (widget-value widget))
2365          (set (or (get symbol 'custom-set) 'set-default))
2366          (value (get symbol 'saved-value))
2367          (comment (get symbol 'saved-variable-comment)))
2368     (cond ((or value comment)
2369            (put symbol 'variable-comment comment)
2370            (condition-case nil
2371                (funcall set symbol (eval (car value)))
2372              (error nil)))
2373           (t
2374            (signal 'error (list "No saved value for variable" symbol))))
2375     (put symbol 'customized-value nil)
2376     (put symbol 'customized-variable-comment nil)
2377     (widget-put widget :custom-state 'unknown)
2378     ;; This call will possibly make the comment invisible
2379     (custom-redraw widget)))
2380
2381 ;; This function returns non nil if we need to re-save the options --dv.
2382 (defun custom-variable-pre-reset-standard (widget)
2383   "Prepare for restoring the variable being edited by WIDGET to its
2384 standard setting."
2385   (let* ((symbol (widget-value widget))
2386          (set (or (get symbol 'custom-set) 'set-default)))
2387     (if (get symbol 'standard-value)
2388         (funcall set symbol (eval (car (get symbol 'standard-value))))
2389       (signal 'error (list "No standard setting known for variable" symbol)))
2390     (put symbol 'variable-comment nil)
2391     (put symbol 'customized-value nil)
2392     (put symbol 'customized-variable-comment nil)
2393     (when (or (get symbol 'saved-value) (get symbol 'saved-variable-comment))
2394       (put symbol 'saved-value nil)
2395       (custom-push-theme 'theme-value symbol 'user 'reset 'standard)
2396       ;; As a special optimizations we do not (explictly)
2397       ;; save resets to standard when no theme sets the value.
2398       (if (null (cdr (get symbol 'theme-value)))
2399           (put symbol 'theme-value nil))
2400       (put symbol 'saved-variable-comment nil)
2401       widget)
2402     ))
2403
2404 (defun custom-variable-post-reset-standard (widget)
2405   "Finish resetting the variable being edited by WIDGET to its standard
2406 value."
2407   (widget-put widget :custom-state 'unknown)
2408   ;; This call will possibly make the comment invisible
2409   (custom-redraw widget))
2410
2411 (defun custom-variable-reset-standard (widget)
2412   "Restore the standard setting for the variable being edited by WIDGET."
2413   (when (custom-variable-pre-reset-standard widget)
2414     (custom-save-all))
2415   (custom-variable-post-reset-standard widget))
2416
2417 ;;; The `custom-face-edit' Widget.
2418
2419 (define-widget 'custom-face-edit 'checklist
2420   "Edit face attributes."
2421   :format "%t: %v"
2422   :tag "Attributes"
2423   :extra-offset 12
2424   :button-args '(:help-echo "Control whether this attribute has any effect")
2425   :args (mapcar (lambda (att)
2426                   (list 'group
2427                         :inline t
2428                         :sibling-args (widget-get (nth 1 att) :sibling-args)
2429                         (list 'const :format "" :value (nth 0 att))
2430                         (nth 1 att)))
2431                 custom-face-attributes))
2432
2433 ;;; The `custom-display' Widget.
2434
2435 (define-widget 'custom-display 'menu-choice
2436   "Select a display type."
2437   :tag "Display"
2438   :value t
2439   :help-echo "Specify frames where the face attributes should be used"
2440   :args '((const :tag "all" t)
2441           (checklist
2442            :offset 0
2443            :extra-offset 9
2444            :args ((group :sibling-args (:help-echo "Only match the specified window systems")
2445                          (const :format "Type: "
2446                                 type)
2447                          (checklist :inline t
2448                                     :offset 0
2449                                     (const :format "X "
2450                                            :sibling-args (:help-echo "The X11 Window System")
2451                                            x)
2452                                     (const :format "PM "
2453                                            :sibling-args (:help-echo "OS/2 Presentation Manager")
2454                                            pm)
2455                                     (const :format "TTY%n"
2456                                            :sibling-args (:help-echo "Plain text terminals")
2457                                            tty)))
2458                   (group :sibling-args (:help-echo "Only match display or printer devices")
2459                          (const :format "Output: "
2460                                 class)
2461                          (checklist :inline t
2462                                     :offset 0
2463                                     (const :format "Display "
2464                                            :sibling-args (:help-echo "Match display devices")
2465                                            display)
2466                                     (const :format "Printer%n"
2467                                            :sibling-args (:help-echo "Match printer devices")
2468                                            printer)))
2469                   (group :sibling-args (:help-echo "Only match the frames with the specified color support")
2470                          (const :format "Color support: "
2471                                 class)
2472                          (checklist :inline t
2473                                     :offset 0
2474                                     (const :format "Color "
2475                                            :sibling-args (:help-echo "Match color frames")
2476                                            color)
2477                                     (const :format "Grayscale "
2478                                            :sibling-args (:help-echo "Match grayscale frames")
2479                                            grayscale)
2480                                     (const :format "Monochrome%n"
2481                                            :sibling-args (:help-echo "Match frames with no color support")
2482                                            mono)))
2483                   (group :sibling-args (:help-echo "Only match frames with the specified intensity")
2484                          (const :format "Background brightness: "
2485                                 background)
2486                          (checklist :inline t
2487                                     :offset 0
2488                                     (const :format "Light "
2489                                            :sibling-args (:help-echo "Match frames with light backgrounds")
2490                                            light)
2491                                     (const :format "Dark\n"
2492                                            :sibling-args (:help-echo "Match frames with dark backgrounds")
2493                                            dark)))))))
2494
2495 ;;; The `custom-face' Widget.
2496
2497 (defface custom-face-tag-face '((t (:underline t)))
2498   "Face used for face tags."
2499   :group 'custom-faces)
2500
2501 (defcustom custom-face-default-form 'selected
2502   "Default form of displaying face definition."
2503   :type '(choice (const all)
2504                  (const selected)
2505                  (const lisp))
2506   :group 'custom-buffer)
2507
2508 (define-widget 'custom-face 'custom
2509   "Customize face."
2510   :sample-face 'custom-face-tag-face
2511   :help-echo "Set or reset this face"
2512   :documentation-property #'(lambda (face)
2513                               (face-doc-string face))
2514   :value-create 'custom-face-value-create
2515   :action 'custom-face-action
2516   :custom-category 'face
2517   :custom-form nil ; defaults to value of `custom-face-default-form'
2518   :custom-set 'custom-face-set
2519   :custom-pre-save 'custom-face-pre-save
2520   :custom-save 'custom-face-save
2521   :custom-post-save 'custom-face-post-save
2522   :custom-reset-current 'custom-redraw
2523   :custom-reset-saved 'custom-face-reset-saved
2524   :custom-pre-reset-standard 'custom-face-pre-reset-standard
2525   :custom-reset-standard 'custom-face-reset-standard
2526   :custom-post-reset-standard 'custom-face-post-reset-standard
2527   :custom-menu 'custom-face-menu-create)
2528
2529 (define-widget 'custom-face-all 'editable-list
2530   "An editable list of display specifications and attributes."
2531   :entry-format "%i %d %v"
2532   :insert-button-args '(:help-echo "Insert new display specification here")
2533   :append-button-args '(:help-echo "Append new display specification here")
2534   :delete-button-args '(:help-echo "Delete this display specification")
2535   :args '((group :format "%v" custom-display custom-face-edit)))
2536
2537 (defconst custom-face-all (widget-convert 'custom-face-all)
2538   "Converted version of the `custom-face-all' widget.")
2539
2540 (define-widget 'custom-display-unselected 'item
2541   "A display specification that doesn't match the selected display."
2542   :match 'custom-display-unselected-match)
2543
2544 (defun custom-display-unselected-match (widget value)
2545   "Non-nil if VALUE is an unselected display specification."
2546   (not (face-spec-set-match-display value (selected-frame))))
2547
2548 (define-widget 'custom-face-selected 'group
2549   "Edit the attributes of the selected display in a face specification."
2550   :args '((repeat :format ""
2551                   :inline t
2552                   (group custom-display-unselected sexp))
2553           (group (sexp :format "") custom-face-edit)
2554           (repeat :format ""
2555                   :inline t
2556                   sexp)))
2557
2558 (defconst custom-face-selected (widget-convert 'custom-face-selected)
2559   "Converted version of the `custom-face-selected' widget.")
2560
2561 (defun custom-face-value-create (widget)
2562   "Create a list of the display specifications for WIDGET."
2563   (let ((buttons (widget-get widget :buttons))
2564         children
2565         (symbol (widget-get widget :value))
2566         (tag (widget-get widget :tag))
2567         (state (widget-get widget :custom-state))
2568         (begin (point))
2569         (is-last (widget-get widget :custom-last))
2570         (prefix (widget-get widget :custom-prefix)))
2571     (unless tag
2572       (setq tag (prin1-to-string symbol)))
2573     (cond ((eq custom-buffer-style 'tree)
2574            (insert prefix (if is-last " `--- " " |--- "))
2575            (push (widget-create-child-and-convert
2576                   widget 'custom-browse-face-tag)
2577                  buttons)
2578            (insert " " tag "\n")
2579            (widget-put widget :buttons buttons))
2580           (t
2581            ;; Create tag.
2582            (insert tag)
2583            (if (eq custom-buffer-style 'face)
2584                (insert " ")
2585              (widget-specify-sample widget begin (point))
2586              (insert ": "))
2587            ;; Sample.
2588            (and (not (find-face symbol))
2589                 ;; XEmacs cannot display uninitialized faces.
2590                 (make-face symbol))
2591            (push (widget-create-child-and-convert widget 'item
2592                                                   :format "(%{%t%})"
2593                                                   :sample-face symbol
2594                                                   :tag "sample")
2595                  buttons)
2596            ;; Visibility.
2597            (insert " ")
2598            (push (widget-create-child-and-convert
2599                   widget 'visibility
2600                   :help-echo "Hide or show this face"
2601                   :action 'custom-toggle-parent
2602                   (not (eq state 'hidden)))
2603                  buttons)
2604            ;; Magic.
2605            (insert "\n")
2606            (let ((magic (widget-create-child-and-convert
2607                          widget 'custom-magic nil)))
2608              (widget-put widget :custom-magic magic)
2609              (push magic buttons))
2610            ;; Update buttons.
2611            (widget-put widget :buttons buttons)
2612            ;; Insert documentation.
2613            (widget-default-format-handler widget ?h)
2614            ;; The comment field
2615            (unless (eq state 'hidden)
2616              (let* ((comment (get symbol 'face-comment))
2617                     (comment-widget
2618                      (widget-create-child-and-convert
2619                       widget 'custom-comment
2620                       :parent widget
2621                       :value (or comment ""))))
2622                (widget-put widget :comment-widget comment-widget)
2623                (push comment-widget children)))
2624            ;; See also.
2625            (unless (eq state 'hidden)
2626              (when (eq (widget-get widget :custom-level) 1)
2627                (custom-add-parent-links widget))
2628              (custom-add-see-also widget))
2629            ;; Editor.
2630            (unless (eq (preceding-char) ?\n)
2631              (insert "\n"))
2632            (unless (eq state 'hidden)
2633              (message "Creating face editor...")
2634              (custom-load-widget widget)
2635              (unless (widget-get widget :custom-form)
2636                  (widget-put widget :custom-form custom-face-default-form))
2637              (let* ((symbol (widget-value widget))
2638                     (spec (custom-face-get-spec symbol))
2639                     (form (widget-get widget :custom-form))
2640                     (indent (widget-get widget :indent))
2641                     (edit (widget-create-child-and-convert
2642                            widget
2643                            (cond ((and (eq form 'selected)
2644                                        (widget-apply custom-face-selected
2645                                                      :match spec))
2646                                   (when indent (insert-char ?\  indent))
2647                                   'custom-face-selected)
2648                                  ((and (not (eq form 'lisp))
2649                                        (widget-apply custom-face-all
2650                                                      :match spec))
2651                                   'custom-face-all)
2652                                  (t
2653                                   (when indent (insert-char ?\  indent))
2654                                   'sexp))
2655                            :value spec)))
2656                (custom-face-state-set widget)
2657                (push edit children)
2658                (widget-put widget :children children))
2659              (message "Creating face editor...done"))))))
2660
2661 (defvar custom-face-menu
2662   `(("Set for Current Session" custom-face-set)
2663     ("Save for Future Sessions" custom-face-save)
2664     ("Reset to Saved" custom-face-reset-saved
2665      ,#'(lambda (widget)
2666           (or (get (widget-value widget) 'saved-face)
2667               (get (widget-value widget) 'saved-face-comment))))
2668     ("Reset to Standard Setting" custom-face-reset-standard
2669      ,#'(lambda (widget)
2670           (get (widget-value widget) 'face-defface-spec)))
2671     ("---" ignore ignore)
2672     ("Add Comment" custom-comment-show custom-comment-invisible-p)
2673     ("---" ignore ignore)
2674     ("Show all display specs" custom-face-edit-all
2675      ,#'(lambda (widget)
2676           (not (eq (widget-get widget :custom-form) 'all))))
2677     ("Just current attributes" custom-face-edit-selected
2678      ,#'(lambda (widget)
2679           (not (eq (widget-get widget :custom-form) 'selected))))
2680     ("Show as Lisp expression" custom-face-edit-lisp
2681      ,#'(lambda (widget)
2682           (not (eq (widget-get widget :custom-form) 'lisp)))))
2683   "Alist of actions for the `custom-face' widget.
2684 Each entry has the form (NAME ACTION FILTER) where NAME is the name of
2685 the menu entry, ACTION is the function to call on the widget when the
2686 menu is selected, and FILTER is a predicate which takes a `custom-face'
2687 widget as an argument, and returns non-nil if ACTION is valid on that
2688 widget. If FILTER is nil, ACTION is always valid.")
2689
2690 (defun custom-face-edit-selected (widget)
2691   "Edit selected attributes of the value of WIDGET."
2692   (widget-put widget :custom-state 'unknown)
2693   (widget-put widget :custom-form 'selected)
2694   (custom-redraw widget))
2695
2696 (defun custom-face-edit-all (widget)
2697   "Edit all attributes of the value of WIDGET."
2698   (widget-put widget :custom-state 'unknown)
2699   (widget-put widget :custom-form 'all)
2700   (custom-redraw widget))
2701
2702 (defun custom-face-edit-lisp (widget)
2703   "Edit the lisp representation of the value of WIDGET."
2704   (widget-put widget :custom-state 'unknown)
2705   (widget-put widget :custom-form 'lisp)
2706   (custom-redraw widget))
2707
2708 (defun custom-face-state-set (widget)
2709   "Set the state of WIDGET."
2710   (let* ((symbol (widget-value widget))
2711          (comment (get symbol 'face-comment))
2712          tmp temp)
2713     (widget-put widget :custom-state
2714                 (cond ((progn
2715                          (setq tmp (get symbol 'customized-face))
2716                          (setq temp (get symbol 'customized-face-comment))
2717                          (or tmp temp))
2718                        (if (equal temp comment)
2719                            'set
2720                          'changed))
2721                       ((progn
2722                          (setq tmp (get symbol 'saved-face))
2723                          (setq temp (get symbol 'saved-face-comment))
2724                          (or tmp temp))
2725                        (if (equal temp comment)
2726                            'saved
2727                          'changed))
2728                       ((get symbol 'face-defface-spec)
2729                        (if (equal comment nil)
2730                            'standard
2731                          'changed))
2732                       (t
2733                        'rogue)))))
2734
2735 (defun custom-face-action (widget &optional event)
2736   "Show the menu for `custom-face' WIDGET.
2737 Optional EVENT is the location for the menu."
2738   (if (eq (widget-get widget :custom-state) 'hidden)
2739       (custom-toggle-hide widget)
2740     (let* ((completion-ignore-case t)
2741            (symbol (widget-get widget :value))
2742            (answer (widget-choose (concat "Operation on "
2743                                           (custom-unlispify-tag-name symbol))
2744                                   (custom-menu-filter custom-face-menu
2745                                                       widget)
2746                                   event)))
2747       (if answer
2748           (funcall answer widget)))))
2749
2750 (defun custom-face-set (widget)
2751   "Make the face attributes in WIDGET take effect."
2752   (let* ((symbol (widget-value widget))
2753          (child (car (widget-get widget :children)))
2754          (value (widget-value child))
2755          (comment-widget (widget-get widget :comment-widget))
2756          (comment (widget-value comment-widget)))
2757     (when (equal comment "")
2758       (setq comment nil)
2759       ;; Make the comment invisible by hand if it's empty
2760       (set-extent-property (widget-get comment-widget :comment-extent)
2761                            'invisible t))
2762     (put symbol 'customized-face value)
2763     (face-spec-set symbol value nil '(custom))
2764     (put symbol 'customized-face-comment comment)
2765     (put symbol 'face-comment comment)
2766     (custom-face-state-set widget)
2767     (custom-redraw-magic widget)))
2768
2769 (defun custom-face-pre-save (widget)
2770   "Prepare for saving the face being edited by WIDGET."
2771   (let* ((symbol (widget-value widget))
2772          (child (car (widget-get widget :children)))
2773          (value (widget-value child))
2774          (comment-widget (widget-get widget :comment-widget))
2775          (comment (widget-value comment-widget)))
2776     (when (equal comment "")
2777       (setq comment nil)
2778       ;; Make the comment invisible by hand if it's empty
2779       (set-extent-property (widget-get comment-widget :comment-extent)
2780                            'invisible t))
2781     (face-spec-set symbol value nil '(custom))
2782     (put symbol 'saved-face value)
2783     (custom-push-theme 'theme-face symbol 'user 'set value)
2784     (put symbol 'customized-face nil)
2785     (put symbol 'face-comment comment)
2786     (put symbol 'customized-face-comment nil)
2787     (put symbol 'saved-face-comment comment)
2788     ))
2789
2790 (defun custom-face-post-save (widget)
2791   "Finish saving the face being edited by WIDGET."
2792   (custom-face-state-set widget)
2793   (custom-redraw-magic widget))
2794
2795 (defun custom-face-save (widget)
2796   "Save the face being edited by WIDGET."
2797   (custom-face-pre-save widget)
2798   (custom-save-all)
2799   (custom-face-post-save widget))
2800
2801 (defun custom-face-reset-saved (widget)
2802   "Reset the face being edited by WIDGET to its saved value."
2803   (let* ((symbol (widget-value widget))
2804          (child (car (widget-get widget :children)))
2805          (value (get symbol 'saved-face))
2806          (comment (get symbol 'saved-face-comment))
2807          (comment-widget (widget-get widget :comment-widget)))
2808     (unless (or value comment)
2809       (signal 'error (list "No saved value for this face" symbol)))
2810     (put symbol 'customized-face nil)
2811     (put symbol 'customized-face-comment nil)
2812     (face-spec-set symbol value nil '(custom))
2813     (put symbol 'face-comment comment)
2814     (widget-value-set child value)
2815     ;; This call manages the comment visibility
2816     (widget-value-set comment-widget (or comment ""))
2817     (custom-face-state-set widget)
2818     (custom-redraw-magic widget)))
2819
2820 ;; This function returns non nil if we need to re-save the options --dv.
2821 (defun custom-face-pre-reset-standard (widget)
2822   "Prepare for restoring the face edited by WIDGET to its standard
2823 settings."
2824   (let* ((symbol (widget-value widget))
2825          (value (get symbol 'face-defface-spec)))
2826     (unless value
2827       (signal 'error (list "No standard setting for this face" symbol)))
2828     (put symbol 'customized-face nil)
2829     (put symbol 'customized-face-comment nil)
2830     (when (or (get symbol 'saved-face) (get symbol 'saved-face-comment))
2831       (put symbol 'saved-face nil)
2832       (custom-push-theme 'theme-face symbol 'user 'reset 'standard)
2833       ;; Do not explictly save resets to standards without themes.
2834       (if (null (cdr (get symbol 'theme-face)))
2835           (put symbol  'theme-face nil))
2836       (put symbol 'saved-face-comment nil)
2837       widget)
2838     ))
2839
2840 (defun custom-face-post-reset-standard (widget)
2841   "Finish restoring the face edited by WIDGET to its standard settings."
2842   (let* ((symbol (widget-value widget))
2843          (child (car (widget-get widget :children)))
2844          (value (get symbol 'face-defface-spec))
2845          (comment-widget (widget-get widget :comment-widget)))
2846     (face-spec-set symbol value nil '(custom))
2847     (put symbol 'face-comment nil)
2848     (widget-value-set child value)
2849     ;; This call manages the comment visibility
2850     (widget-value-set comment-widget "")
2851     (custom-face-state-set widget)
2852     (custom-redraw-magic widget)
2853     ))
2854
2855 (defun custom-face-reset-standard (widget)
2856   "Restore the face edited by WIDGET to its standard settings."
2857   (when (custom-face-pre-reset-standard widget)
2858     (custom-save-all))
2859   (custom-face-post-reset-standard widget))
2860
2861
2862 ;;; The `face' Widget.
2863
2864 (define-widget 'face 'default
2865   "Select and customize a face."
2866   :convert-widget 'widget-value-convert-widget
2867   :button-prefix 'widget-push-button-prefix
2868   :button-suffix 'widget-push-button-suffix
2869   :format "%t: %[select face%] %v"
2870   :tag "Face"
2871   :value 'default
2872   :value-create 'widget-face-value-create
2873   :value-delete 'widget-face-value-delete
2874   :value-get 'widget-value-value-get
2875   :validate 'widget-children-validate
2876   :action 'widget-face-action
2877   :match (lambda (widget value) (symbolp value)))
2878
2879 (defun widget-face-value-create (widget)
2880   ;; Create a `custom-face' child.
2881   (let* ((symbol (widget-value widget))
2882          (custom-buffer-style 'face)
2883          (child (widget-create-child-and-convert
2884                  widget 'custom-face
2885                  :custom-level nil
2886                  :value symbol)))
2887     (custom-magic-reset child)
2888     (setq custom-options (cons child custom-options))
2889     (widget-put widget :children (list child))))
2890
2891 (defun widget-face-value-delete (widget)
2892   ;; Remove the child from the options.
2893   (let ((child (car (widget-get widget :children))))
2894     (setq custom-options (delq child custom-options))
2895     (widget-children-value-delete widget)))
2896
2897 (defvar face-history nil
2898   "History of entered face names.")
2899
2900 (defun widget-face-action (widget &optional event)
2901   "Prompt for a face."
2902   (let ((answer (completing-read "Face: "
2903                                  (mapcar (lambda (face)
2904                                            (list (symbol-name face)))
2905                                          (face-list))
2906                                  nil nil nil
2907                                  'face-history)))
2908     (unless (zerop (length answer))
2909       (widget-value-set widget (intern answer))
2910       (widget-apply widget :notify widget event)
2911       (widget-setup))))
2912
2913 ;;; The `hook' Widget.
2914
2915 (define-widget 'hook 'list
2916   "A emacs lisp hook"
2917   :value-to-internal (lambda (widget value)
2918                        (if (symbolp value)
2919                            (list value)
2920                          value))
2921   :match (lambda (widget value)
2922            (or (symbolp value)
2923                (widget-group-match widget value)))
2924   :convert-widget 'custom-hook-convert-widget
2925   :tag "Hook")
2926
2927 (defun custom-hook-convert-widget (widget)
2928   ;; Handle `:options'.
2929   (let* ((options (widget-get widget :options))
2930          (other `(editable-list :inline t
2931                                 :entry-format "%i %d%v"
2932                                 (function :format " %v")))
2933          (args (if options
2934                    (list `(checklist :inline t
2935                                      ,@(mapcar (lambda (entry)
2936                                                  `(function-item ,entry))
2937                                                options))
2938                          other)
2939                  (list other))))
2940     (widget-put widget :args args)
2941     widget))
2942
2943 ;;; The `plist' Widget.
2944
2945 (define-widget 'plist 'list
2946   "A property list."
2947   :match (lambda (widget value)
2948            (valid-plist-p value))
2949   :convert-widget 'custom-plist-convert-widget
2950   :tag "Property List")
2951
2952 ;; #### Should handle options better.
2953 (defun custom-plist-convert-widget (widget)
2954   (let* ((options (widget-get widget :options))
2955          (other `(editable-list :inline t
2956                                 (group :inline t
2957                                        (symbol :format "%t: %v "
2958                                                :size 10
2959                                                :tag "Property")
2960                                        (sexp :tag "Value"))))
2961          (args
2962           (if options
2963               `((checklist :inline t
2964                            ,@(mapcar 'custom-plist-process-option options))
2965                 ,other)
2966             (list other))))
2967     (widget-put widget :args args)
2968     widget))
2969
2970 (defun custom-plist-process-option (entry)
2971   `(group :inline t
2972           (const :tag "Property"
2973                  :format "%t: %v "
2974                  :size 10
2975                  ,entry)
2976           (sexp :tag "Value")))
2977
2978 ;;; The `custom-group-link' Widget.
2979
2980 (define-widget 'custom-group-link 'link
2981   "Show parent in other window when activated."
2982   :help-echo 'custom-group-link-help-echo
2983   :action 'custom-group-link-action)
2984
2985 (defun custom-group-link-help-echo (widget)
2986   (concat "Create customization buffer for the `"
2987           (custom-unlispify-tag-name (widget-value widget))
2988           "' group"))
2989
2990 (defun custom-group-link-action (widget &rest ignore)
2991   (customize-group (widget-value widget)))
2992
2993 ;;; The `custom-group' Widget.
2994
2995 (defcustom custom-group-tag-faces nil
2996   ;; In XEmacs, this ought to play games with font size.
2997   "Face used for group tags.
2998 The first member is used for level 1 groups, the second for level 2,
2999 and so forth.  The remaining group tags are shown with
3000 `custom-group-tag-face'."
3001   :type '(repeat face)
3002   :group 'custom-faces)
3003
3004 (defface custom-group-tag-face-1 '((((class color)
3005                                      (background dark))
3006                                     (:foreground "pink" :underline t))
3007                                    (((class color)
3008                                      (background light))
3009                                     (:foreground "red" :underline t))
3010                                    (t (:underline t)))
3011   "Face used for group tags.")
3012
3013 (defface custom-group-tag-face '((((class color)
3014                                    (background dark))
3015                                   (:foreground "light blue" :underline t))
3016                                  (((class color)
3017                                    (background light))
3018                                   (:foreground "blue" :underline t))
3019                                  (t (:underline t)))
3020   "Face used for low level group tags."
3021   :group 'custom-faces)
3022
3023 (define-widget 'custom-group 'custom
3024   "Customize group."
3025   :format "%v"
3026   :sample-face-get 'custom-group-sample-face-get
3027   :documentation-property 'group-documentation
3028   :help-echo "Set or reset all members of this group"
3029   :value-create 'custom-group-value-create
3030   :action 'custom-group-action
3031   :custom-category 'group
3032   :custom-set 'custom-group-set
3033   :custom-pre-save 'custom-group-pre-save
3034   :custom-save 'custom-group-save
3035   :custom-post-save 'custom-group-post-save
3036   :custom-reset-current 'custom-group-reset-current
3037   :custom-reset-saved 'custom-group-reset-saved
3038   :custom-pre-reset-standard 'custom-group-pre-reset-standard
3039   :custom-reset-standard 'custom-group-reset-standard
3040   :custom-post-reset-standard 'custom-group-post-reset-standard
3041   :custom-menu 'custom-group-menu-create)
3042
3043 (defun custom-group-sample-face-get (widget)
3044   ;; Use :sample-face.
3045   (or (nth (1- (widget-get widget :custom-level)) custom-group-tag-faces)
3046       'custom-group-tag-face))
3047
3048 (define-widget 'custom-group-visibility 'visibility
3049   "An indicator and manipulator for hidden group contents."
3050   :create 'custom-group-visibility-create)
3051
3052 (defun custom-group-visibility-create (widget)
3053   (let ((visible (widget-value widget)))
3054     (if visible
3055         (insert "--------")))
3056   (widget-default-create widget))
3057
3058 (defun custom-group-members (symbol groups-only)
3059   "Return SYMBOL's custom group members.
3060 If GROUPS-ONLY non-nil, return only those members that are groups."
3061   (if (not groups-only)
3062       (get symbol 'custom-group)
3063     (let (members)
3064       (dolist (entry (get symbol 'custom-group) (nreverse members))
3065         (when (eq (nth 1 entry) 'custom-group)
3066           (push entry members))))))
3067
3068 (defun custom-group-value-create (widget)
3069   "Insert a customize group for WIDGET in the current buffer."
3070   (let* ((state (widget-get widget :custom-state))
3071          (level (widget-get widget :custom-level))
3072          ;; (indent (widget-get widget :indent))
3073          (prefix (widget-get widget :custom-prefix))
3074          (buttons (widget-get widget :buttons))
3075          (tag (widget-get widget :tag))
3076          (symbol (widget-value widget))
3077          (members (custom-group-members symbol
3078                                         (and (eq custom-buffer-style 'tree)
3079                                              custom-browse-only-groups))))
3080     (cond ((and (eq custom-buffer-style 'tree)
3081                 (eq state 'hidden)
3082                 (or members (custom-unloaded-widget-p widget)))
3083            (custom-browse-insert-prefix prefix)
3084            (push (widget-create-child-and-convert
3085                   widget 'custom-browse-visibility
3086                   ;; :tag-glyph "plus"
3087                   :tag "+")
3088                  buttons)
3089            (insert "-- ")
3090            ;; (widget-glyph-insert nil "-- " "horizontal")
3091            (push (widget-create-child-and-convert
3092                   widget 'custom-browse-group-tag)
3093                  buttons)
3094            (insert " " tag "\n")
3095            (widget-put widget :buttons buttons))
3096           ((and (eq custom-buffer-style 'tree)
3097                 (zerop (length members)))
3098            (custom-browse-insert-prefix prefix)
3099            (insert "[ ]-- ")
3100            ;; (widget-glyph-insert nil "[ ]" "empty")
3101            ;; (widget-glyph-insert nil "-- " "horizontal")
3102            (push (widget-create-child-and-convert
3103                   widget 'custom-browse-group-tag)
3104                  buttons)
3105            (insert " " tag "\n")
3106            (widget-put widget :buttons buttons))
3107           ((eq custom-buffer-style 'tree)
3108            (custom-browse-insert-prefix prefix)
3109            (custom-load-widget widget)
3110            (if (zerop (length members))
3111                (progn
3112                  (custom-browse-insert-prefix prefix)
3113                  (insert "[ ]-- ")
3114                  ;; (widget-glyph-insert nil "[ ]" "empty")
3115                  ;; (widget-glyph-insert nil "-- " "horizontal")
3116                  (push (widget-create-child-and-convert
3117                         widget 'custom-browse-group-tag)
3118                        buttons)
3119                  (insert " " tag "\n")
3120                  (widget-put widget :buttons buttons))
3121              (push (widget-create-child-and-convert
3122                     widget 'custom-browse-visibility
3123                     ;; :tag-glyph "minus"
3124                     :tag "-")
3125                    buttons)
3126              (insert "-\\ ")
3127              ;; (widget-glyph-insert nil "-\\ " "top")
3128              (push (widget-create-child-and-convert
3129                     widget 'custom-browse-group-tag)
3130                    buttons)
3131              (insert " " tag "\n")
3132              (widget-put widget :buttons buttons)
3133              (message "Creating group...")
3134              (let* ((members (custom-sort-items members
3135                               custom-browse-sort-alphabetically
3136                               custom-browse-order-groups))
3137                     (prefixes (widget-get widget :custom-prefixes))
3138                     (custom-prefix-list (custom-prefix-add symbol prefixes))
3139                     (extra-prefix (if (widget-get widget :custom-last)
3140                                       "   "
3141                                     " | "))
3142                     (prefix (concat prefix extra-prefix))
3143                     children entry)
3144                (while members
3145                  (setq entry (car members)
3146                        members (cdr members))
3147                  (push (widget-create-child-and-convert
3148                         widget (nth 1 entry)
3149                         :group widget
3150                         :tag (custom-unlispify-tag-name (nth 0 entry))
3151                         :custom-prefixes custom-prefix-list
3152                         :custom-level (1+ level)
3153                         :custom-last (null members)
3154                         :value (nth 0 entry)
3155                         :custom-prefix prefix)
3156                        children))
3157                (widget-put widget :children (reverse children)))
3158              (message "Creating group...done")))
3159           ;; Nested style.
3160           ((eq state 'hidden)
3161            ;; Create level indicator.
3162            (unless (eq custom-buffer-style 'links)
3163              (insert-char ?\  (* custom-buffer-indent (1- level)))
3164              (insert "-- "))
3165            ;; Create link indicator.
3166            (when (eq custom-buffer-style 'links)
3167              (insert " ")
3168              (push (widget-create-child-and-convert
3169                     widget 'custom-group-link
3170                     :tag "Open"
3171                     :tag-glyph '("open-up" "open-down")
3172                     symbol)
3173                    buttons)
3174              (insert " "))
3175            ;; Create tag.
3176            (let ((begin (point)))
3177              (insert tag)
3178              (widget-specify-sample widget begin (point)))
3179            (insert " group")
3180            ;; Create visibility indicator.
3181            (unless (eq custom-buffer-style 'links)
3182              (insert ": ")
3183              (push (widget-create-child-and-convert
3184                     widget 'custom-group-visibility
3185                     :help-echo "Show members of this group"
3186                     :action 'custom-toggle-parent
3187                     (not (eq state 'hidden)))
3188                    buttons))
3189            (insert " \n")
3190            ;; Create magic button.
3191            (let ((magic (widget-create-child-and-convert
3192                          widget 'custom-magic nil)))
3193              (widget-put widget :custom-magic magic)
3194              (push magic buttons))
3195            ;; Update buttons.
3196            (widget-put widget :buttons buttons)
3197            ;; Insert documentation.
3198            (if (and (eq custom-buffer-style 'links) (> level 1))
3199                (widget-put widget :documentation-indent 0))
3200            (widget-default-format-handler widget ?h))
3201           ;; Nested style.
3202           (t                            ;Visible.
3203            (custom-load-widget widget)
3204            ;; Update members
3205            (setq members (custom-group-members
3206                           symbol (and (eq custom-buffer-style 'tree)
3207                                       custom-browse-only-groups)))
3208            ;; Add parent groups references above the group.
3209            (if t    ;;; This should test that the buffer
3210                     ;;; was made to display a group.
3211                (when (eq level 1)
3212                  (if (custom-add-parent-links widget
3213                                               "Go to parent group:")
3214                      (insert "\n"))))
3215            ;; Create level indicator.
3216            (insert-char ?\  (* custom-buffer-indent (1- level)))
3217            (insert "/- ")
3218            ;; Create tag.
3219            (let ((start (point)))
3220              (insert tag)
3221              (widget-specify-sample widget start (point)))
3222            (insert " group: ")
3223            ;; Create visibility indicator.
3224            (unless (eq custom-buffer-style 'links)
3225              (insert "--------")
3226              (push (widget-create-child-and-convert
3227                     widget 'visibility
3228                     :help-echo "Hide members of this group"
3229                     :action 'custom-toggle-parent
3230                     (not (eq state 'hidden)))
3231                    buttons)
3232              (insert " "))
3233            ;; Create more dashes.
3234            ;; Use 76 instead of 75 to compensate for the temporary "<"
3235            ;; added by `widget-insert'.
3236            (insert-char ?- (- 76 (current-column)
3237                               (* custom-buffer-indent level)))
3238            (insert "\\\n")
3239            ;; Create magic button.
3240            (let ((magic (widget-create-child-and-convert
3241                          widget 'custom-magic
3242                          :indent 0
3243                          nil)))
3244              (widget-put widget :custom-magic magic)
3245              (push magic buttons))
3246            ;; Update buttons.
3247            (widget-put widget :buttons buttons)
3248            ;; Insert documentation.
3249            (widget-default-format-handler widget ?h)
3250            ;; Parent groups.
3251            (if nil  ;;; This should test that the buffer
3252                     ;;; was not made to display a group.
3253                (when (eq level 1)
3254                  (insert-char ?\  custom-buffer-indent)
3255                  (custom-add-parent-links widget)))
3256            (custom-add-see-also widget
3257                                 (make-string (* custom-buffer-indent level)
3258                                              ?\ ))
3259            ;; Members.
3260            (message "Creating group...")
3261            (let* ((members (custom-sort-items members
3262                                               custom-buffer-sort-alphabetically
3263                                               custom-buffer-order-groups))
3264                   (prefixes (widget-get widget :custom-prefixes))
3265                   (custom-prefix-list (custom-prefix-add symbol prefixes))
3266                   (length (length members))
3267                   (count 0)
3268                   (children (mapcar
3269                              (lambda (entry)
3270                                (widget-insert "\n")
3271                                (when (zerop (% count custom-skip-messages))
3272                                  (display-message
3273                                   'progress
3274                                   (format "Creating group members... %2d%%"
3275                                           (/ (* 100.0 count) length))))
3276                                (incf count)
3277                                (prog1
3278                                    (widget-create-child-and-convert
3279                                     widget (nth 1 entry)
3280                                     :group widget
3281                                     :tag (custom-unlispify-tag-name
3282                                           (nth 0 entry))
3283                                     :custom-prefixes custom-prefix-list
3284                                     :custom-level (1+ level)
3285                                     :value (nth 0 entry))
3286                                  (unless (eq (preceding-char) ?\n)
3287                                    (widget-insert "\n"))))
3288                              members)))
3289              (message "Creating group magic...")
3290              (mapc 'custom-magic-reset children)
3291              (message "Creating group state...")
3292              (widget-put widget :children children)
3293              (custom-group-state-update widget)
3294              (message "Creating group... done"))
3295            ;; End line
3296            (insert "\n")
3297            (insert-char ?\  (* custom-buffer-indent (1- level)))
3298            (insert "\\- " (widget-get widget :tag) " group end ")
3299            (insert-char ?- (- 75 (current-column) (* custom-buffer-indent level)))
3300            (insert "/\n")))))
3301
3302 (defvar custom-group-menu
3303   `(("Set for Current Session" custom-group-set
3304      ,#'(lambda (widget)
3305           (eq (widget-get widget :custom-state) 'modified)))
3306     ("Save for Future Sessions" custom-group-save
3307      ,#'(lambda (widget)
3308           (memq (widget-get widget :custom-state) '(modified set))))
3309     ("Reset to Current" custom-group-reset-current
3310      ,#'(lambda (widget)
3311           (memq (widget-get widget :custom-state) '(modified))))
3312     ("Reset to Saved" custom-group-reset-saved
3313      ,#'(lambda (widget)
3314           (memq (widget-get widget :custom-state) '(modified set))))
3315     ("Reset to standard setting" custom-group-reset-standard
3316      ,#'(lambda (widget)
3317           (memq (widget-get widget :custom-state) '(modified set saved)))))
3318   "Alist of actions for the `custom-group' widget.
3319 Each entry has the form (NAME ACTION FILTER) where NAME is the name of
3320 the menu entry, ACTION is the function to call on the widget when the
3321 menu is selected, and FILTER is a predicate which takes a `custom-group'
3322 widget as an argument, and returns non-nil if ACTION is valid on that
3323 widget. If FILTER is nil, ACTION is always valid.")
3324
3325 (defun custom-group-action (widget &optional event)
3326   "Show the menu for `custom-group' WIDGET.
3327 Optional EVENT is the location for the menu."
3328   (if (eq (widget-get widget :custom-state) 'hidden)
3329       (custom-toggle-hide widget)
3330     (let* ((completion-ignore-case t)
3331            (answer (widget-choose (concat "Operation on "
3332                                           (custom-unlispify-tag-name
3333                                            (widget-get widget :value)))
3334                                   (custom-menu-filter custom-group-menu
3335                                                       widget)
3336                                   event)))
3337       (if answer
3338           (funcall answer widget)))))
3339
3340 (defun custom-group-set (widget)
3341   "Set changes in all modified group members."
3342   (let ((children (widget-get widget :children)))
3343     (mapc (lambda (child)
3344             (when (eq (widget-get child :custom-state) 'modified)
3345               (widget-apply child :custom-set)))
3346           children)))
3347
3348 (defun custom-group-pre-save (widget)
3349   "Prepare for saving all modified group members."
3350   (let ((children (widget-get widget :children)))
3351     (mapc (lambda (child)
3352             (when (memq (widget-get child :custom-state) '(modified set))
3353               (widget-apply child :custom-pre-save)))
3354           children)))
3355
3356 (defun custom-group-post-save (widget)
3357   "Save all modified group members."
3358   (let ((children (widget-get widget :children)))
3359     (mapc (lambda (child)
3360             (when (memq (widget-get child :custom-state) '(modified set))
3361               (widget-apply child :custom-post-save)))
3362           children)))
3363
3364 (defun custom-group-save (widget)
3365   "Save all modified group members."
3366   (custom-group-pre-save widget)
3367   (custom-save-all)
3368   (custom-group-post-save widget))
3369
3370 (defun custom-group-reset-current (widget)
3371   "Reset all modified group members."
3372   (let ((children (widget-get widget :children)))
3373     (mapc (lambda (child)
3374             (when (eq (widget-get child :custom-state) 'modified)
3375               (widget-apply child :custom-reset-current)))
3376           children)))
3377
3378 (defun custom-group-reset-saved (widget)
3379   "Reset all modified or set group members."
3380   (let ((children (widget-get widget :children)))
3381     (mapc (lambda (child)
3382             (when (memq (widget-get child :custom-state) '(modified set))
3383               (widget-apply child :custom-reset-saved)))
3384           children)))
3385
3386 ;; This function returns non nil when we need to re-save the options --dv.
3387 (defun custom-group-pre-reset-standard (widget)
3388   "Prepare for resetting all modified, set, or saved group members."
3389   (let ((children (widget-get widget :children))
3390         must-save)
3391     (mapc (lambda (child)
3392             (when (memq (widget-get child :custom-state)
3393                         '(modified set saved))
3394               (and (widget-apply child :custom-pre-reset-standard)
3395                    (setq must-save t))))
3396           children)
3397     must-save
3398     ))
3399
3400 (defun custom-group-post-reset-standard (widget)
3401   "Finish resetting all modified, set, or saved group members."
3402   (let ((children (widget-get widget :children)))
3403     (mapc (lambda (child)
3404             (when (memq (widget-get child :custom-state)
3405                         '(modified set saved))
3406               (widget-apply child :custom-post-reset-standard)))
3407           children)))
3408
3409 (defun custom-group-reset-standard (widget)
3410   "Reset all modified, set, or saved group members."
3411   (when (custom-group-pre-reset-standard widget)
3412     (custom-save-all))
3413   (custom-group-post-reset-standard widget))
3414
3415 (defun custom-group-state-update (widget)
3416   "Update magic."
3417   (unless (eq (widget-get widget :custom-state) 'hidden)
3418     (let* ((children (widget-get widget :children))
3419            (states (mapcar (lambda (child)
3420                              (widget-get child :custom-state))
3421                            children))
3422            (magics custom-magic-alist)
3423            (found 'standard))
3424       (while magics
3425         (let ((magic (car (car magics))))
3426           (if (and (not (eq magic 'hidden))
3427                    (memq magic states))
3428               (setq found magic
3429                     magics nil)
3430             (setq magics (cdr magics)))))
3431       (widget-put widget :custom-state found)))
3432   (custom-magic-reset widget))
3433
3434 (defun custom-save-delete (symbol)
3435   "Delete the call to SYMBOL form in `custom-file'.
3436 Leave point at the location of the call, or after the last expression."
3437   (let ((find-file-hooks nil)
3438         (auto-mode-alist nil))
3439     (set-buffer (find-file-noselect custom-file)))
3440   (goto-char (point-min))
3441   (catch 'found
3442     (while t
3443       (let ((sexp (condition-case nil
3444                       (read (current-buffer))
3445                     (end-of-file (throw 'found nil)))))
3446         (when (and (listp sexp)
3447                    (eq (car sexp) symbol))
3448           (delete-region (save-excursion
3449                            (backward-sexp)
3450                            (point))
3451                          (point))
3452           (throw 'found nil))))))
3453
3454 (defun custom-save-delete-any (&rest symbols)
3455   "Delete the call to any symbol among SYMBOLS in `custom-file'.
3456 Leave the point at the end of the file."
3457   (let ((find-file-hooks nil)
3458         (auto-mode-alist nil))
3459     (set-buffer (find-file-noselect custom-file)))
3460   (goto-char (point-min))
3461   (condition-case nil
3462       (while (not (eobp))
3463         (let ((sexp (read (current-buffer))))
3464           (when (and (listp sexp)
3465                      (memq (car sexp) symbols))
3466             (delete-region (save-excursion
3467                              (backward-sexp)
3468                              (point))
3469                            (point))
3470             (while (and (eolp) (not (eobp)))
3471               (delete-region (point) (prog2 (forward-line 1) (point))))
3472             )))
3473     (end-of-file nil)))
3474
3475 (defsubst custom-save-variable-p (symbol)
3476   "Return non-nil if symbol SYMBOL is a customized variable."
3477   (and (symbolp symbol)
3478        (let ((spec (car-safe (get symbol 'theme-value))))
3479          (or (and spec (eq (car spec) 'user)
3480                   (eq (second spec) 'set))
3481              (get symbol 'saved-variable-comment)
3482              ;; support non-themed vars
3483              (and (null spec) (get symbol 'saved-value))))))
3484
3485 (defun custom-save-variable-internal (symbol)
3486   "Print variable SYMBOL to the standard output.
3487 SYMBOL must be a customized variable."
3488   (let ((requests (get symbol 'custom-requests))
3489         (now (not (or (get symbol 'standard-value)
3490                       (and (not (boundp symbol))
3491                            (not (eq (get symbol 'force-value)
3492                                     'rogue))))))
3493         (comment (get symbol 'saved-variable-comment))
3494         ;; Print everything, no placeholders `...'
3495         (print-level nil)
3496         (print-length nil))
3497     (unless (custom-save-variable-p symbol)
3498       (error 'wrong-type-argument "Not a customized variable" symbol))
3499     (princ "\n '(")
3500     (prin1 symbol)
3501     (princ " ")
3502     ;; This comment stuff is in the way ####
3503     ;; Is (eq (third spec) (car saved-value)) ????
3504     ;; (prin1 (third spec))
3505     ;; XEmacs -- pretty-print value if available
3506     (if (and custom-save-pretty-print
3507              (fboundp 'pp))
3508         ;; To suppress bytecompiler warning
3509         (with-fboundp 'pp
3510           (pp (car (get symbol 'saved-value))))
3511       (prin1 (car (get symbol 'saved-value))))
3512     (when (or now requests comment)
3513       (princ (if now " t" " nil")))
3514     (when (or comment requests)
3515       (princ " ")
3516       (prin1 requests))
3517     (when comment
3518       (princ " ")
3519       (prin1 comment))
3520     (princ ")")))
3521
3522 (defun custom-save-variables ()
3523    "Save all customized variables in `custom-file'."
3524    (save-excursion
3525      (custom-save-delete 'custom-load-themes)
3526      (custom-save-delete 'custom-reset-variables)
3527      (custom-save-delete 'custom-set-variables)
3528      ;; This leaves point at the end of file.
3529      ;; Adrian Aichner <adrian@xemacs.org> stated it is
3530      ;; a bad behavior <npak@ispras.ru>
3531      ;;(custom-save-delete-any 'custom-load-themes
3532      ;;                        'custom-reset-variables
3533      ;;                        'custom-set-variables)
3534      (custom-save-loaded-themes)
3535      (custom-save-resets 'theme-value 'custom-reset-variables nil)
3536      (let ((standard-output (current-buffer))
3537            (sorted-list ()))
3538        ;; First create a sorted list of saved variables.
3539        (mapatoms
3540         (lambda (symbol)
3541           (when (custom-save-variable-p symbol)
3542             (push symbol sorted-list))))
3543        (setq sorted-list (sort sorted-list 'string<))
3544        (unless (bolp)
3545          (princ "\n"))
3546        (princ "(custom-set-variables")
3547        (mapc 'custom-save-variable-internal
3548              sorted-list)
3549        (princ ")")
3550        (unless (looking-at "\n")
3551          (princ "\n")))))
3552
3553 (defvar custom-save-face-ignoring nil)
3554
3555 (defsubst custom-save-face-p (symbol)
3556   "Return non-nil if SYMBOL is a customized face."
3557   (let ((theme-spec (car-safe (get symbol 'theme-face)))
3558         (comment (get symbol 'saved-face-comment)))
3559     (or (and (not (memq symbol custom-save-face-ignoring))
3560              ;; Don't print default face here.
3561              (or (and theme-spec
3562                       (eq (car theme-spec) 'user)
3563                       (eq (second theme-spec) 'set))
3564                  ;; cope with non-themed faces
3565                  (and (null theme-spec)
3566                       (get symbol 'saved-face))))
3567         comment)))
3568
3569 (defun custom-save-face-internal (symbol)
3570   "Print face SYMBOL to the standard output.
3571 SYMBOL must be a customized face."
3572   (let ((comment (get symbol 'saved-face-comment))
3573         (now (not (or (get symbol 'face-defface-spec)
3574               (and (not (find-face symbol))
3575                    (not (eq (get symbol 'force-face) 'rogue))))))
3576         ;; Print everything, no placeholders `...'
3577         (print-level nil)
3578         (print-length nil))
3579     (if (memq symbol custom-save-face-ignoring)
3580         ;; Do nothing
3581         nil
3582       ;; Print face
3583       (unless (custom-save-face-p symbol)
3584         (error 'wrong-type-argument "Not a customized face" symbol))
3585       (princ "\n '(")
3586       (prin1 symbol)
3587       (princ " ")
3588       (prin1 (get symbol 'saved-face))
3589       (if (or comment now)
3590           (princ (if now " t" " nil")))
3591       (when comment
3592           (princ " ")
3593           (prin1 comment))
3594       (princ ")"))))
3595
3596 (defun custom-save-faces ()
3597   "Save all customized faces in `custom-file'."
3598   (save-excursion
3599     (custom-save-delete 'custom-reset-faces)
3600     (custom-save-delete 'custom-set-faces)
3601     ;; This leaves point at the end of file.
3602     ;; Adrian Aichner <adrian@xemacs.org> stated it is
3603     ;; a bad behavior <npak@ispras.ru>
3604     ;;(custom-save-delete-any 'custom-reset-faces
3605     ;;                        'custom-set-faces)
3606     (custom-save-resets 'theme-face 'custom-reset-faces '(default))
3607     (let ((standard-output (current-buffer))
3608           (sorted-list ()))
3609       ;; Create a sorted list of faces
3610       (mapatoms
3611        (lambda (symbol)
3612          (when (custom-save-face-p symbol)
3613            (push symbol sorted-list))))
3614       (setq sorted-list (sort sorted-list 'string<))
3615       (unless (bolp)
3616         (princ "\n"))
3617       (princ "(custom-set-faces")
3618         ;; The default face must be first, since it affects the others.
3619       (when (custom-save-face-p 'default)
3620         (custom-save-face-internal 'default))
3621       (let ((custom-save-face-ignoring '(default)))
3622         (mapc 'custom-save-face-internal
3623               sorted-list))
3624       (princ ")")
3625       (unless (looking-at "\n")
3626         (princ "\n")))))
3627
3628 (defmacro make-custom-save-resets-mapper (property setter)
3629   "Create a mapper for `custom-save-resets'."
3630   `(lambda (object)
3631      (let ((spec (car-safe (get object (quote ,property))))
3632            (print-level nil)
3633            (print-length nil))
3634        (with-boundp '(ignored-special started-writing)
3635          (when (and (not (memq object ignored-special))
3636                     (eq (car spec) 'user)
3637                     (eq (second spec) 'reset))
3638            ;; Do not write reset statements unless necessary.
3639            (unless started-writing
3640              (setq started-writing t)
3641              (unless (bolp)
3642                (princ "\n"))
3643              (princ "(")
3644              (princ (quote ,setter))
3645              (princ "\n '(")
3646              (prin1 object)
3647              (princ " ")
3648              (prin1 (third spec))
3649              (princ ")")))))))
3650
3651 (defconst custom-save-resets-mapper-alist
3652   (eval-when-compile
3653     (list (list 'theme-value 'custom-reset-variables
3654                 (byte-compile
3655                  (make-custom-save-resets-mapper
3656                   'theme-value 'custom-reset-variables)))
3657           (list 'theme-face 'custom-reset-faces
3658                 (byte-compile
3659                  (make-custom-save-resets-mapper
3660                   'theme-face 'custom-reset-faces)))))
3661   "Never use it.
3662 Hashes several heavily used functions for `custom-save-resets'")
3663
3664 (defun custom-save-resets (property setter special)
3665   (declare (special ignored-special))
3666   (let (started-writing ignored-special)
3667     ;; (custom-save-delete setter) Done by caller
3668     (let ((standard-output (current-buffer))
3669           (mapper (let ((triple (assq property custom-save-resets-mapper-alist)))
3670                     (if (and triple (eq (second triple) setter))
3671                         (third triple)
3672                       (make-custom-save-resets-mapper property setter)))))
3673       (mapc mapper special)
3674       (setq ignored-special special)
3675       (mapatoms mapper)
3676       (when started-writing
3677         (princ ")\n")))))
3678
3679
3680 (defun custom-save-loaded-themes ()
3681   (let ((themes (reverse (get 'user 'theme-loads-themes)))
3682         (standard-output (current-buffer))
3683         (print-level nil)
3684         (print-length nil))
3685     (when themes
3686       (unless (bolp) (princ "\n"))
3687       (princ "(custom-load-themes")
3688       (mapc (lambda (theme)
3689               (princ "\n   '")
3690               (prin1 theme)) themes)
3691       (princ " )\n"))))
3692
3693 ;;;###autoload
3694 (defun customize-save-customized ()
3695   "Save all user options which have been set in this session."
3696   (interactive)
3697   (mapatoms (lambda (symbol)
3698               (let ((face (get symbol 'customized-face))
3699                     (value (get symbol 'customized-value))
3700                     (face-comment (get symbol 'customized-face-comment))
3701                     (variable-comment
3702                      (get symbol 'customized-variable-comment)))
3703                 (when face
3704                   (put symbol 'saved-face face)
3705                   (custom-push-theme 'theme-face symbol 'user 'set value)
3706                   (put symbol 'customized-face nil))
3707                 (when value
3708                   (put symbol 'saved-value value)
3709                   (custom-push-theme 'theme-value symbol 'user 'set value)
3710                   (put symbol 'customized-value nil))
3711                 (when variable-comment
3712                   (put symbol 'saved-variable-comment variable-comment)
3713                   (put symbol 'customized-variable-comment nil))
3714                 (when face-comment
3715                   (put symbol 'saved-face-comment face-comment)
3716                   (put symbol 'customized-face-comment nil)))))
3717   ;; We really should update all custom buffers here.
3718   (custom-save-all))
3719
3720 ;;;###autoload
3721 (defun custom-save-all ()
3722   "Save all customizations in `custom-file'."
3723   (let ((inhibit-read-only t))
3724     (custom-save-variables)
3725     (custom-save-faces)
3726     (let ((find-file-hooks nil)
3727           (auto-mode-alist))
3728       (with-current-buffer (find-file-noselect custom-file)
3729         (save-buffer)))))
3730
3731 \f
3732 ;;; The Customize Menu.
3733
3734 ;;; Menu support
3735
3736 (defun custom-face-menu-create (widget symbol)
3737   "Ignoring WIDGET, create a menu entry for customization face SYMBOL."
3738   (vector (custom-unlispify-menu-entry symbol)
3739           `(customize-face ',symbol)
3740           t))
3741
3742 (defun custom-variable-menu-create (widget symbol)
3743   "Ignoring WIDGET, create a menu entry for customization variable SYMBOL."
3744   (let ((type (get symbol 'custom-type)))
3745     (unless (listp type)
3746       (setq type (list type)))
3747     (if (and type (widget-get type :custom-menu))
3748         (widget-apply type :custom-menu symbol)
3749       (vector (custom-unlispify-menu-entry symbol)
3750               `(customize-variable ',symbol)
3751               t))))
3752
3753 ;; Add checkboxes to boolean variable entries.
3754 (widget-put (get 'boolean 'widget-type)
3755             :custom-menu (lambda (widget symbol)
3756                            `[,(custom-unlispify-menu-entry symbol)
3757                              (customize-variable ',symbol)
3758                              :style toggle
3759                              :selected ,symbol]))
3760
3761 ;; XEmacs can create menus dynamically.
3762 (defun custom-group-menu-create (widget symbol)
3763   "Ignoring WIDGET, create a menu entry for customization group SYMBOL."
3764   `( ,(custom-unlispify-menu-entry symbol t)
3765      :filter (lambda (&rest junk)
3766                (let ((item (custom-menu-create ',symbol)))
3767                  (if (listp item)
3768                      (cdr item)
3769                    (list item))))))
3770
3771 ;;;###autoload
3772 (defun custom-menu-create (symbol)
3773   "Create menu for customization group SYMBOL.
3774 The menu is in a format applicable to `easy-menu-define'."
3775   (menu-split-long-menu
3776    (let* ((item (vector (custom-unlispify-menu-entry symbol)
3777                         `(customize-group ',symbol)
3778                         t)))
3779      ;; Item is the entry for creating a menu buffer for SYMBOL.
3780      ;; We may nest, if the menu is not too big.
3781      (custom-load-custom-defines symbol)
3782      (if t ;(< (length (get symbol 'custom-group)) widget-menu-max-size)
3783          ;; The menu is not too big.
3784          (let ((custom-prefix-list (custom-prefix-add symbol
3785                                                       custom-prefix-list))
3786                (members (custom-sort-items (get symbol 'custom-group)
3787                                            custom-menu-sort-alphabetically
3788                                            custom-menu-order-groups)))
3789            ;; Create the menu.
3790            `(,(custom-unlispify-menu-entry symbol t)
3791              ,item
3792              "--"
3793              ,@(mapcar (lambda (entry)
3794                          (widget-apply (if (listp (nth 1 entry))
3795                                            (nth 1 entry)
3796                                          (list (nth 1 entry)))
3797                                        :custom-menu (nth 0 entry)))
3798                        members)))
3799        ; else ;; The menu was too big.
3800        item
3801        ))))
3802
3803 ;;;###autoload
3804 (defun customize-menu-create (symbol &optional name)
3805   "Return a customize menu for customization group SYMBOL.
3806 If optional NAME is given, use that as the name of the menu.
3807 Otherwise the menu will be named `Customize'.
3808 The format is suitable for use with `easy-menu-define'."
3809   (unless name
3810     (setq name "Customize"))
3811   `(,name
3812     :filter (lambda (&rest junk)
3813               (cdr (custom-menu-create ',symbol)))))
3814
3815 ;;; The Custom Mode.
3816
3817 (defvar custom-mode-map nil
3818   "Keymap for `custom-mode'.")
3819
3820 (unless custom-mode-map
3821   (setq custom-mode-map (make-sparse-keymap))
3822   (set-keymap-parents custom-mode-map widget-keymap)
3823   (suppress-keymap custom-mode-map)
3824   (define-key custom-mode-map " " 'scroll-up)
3825   (define-key custom-mode-map [delete] 'scroll-down)
3826   (define-key custom-mode-map "q" 'Custom-buffer-done)
3827   (define-key custom-mode-map "u" 'Custom-goto-parent)
3828   (define-key custom-mode-map "n" 'widget-forward)
3829   (define-key custom-mode-map "p" 'widget-backward))
3830
3831 (easy-menu-define Custom-mode-menu
3832     custom-mode-map
3833   "Menu used in customization buffers."
3834   `("Custom"
3835     ,(customize-menu-create 'customize)
3836     ["Set" Custom-set t]
3837     ["Save" Custom-save t]
3838     ["Reset to Current" Custom-reset-current t]
3839     ["Reset to Saved" Custom-reset-saved t]
3840     ["Reset to Standard Settings" Custom-reset-standard t]
3841     ["Info" (Info-goto-node "(xemacs)Easy Customization") t]))
3842
3843 (defun Custom-goto-parent ()
3844   "Go to the parent group listed at the top of this buffer.
3845 If several parents are listed, go to the first of them."
3846   (interactive)
3847   (save-excursion
3848     (goto-char (point-min))
3849     (if (search-forward "\nGo to parent group: " nil t)
3850         (let* ((button (get-char-property (point) 'button))
3851                (parent (downcase (widget-get  button :tag))))
3852           (customize-group parent)))))
3853
3854 (defcustom custom-mode-hook nil
3855   "Hook called when entering custom-mode."
3856   :type 'hook
3857   :group 'custom-buffer )
3858
3859 (defun custom-state-buffer-message (widget)
3860   (if (eq (widget-get (widget-get widget :parent) :custom-state) 'modified)
3861       (message
3862        "To install your edits, invoke [State] and choose the Set operation")))
3863
3864 (defun custom-mode ()
3865   "Major mode for editing customization buffers.
3866
3867 The following commands are available:
3868
3869 Move to next button or editable field.     \\[widget-forward]
3870 Move to previous button or editable field. \\[widget-backward]
3871 \\<widget-field-keymap>\
3872 Complete content of editable text field.   \\[widget-complete]
3873 \\<custom-mode-map>\
3874 Invoke button under point.                 \\[widget-button-press]
3875 Set all modifications.                     \\[Custom-set]
3876 Make all modifications default.            \\[Custom-save]
3877 Reset all modified options.                \\[Custom-reset-current]
3878 Reset all modified or set options.         \\[Custom-reset-saved]
3879 Reset all options.                         \\[Custom-reset-standard]
3880
3881 Entry to this mode calls the value of `custom-mode-hook'
3882 if that value is non-nil."
3883   (kill-all-local-variables)
3884   (setq major-mode 'custom-mode
3885         mode-name "Custom")
3886   (use-local-map custom-mode-map)
3887   (easy-menu-add Custom-mode-menu)
3888   (make-local-variable 'custom-options)
3889   (make-local-variable 'widget-documentation-face)
3890   (setq widget-documentation-face 'custom-documentation-face)
3891   (make-local-variable 'widget-button-face)
3892   (setq widget-button-face 'custom-button-face)
3893   (make-local-hook 'widget-edit-functions)
3894   (add-hook 'widget-edit-functions 'custom-state-buffer-message nil t)
3895   (run-hooks 'custom-mode-hook))
3896
3897 \f
3898 ;;;###autoload
3899 (defun custom-migrate-custom-file (new-custom-file-name)
3900   "Migrate custom file from home directory."
3901   (mapc 'custom-save-delete
3902         '(custom-load-themes custom-reset-variables
3903                              custom-set-variables
3904                              custom-set-faces
3905                              custom-reset-faces))
3906   (with-current-buffer (find-file-noselect custom-file)
3907     (save-buffer))
3908   (setq custom-file new-custom-file-name)
3909   (custom-save-all))
3910 \f
3911 ;;; The End.
3912
3913 (provide 'cus-edit)
3914
3915 ;; cus-edit.el ends here