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