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