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