(reveal-open-new-overlays): New extracted fun.
[bpt/emacs.git] / lisp / cus-edit.el
CommitLineData
e8af40ee 1;;; cus-edit.el --- tools for customizing Emacs and Lisp packages
d543e20b 2;;
0d30b337
TTN
3;; Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
4;; 2005 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
d478e69d
MB
2269(defface custom-comment '((((class grayscale color)
2270 (background light))
2271 (:background "gray85"))
2272 (((class grayscale color)
2273 (background dark))
2274 (:background "dim gray"))
2275 (t
2276 (:slant italic)))
d3d4df42
DL
2277 "Face used for comments on variables or faces"
2278 :version "21.1"
2279 :group 'custom-faces)
d478e69d
MB
2280;; backward-compatibility alias
2281(put 'custom-comment-face 'face-alias 'custom-comment)
d3d4df42
DL
2282
2283;; like font-lock-comment-face
d478e69d 2284(defface custom-comment-tag
d3d4df42
DL
2285 '((((class color) (background dark)) (:foreground "gray80"))
2286 (((class color) (background light)) (:foreground "blue4"))
2287 (((class grayscale) (background light))
b5555381 2288 (:foreground "DimGray" :weight bold :slant italic))
d3d4df42 2289 (((class grayscale) (background dark))
b5555381
RS
2290 (:foreground "LightGray" :weight bold :slant italic))
2291 (t (:weight bold)))
d3d4df42
DL
2292 "Face used for variables or faces comment tags"
2293 :group 'custom-faces)
d478e69d
MB
2294;; backward-compatibility alias
2295(put 'custom-comment-tag-face 'face-alias 'custom-comment-tag)
d3d4df42
DL
2296
2297(define-widget 'custom-comment 'string
164cfaeb 2298 "User comment."
d3d4df42 2299 :tag "Comment"
164cfaeb 2300 :help-echo "Edit a comment here."
d3d4df42
DL
2301 :sample-face 'custom-comment-tag-face
2302 :value-face 'custom-comment-face
164cfaeb
DL
2303 :shown nil
2304 :create 'custom-comment-create)
d3d4df42
DL
2305
2306(defun custom-comment-create (widget)
164cfaeb 2307 (let* ((null-comment (equal "" (widget-value widget))))
6171a945
DL
2308 (if (or (widget-get (widget-get widget :parent) :comment-shown)
2309 (not null-comment))
2310 (widget-default-create widget)
2311 ;; `widget-default-delete' expects markers in these slots --
2312 ;; maybe it shouldn't.
2313 (widget-put widget :from (point-marker))
2314 (widget-put widget :to (point-marker)))))
164cfaeb
DL
2315
2316(defun custom-comment-hide (widget)
2317 (widget-put (widget-get widget :parent) :comment-shown nil))
d3d4df42
DL
2318
2319;; Those functions are for the menu. WIDGET is NOT the comment widget. It's
2320;; the global custom one
2321(defun custom-comment-show (widget)
164cfaeb
DL
2322 (widget-put widget :comment-shown t)
2323 (custom-redraw widget)
2324 (widget-setup))
d3d4df42
DL
2325
2326(defun custom-comment-invisible-p (widget)
164cfaeb
DL
2327 (let ((val (widget-value (widget-get widget :comment-widget))))
2328 (and (equal "" val)
2329 (not (widget-get widget :comment-shown)))))
d3d4df42 2330
d543e20b
PA
2331;;; The `custom-variable' Widget.
2332
2365594b
DL
2333;; When this was underlined blue, users confused it with a
2334;; Mosaic-style hyperlink...
d478e69d 2335(defface custom-variable-tag
16b20ed9
GM
2336 `((((class color)
2337 (background dark))
b5555381 2338 (:foreground "light blue" :weight bold :height 1.2 :inherit variable-pitch))
ea81d57e
DN
2339 (((min-colors 88) (class color)
2340 (background light))
2341 (:foreground "blue1" :weight bold :height 1.2 :inherit variable-pitch))
16b20ed9
GM
2342 (((class color)
2343 (background light))
29a82d4c 2344 (:foreground "blue" :weight bold :height 1.2 :inherit variable-pitch))
b5555381 2345 (t (:weight bold)))
d543e20b 2346 "Face used for unpushable variable tags."
bd042c03 2347 :group 'custom-faces)
d478e69d
MB
2348;; backward-compatibility alias
2349(put 'custom-variable-tag-face 'face-alias 'custom-variable-tag)
d543e20b 2350
d478e69d 2351(defface custom-variable-button '((t (:underline t :weight bold)))
d543e20b 2352 "Face used for pushable variable tags."
bd042c03 2353 :group 'custom-faces)
d478e69d
MB
2354;; backward-compatibility alias
2355(put 'custom-variable-button-face 'face-alias 'custom-variable-button)
d543e20b 2356
d64478da
KH
2357(defcustom custom-variable-default-form 'edit
2358 "Default form of displaying variable values."
2359 :type '(choice (const edit)
2360 (const lisp))
cd32a7ba
DN
2361 :group 'custom-buffer
2362 :version "20.3")
d64478da 2363
a075569a
LT
2364(defun custom-variable-documentation (variable)
2365 "Return documentation of VARIABLE for use in Custom buffer.
2366Normally just return the docstring. But if VARIABLE automatically
2367becomes buffer local when set, append a message to that effect."
2368 (if (and (local-variable-if-set-p variable)
2369 (or (not (local-variable-p variable))
2370 (with-temp-buffer
2371 (local-variable-if-set-p variable))))
2372 (concat (documentation-property variable 'variable-documentation)
2373 "\n
2374This variable automatically becomes buffer-local when set outside Custom.
2375However, setting it through Custom sets the default value.")
2376 (documentation-property variable 'variable-documentation)))
2377
d543e20b
PA
2378(define-widget 'custom-variable 'custom
2379 "Customize variable."
944c91b6 2380 :format "%v"
d543e20b 2381 :help-echo "Set or reset this variable."
a075569a 2382 :documentation-property #'custom-variable-documentation
9097aeb7 2383 :custom-category 'option
d543e20b
PA
2384 :custom-state nil
2385 :custom-menu 'custom-variable-menu-create
d64478da 2386 :custom-form nil ; defaults to value of `custom-variable-default-form'
d543e20b
PA
2387 :value-create 'custom-variable-value-create
2388 :action 'custom-variable-action
2389 :custom-set 'custom-variable-set
2390 :custom-save 'custom-variable-save
2391 :custom-reset-current 'custom-redraw
2392 :custom-reset-saved 'custom-variable-reset-saved
4f985043
RS
2393 :custom-reset-standard 'custom-variable-reset-standard
2394 :custom-standard-value 'custom-variable-standard-value)
d543e20b 2395
bd042c03
PA
2396(defun custom-variable-type (symbol)
2397 "Return a widget suitable for editing the value of SYMBOL.
d3d4df42 2398If SYMBOL has a `custom-type' property, use that.
bd042c03
PA
2399Otherwise, look up symbol in `custom-guess-type-alist'."
2400 (let* ((type (or (get symbol 'custom-type)
25ac13b5 2401 (and (not (get symbol 'standard-value))
bd042c03
PA
2402 (custom-guess-type symbol))
2403 'sexp))
2404 (options (get symbol 'custom-options))
2405 (tmp (if (listp type)
46fa5a83 2406 (copy-sequence type)
bd042c03
PA
2407 (list type))))
2408 (when options
2409 (widget-put tmp :options options))
2410 tmp))
2411
d543e20b 2412(defun custom-variable-value-create (widget)
164cfaeb 2413 "Here is where you edit the variable's value."
d543e20b 2414 (custom-load-widget widget)
d64478da
KH
2415 (unless (widget-get widget :custom-form)
2416 (widget-put widget :custom-form custom-variable-default-form))
d543e20b
PA
2417 (let* ((buttons (widget-get widget :buttons))
2418 (children (widget-get widget :children))
2419 (form (widget-get widget :custom-form))
2420 (state (widget-get widget :custom-state))
2421 (symbol (widget-get widget :value))
d543e20b 2422 (tag (widget-get widget :tag))
bd042c03 2423 (type (custom-variable-type symbol))
d543e20b 2424 (conv (widget-convert type))
6d528fc5 2425 (get (or (get symbol 'custom-get) 'default-value))
944c91b6
PA
2426 (prefix (widget-get widget :custom-prefix))
2427 (last (widget-get widget :custom-last))
d543e20b 2428 (value (if (default-boundp symbol)
6d528fc5 2429 (funcall get symbol)
d543e20b 2430 (widget-get conv :value))))
164cfaeb 2431 ;; If the widget is new, the child determines whether it is hidden.
d543e20b
PA
2432 (cond (state)
2433 ((custom-show type value)
2434 (setq state 'unknown))
2435 (t
2436 (setq state 'hidden)))
2437 ;; If we don't know the state, see if we need to edit it in lisp form.
2438 (when (eq state 'unknown)
2439 (unless (widget-apply conv :match value)
2440 ;; (widget-apply (widget-convert type) :match value)
f985c5f7 2441 (setq form 'mismatch)))
d543e20b 2442 ;; Now we can create the child widget.
944c91b6 2443 (cond ((eq custom-buffer-style 'tree)
da5ec617 2444 (insert prefix (if last " `--- " " |--- "))
944c91b6 2445 (push (widget-create-child-and-convert
c953515e 2446 widget 'custom-browse-variable-tag)
944c91b6
PA
2447 buttons)
2448 (insert " " tag "\n")
2449 (widget-put widget :buttons buttons))
2450 ((eq state 'hidden)
d543e20b 2451 ;; Indicate hidden value.
d3d4df42 2452 (push (widget-create-child-and-convert
d543e20b 2453 widget 'item
3acab5ef 2454 :format "%{%t%}: "
b62c92bb 2455 :sample-face 'custom-variable-tag-face
d543e20b
PA
2456 :tag tag
2457 :parent widget)
3acab5ef 2458 buttons)
d3d4df42 2459 (push (widget-create-child-and-convert
3acab5ef 2460 widget 'visibility
8697863a 2461 :help-echo "Show the value of this option."
7f663295 2462 :off "Show Value"
3acab5ef
PA
2463 :action 'custom-toggle-parent
2464 nil)
2465 buttons))
f985c5f7 2466 ((memq form '(lisp mismatch))
d543e20b
PA
2467 ;; In lisp mode edit the saved value when possible.
2468 (let* ((value (cond ((get symbol 'saved-value)
2469 (car (get symbol 'saved-value)))
25ac13b5
PA
2470 ((get symbol 'standard-value)
2471 (car (get symbol 'standard-value)))
d543e20b 2472 ((default-boundp symbol)
6d528fc5 2473 (custom-quote (funcall get symbol)))
d543e20b
PA
2474 (t
2475 (custom-quote (widget-get conv :value))))))
3acab5ef 2476 (insert (symbol-name symbol) ": ")
d3d4df42 2477 (push (widget-create-child-and-convert
944c91b6
PA
2478 widget 'visibility
2479 :help-echo "Hide the value of this option."
7f663295
RS
2480 :on "Hide Value"
2481 :off "Show Value"
944c91b6
PA
2482 :action 'custom-toggle-parent
2483 t)
2484 buttons)
3acab5ef 2485 (insert " ")
d3d4df42
DL
2486 (push (widget-create-child-and-convert
2487 widget 'sexp
d543e20b 2488 :button-face 'custom-variable-button-face
3acab5ef 2489 :format "%v"
d543e20b
PA
2490 :tag (symbol-name symbol)
2491 :parent widget
2492 :value value)
2493 children)))
2494 (t
2495 ;; Edit mode.
3acab5ef
PA
2496 (let* ((format (widget-get type :format))
2497 tag-format value-format)
2498 (unless (string-match ":" format)
896a6a5d 2499 (error "Bad format"))
3acab5ef
PA
2500 (setq tag-format (substring format 0 (match-end 0)))
2501 (setq value-format (substring format (match-end 0)))
2502 (push (widget-create-child-and-convert
d3d4df42 2503 widget 'item
3acab5ef
PA
2504 :format tag-format
2505 :action 'custom-tag-action
8697863a 2506 :help-echo "Change value of this option."
3acab5ef
PA
2507 :mouse-down-action 'custom-tag-mouse-down-action
2508 :button-face 'custom-variable-button-face
b62c92bb 2509 :sample-face 'custom-variable-tag-face
3acab5ef
PA
2510 tag)
2511 buttons)
2512 (insert " ")
d3d4df42 2513 (push (widget-create-child-and-convert
164cfaeb
DL
2514 widget 'visibility
2515 :help-echo "Hide the value of this option."
7f663295
RS
2516 :on "Hide Value"
2517 :off "Show Value"
164cfaeb
DL
2518 :action 'custom-toggle-parent
2519 t)
2520 buttons)
3acab5ef 2521 (push (widget-create-child-and-convert
d3d4df42 2522 widget type
3acab5ef
PA
2523 :format value-format
2524 :value value)
2525 children))))
944c91b6 2526 (unless (eq custom-buffer-style 'tree)
944c91b6
PA
2527 (unless (eq (preceding-char) ?\n)
2528 (widget-insert "\n"))
944c91b6
PA
2529 ;; Create the magic button.
2530 (let ((magic (widget-create-child-and-convert
2531 widget 'custom-magic nil)))
2532 (widget-put widget :custom-magic magic)
2533 (push magic buttons))
164cfaeb 2534 ;; ### NOTE: this is ugly!!!! I need to update the :buttons property
d3d4df42
DL
2535 ;; before the call to `widget-default-format-handler'. Otherwise, I
2536 ;; loose my current `buttons'. This function shouldn't be called like
2537 ;; this anyway. The doc string widget should be added like the others.
2538 ;; --dv
944c91b6 2539 (widget-put widget :buttons buttons)
7f663295 2540 (insert "\n")
944c91b6
PA
2541 ;; Insert documentation.
2542 (widget-default-format-handler widget ?h)
d3d4df42
DL
2543
2544 ;; The comment field
2545 (unless (eq state 'hidden)
2546 (let* ((comment (get symbol 'variable-comment))
2547 (comment-widget
2548 (widget-create-child-and-convert
2549 widget 'custom-comment
2550 :parent widget
2551 :value (or comment ""))))
2552 (widget-put widget :comment-widget comment-widget)
2553 ;; Don't push it !!! Custom assumes that the first child is the
2554 ;; value one.
2555 (setq children (append children (list comment-widget)))))
2556 ;; Update the rest of the properties properties.
2557 (widget-put widget :custom-form form)
2558 (widget-put widget :children children)
2559 ;; Now update the state.
2560 (if (eq state 'hidden)
2561 (widget-put widget :custom-state state)
2562 (custom-variable-state-set widget))
944c91b6
PA
2563 ;; See also.
2564 (unless (eq state 'hidden)
2565 (when (eq (widget-get widget :custom-level) 1)
2566 (custom-add-parent-links widget))
2567 (custom-add-see-also widget)))))
d543e20b 2568
3acab5ef
PA
2569(defun custom-tag-action (widget &rest args)
2570 "Pass :action to first child of WIDGET's parent."
2571 (apply 'widget-apply (car (widget-get (widget-get widget :parent) :children))
2572 :action args))
2573
2574(defun custom-tag-mouse-down-action (widget &rest args)
2575 "Pass :mouse-down-action to first child of WIDGET's parent."
2576 (apply 'widget-apply (car (widget-get (widget-get widget :parent) :children))
2577 :mouse-down-action args))
2578
d543e20b
PA
2579(defun custom-variable-state-set (widget)
2580 "Set the state of WIDGET."
2581 (let* ((symbol (widget-value widget))
6d528fc5 2582 (get (or (get symbol 'custom-get) 'default-value))
d543e20b 2583 (value (if (default-boundp symbol)
6d528fc5 2584 (funcall get symbol)
d543e20b 2585 (widget-get widget :value)))
d3d4df42 2586 (comment (get symbol 'variable-comment))
d543e20b 2587 tmp
d3d4df42
DL
2588 temp
2589 (state (cond ((progn (setq tmp (get symbol 'customized-value))
2590 (setq temp
2591 (get symbol 'customized-variable-comment))
2592 (or tmp temp))
d543e20b 2593 (if (condition-case nil
d3d4df42
DL
2594 (and (equal value (eval (car tmp)))
2595 (equal comment temp))
d543e20b
PA
2596 (error nil))
2597 'set
2598 'changed))
25c6d447 2599 ((progn (setq tmp (get symbol 'theme-value))
d3d4df42
DL
2600 (setq temp (get symbol 'saved-variable-comment))
2601 (or tmp temp))
d543e20b 2602 (if (condition-case nil
25c6d447
CY
2603 (and (equal comment temp)
2604 (equal value
d358aa10
CY
2605 (eval
2606 (car (custom-variable-theme-value
2607 symbol)))))
d543e20b 2608 (error nil))
d820f1fb 2609 (cond
d358aa10
CY
2610 ((eq (caar tmp) 'user) 'saved)
2611 ((eq (caar tmp) 'changed) 'changed)
d820f1fb 2612 (t 'themed))
d543e20b 2613 'changed))
25ac13b5 2614 ((setq tmp (get symbol 'standard-value))
d543e20b 2615 (if (condition-case nil
d3d4df42
DL
2616 (and (equal value (eval (car tmp)))
2617 (equal comment nil))
d543e20b 2618 (error nil))
25ac13b5 2619 'standard
d543e20b
PA
2620 'changed))
2621 (t 'rogue))))
2622 (widget-put widget :custom-state state)))
2623
4f985043
RS
2624(defun custom-variable-standard-value (widget)
2625 (get (widget-value widget) 'standard-value))
2626
d3d4df42 2627(defvar custom-variable-menu
eaa99205 2628 `(("Set for current session" custom-variable-set
0c731046 2629 (lambda (widget)
eaa99205
CY
2630 (eq (widget-get widget :custom-state) 'modified)))
2631 ,@(when (or custom-file user-init-file)
2632 '(("Save for future sessions" custom-variable-save
2633 (lambda (widget)
2634 (memq (widget-get widget :custom-state)
2635 '(modified set changed rogue))))))
0c731046
CY
2636 ("---" ignore ignore)
2637 ("Reset to current value" custom-redraw
6d528fc5
PA
2638 (lambda (widget)
2639 (and (default-boundp (widget-value widget))
86bd10bc 2640 (memq (widget-get widget :custom-state) '(modified changed)))))
0c731046 2641 ("Reset to saved value" custom-variable-reset-saved
6d528fc5 2642 (lambda (widget)
d3d4df42
DL
2643 (and (or (get (widget-value widget) 'saved-value)
2644 (get (widget-value widget) 'saved-variable-comment))
6d528fc5
PA
2645 (memq (widget-get widget :custom-state)
2646 '(modified set changed rogue)))))
0c731046 2647 ("Reset to backup value" custom-variable-reset-backup
bde4f354
RS
2648 (lambda (widget)
2649 (get (widget-value widget) 'backup-value)))
73e60f53
CY
2650 ,@(when (or custom-file user-init-file)
2651 '(("Erase customization" custom-variable-reset-standard
2652 (lambda (widget)
2653 (and (get (widget-value widget) 'standard-value)
2654 (memq (widget-get widget :custom-state)
2655 '(modified set changed saved rogue)))))))
eaa99205
CY
2656 ("---" ignore ignore)
2657 ("Add comment" custom-comment-show custom-comment-invisible-p)
2658 ("Show value widget" custom-variable-edit
73e60f53 2659 (lambda (widget)
eaa99205
CY
2660 (eq (widget-get widget :custom-form) 'lisp)))
2661 ("Show Lisp expression" custom-variable-edit-lisp
2662 (lambda (widget)
2663 (eq (widget-get widget :custom-form) 'edit))))
d543e20b 2664 "Alist of actions for the `custom-variable' widget.
6d528fc5
PA
2665Each entry has the form (NAME ACTION FILTER) where NAME is the name of
2666the menu entry, ACTION is the function to call on the widget when the
2667menu is selected, and FILTER is a predicate which takes a `custom-variable'
2668widget as an argument, and returns non-nil if ACTION is valid on that
19d63704 2669widget. If FILTER is nil, ACTION is always valid.")
d543e20b
PA
2670
2671(defun custom-variable-action (widget &optional event)
2672 "Show the menu for `custom-variable' WIDGET.
2673Optional EVENT is the location for the menu."
2674 (if (eq (widget-get widget :custom-state) 'hidden)
6d528fc5 2675 (custom-toggle-hide widget)
86bd10bc
PA
2676 (unless (eq (widget-get widget :custom-state) 'modified)
2677 (custom-variable-state-set widget))
2678 (custom-redraw-magic widget)
d543e20b 2679 (let* ((completion-ignore-case t)
25ac13b5
PA
2680 (answer (widget-choose (concat "Operation on "
2681 (custom-unlispify-tag-name
2682 (widget-get widget :value)))
6d528fc5
PA
2683 (custom-menu-filter custom-variable-menu
2684 widget)
d543e20b
PA
2685 event)))
2686 (if answer
2687 (funcall answer widget)))))
2688
2689(defun custom-variable-edit (widget)
2690 "Edit value of WIDGET."
2691 (widget-put widget :custom-state 'unknown)
2692 (widget-put widget :custom-form 'edit)
2693 (custom-redraw widget))
2694
2695(defun custom-variable-edit-lisp (widget)
2365594b 2696 "Edit the Lisp representation of the value of WIDGET."
d543e20b
PA
2697 (widget-put widget :custom-state 'unknown)
2698 (widget-put widget :custom-form 'lisp)
2699 (custom-redraw widget))
2700
2701(defun custom-variable-set (widget)
2702 "Set the current value for the variable being edited by WIDGET."
6d528fc5
PA
2703 (let* ((form (widget-get widget :custom-form))
2704 (state (widget-get widget :custom-state))
2705 (child (car (widget-get widget :children)))
2706 (symbol (widget-value widget))
2707 (set (or (get symbol 'custom-set) 'set-default))
d3d4df42
DL
2708 (comment-widget (widget-get widget :comment-widget))
2709 (comment (widget-value comment-widget))
2710 val)
d543e20b 2711 (cond ((eq state 'hidden)
896a6a5d 2712 (error "Cannot set hidden variable"))
d543e20b
PA
2713 ((setq val (widget-apply child :validate))
2714 (goto-char (widget-get val :from))
2715 (error "%s" (widget-get val :error)))
f985c5f7 2716 ((memq form '(lisp mismatch))
d3d4df42
DL
2717 (when (equal comment "")
2718 (setq comment nil)
2719 ;; Make the comment invisible by hand if it's empty
164cfaeb 2720 (custom-comment-hide comment-widget))
bde4f354 2721 (custom-variable-backup-value widget)
25c6d447 2722 (custom-push-theme 'theme-value symbol 'user
c5d290fb 2723 'set (custom-quote (widget-value child)))
6d528fc5 2724 (funcall set symbol (eval (setq val (widget-value child))))
d3d4df42
DL
2725 (put symbol 'customized-value (list val))
2726 (put symbol 'variable-comment comment)
2727 (put symbol 'customized-variable-comment comment))
d543e20b 2728 (t
d3d4df42
DL
2729 (when (equal comment "")
2730 (setq comment nil)
2731 ;; Make the comment invisible by hand if it's empty
164cfaeb 2732 (custom-comment-hide comment-widget))
bde4f354 2733 (custom-variable-backup-value widget)
25c6d447 2734 (custom-push-theme 'theme-value symbol 'user
c5d290fb 2735 'set (custom-quote (widget-value child)))
6d528fc5 2736 (funcall set symbol (setq val (widget-value child)))
d3d4df42
DL
2737 (put symbol 'customized-value (list (custom-quote val)))
2738 (put symbol 'variable-comment comment)
2739 (put symbol 'customized-variable-comment comment)))
d543e20b
PA
2740 (custom-variable-state-set widget)
2741 (custom-redraw-magic widget)))
2742
2743(defun custom-variable-save (widget)
0db1ff23 2744 "Set and save the value for the variable being edited by WIDGET."
6d528fc5
PA
2745 (let* ((form (widget-get widget :custom-form))
2746 (state (widget-get widget :custom-state))
2747 (child (car (widget-get widget :children)))
2748 (symbol (widget-value widget))
2749 (set (or (get symbol 'custom-set) 'set-default))
d3d4df42
DL
2750 (comment-widget (widget-get widget :comment-widget))
2751 (comment (widget-value comment-widget))
6d528fc5 2752 val)
d543e20b 2753 (cond ((eq state 'hidden)
896a6a5d 2754 (error "Cannot set hidden variable"))
d543e20b
PA
2755 ((setq val (widget-apply child :validate))
2756 (goto-char (widget-get val :from))
6b292312 2757 (error "Saving %s: %s" symbol (widget-get val :error)))
f985c5f7 2758 ((memq form '(lisp mismatch))
d3d4df42
DL
2759 (when (equal comment "")
2760 (setq comment nil)
2761 ;; Make the comment invisible by hand if it's empty
164cfaeb 2762 (custom-comment-hide comment-widget))
d543e20b 2763 (put symbol 'saved-value (list (widget-value child)))
c942535f 2764 (custom-push-theme 'theme-value symbol 'user
c5d290fb 2765 'set (custom-quote (widget-value child)))
d3d4df42
DL
2766 (funcall set symbol (eval (widget-value child)))
2767 (put symbol 'variable-comment comment)
2768 (put symbol 'saved-variable-comment comment))
d543e20b 2769 (t
d3d4df42
DL
2770 (when (equal comment "")
2771 (setq comment nil)
2772 ;; Make the comment invisible by hand if it's empty
164cfaeb 2773 (custom-comment-hide comment-widget))
d3d4df42
DL
2774 (put symbol 'saved-value
2775 (list (custom-quote (widget-value child))))
c942535f 2776 (custom-push-theme 'theme-value symbol 'user
c5d290fb 2777 'set (custom-quote (widget-value child)))
d3d4df42
DL
2778 (funcall set symbol (widget-value child))
2779 (put symbol 'variable-comment comment)
2780 (put symbol 'saved-variable-comment comment)))
d543e20b 2781 (put symbol 'customized-value nil)
d3d4df42 2782 (put symbol 'customized-variable-comment nil)
d543e20b
PA
2783 (custom-save-all)
2784 (custom-variable-state-set widget)
2785 (custom-redraw-magic widget)))
2786
2787(defun custom-variable-reset-saved (widget)
bde4f354 2788 "Restore the saved value for the variable being edited by WIDGET.
67177975 2789This also updates the buffer to show that value.
bde4f354
RS
2790The value that was current before this operation
2791becomes the backup value, so you can get it again."
6d528fc5 2792 (let* ((symbol (widget-value widget))
d3d4df42 2793 (set (or (get symbol 'custom-set) 'set-default))
d3d4df42
DL
2794 (value (get symbol 'saved-value))
2795 (comment (get symbol 'saved-variable-comment)))
2796 (cond ((or value comment)
2797 (put symbol 'variable-comment comment)
bde4f354 2798 (custom-variable-backup-value widget)
d358aa10 2799 (custom-push-theme 'theme-value symbol 'user 'set (car-safe value))
d3d4df42
DL
2800 (condition-case nil
2801 (funcall set symbol (eval (car value)))
2802 (error nil)))
2803 (t
2804 (error "No saved value for %s" symbol)))
d543e20b 2805 (put symbol 'customized-value nil)
d3d4df42 2806 (put symbol 'customized-variable-comment nil)
d543e20b 2807 (widget-put widget :custom-state 'unknown)
d3d4df42 2808 ;; This call will possibly make the comment invisible
d543e20b
PA
2809 (custom-redraw widget)))
2810
25ac13b5 2811(defun custom-variable-reset-standard (widget)
19d63704
RS
2812 "Restore the standard setting for the variable being edited by WIDGET.
2813This operation eliminates any saved setting for the variable,
bde4f354
RS
2814restoring it to the state of a variable that has never been customized.
2815The value that was current before this operation
2816becomes the backup value, so you can get it again."
d358aa10 2817 (let* ((symbol (widget-value widget)))
25ac13b5 2818 (if (get symbol 'standard-value)
25c6d447 2819 (custom-variable-backup-value widget)
5dd0cad0 2820 (error "No standard setting known for %S" symbol))
164cfaeb 2821 (put symbol 'variable-comment nil)
d543e20b 2822 (put symbol 'customized-value nil)
d3d4df42 2823 (put symbol 'customized-variable-comment nil)
d358aa10 2824 (custom-push-theme 'theme-value symbol 'user 'reset)
25c6d447 2825 (custom-theme-recalc-variable symbol)
d3d4df42 2826 (when (or (get symbol 'saved-value) (get symbol 'saved-variable-comment))
d543e20b 2827 (put symbol 'saved-value nil)
d3d4df42 2828 (put symbol 'saved-variable-comment nil)
d543e20b
PA
2829 (custom-save-all))
2830 (widget-put widget :custom-state 'unknown)
d3d4df42 2831 ;; This call will possibly make the comment invisible
d543e20b
PA
2832 (custom-redraw widget)))
2833
bde4f354
RS
2834(defun custom-variable-backup-value (widget)
2835 "Back up the current value for WIDGET's variable.
2836The backup value is kept in the car of the `backup-value' property."
2837 (let* ((symbol (widget-value widget))
2838 (get (or (get symbol 'custom-get) 'default-value))
2839 (type (custom-variable-type symbol))
2840 (conv (widget-convert type))
2841 (value (if (default-boundp symbol)
2842 (funcall get symbol)
2843 (widget-get conv :value))))
2844 (put symbol 'backup-value (list value))))
2845
2846(defun custom-variable-reset-backup (widget)
2847 "Restore the backup value for the variable being edited by WIDGET.
2848The value that was current before this operation
2849becomes the backup value, so you can use this operation repeatedly
2850to switch between two values."
2851 (let* ((symbol (widget-value widget))
2852 (set (or (get symbol 'custom-set) 'set-default))
2853 (value (get symbol 'backup-value))
2854 (comment-widget (widget-get widget :comment-widget))
2855 (comment (widget-value comment-widget)))
2856 (if value
2857 (progn
2858 (custom-variable-backup-value widget)
25c6d447 2859 (custom-push-theme 'theme-value symbol 'user 'set value)
bde4f354
RS
2860 (condition-case nil
2861 (funcall set symbol (car value))
2862 (error nil)))
2863 (error "No backup value for %s" symbol))
2864 (put symbol 'customized-value (list (car value)))
2865 (put symbol 'variable-comment comment)
2866 (put symbol 'customized-variable-comment comment)
2867 (custom-variable-state-set widget)
2868 ;; This call will possibly make the comment invisible
2869 (custom-redraw widget)))
2870
d543e20b
PA
2871;;; The `custom-face-edit' Widget.
2872
2873(define-widget 'custom-face-edit 'checklist
2874 "Edit face attributes."
2875 :format "%t: %v"
2876 :tag "Attributes"
2dfa4c57 2877 :extra-offset 13
d3d4df42 2878 :button-args '(:help-echo "Control whether this attribute has any effect.")
d75fa08f
RS
2879 :value-to-internal 'custom-face-edit-fix-value
2880 :match (lambda (widget value)
ee1f522d 2881 (widget-checklist-match widget
d75fa08f 2882 (custom-face-edit-fix-value widget value)))
3ea051cb 2883 :convert-widget 'custom-face-edit-convert-widget
d543e20b 2884 :args (mapcar (lambda (att)
d3d4df42 2885 (list 'group
d543e20b
PA
2886 :inline t
2887 :sibling-args (widget-get (nth 1 att) :sibling-args)
d3d4df42 2888 (list 'const :format "" :value (nth 0 att))
d543e20b
PA
2889 (nth 1 att)))
2890 custom-face-attributes))
2891
d75fa08f 2892(defun custom-face-edit-fix-value (widget value)
0bbe869a
AS
2893 "Ignoring WIDGET, convert :bold and :italic in VALUE to new form.
2894Also change :reverse-video to :inverse-video."
4f985043
RS
2895 (if (listp value)
2896 (let (result)
2897 (while value
2898 (let ((key (car value))
2899 (val (car (cdr value))))
2900 (cond ((eq key :italic)
2901 (push :slant result)
2902 (push (if val 'italic 'normal) result))
2903 ((eq key :bold)
2904 (push :weight result)
2905 (push (if val 'bold 'normal) result))
0bbe869a
AS
2906 ((eq key :reverse-video)
2907 (push :inverse-video result)
2908 (push val result))
ee1f522d 2909 (t
4f985043
RS
2910 (push key result)
2911 (push val result))))
2912 (setq value (cdr (cdr value))))
2913 (setq result (nreverse result))
2914 result)
2915 value))
d75fa08f 2916
3ea051cb
MB
2917(defun custom-face-edit-convert-widget (widget)
2918 "Convert :args as widget types in WIDGET."
2919 (widget-put
2920 widget
2921 :args (mapcar (lambda (arg)
2922 (widget-convert arg
2923 :deactivate 'custom-face-edit-deactivate
2924 :activate 'custom-face-edit-activate
2925 :delete 'custom-face-edit-delete))
2926 (widget-get widget :args)))
2927 widget)
2928
2929(defun custom-face-edit-deactivate (widget)
2930 "Make face widget WIDGET inactive for user modifications."
2931 (unless (widget-get widget :inactive)
2932 (let ((tag (custom-face-edit-attribute-tag widget))
2933 (from (copy-marker (widget-get widget :from)))
3ea051cb
MB
2934 (value (widget-value widget))
2935 (inhibit-read-only t)
2936 (inhibit-modification-hooks t))
2937 (save-excursion
2938 (goto-char from)
2939 (widget-default-delete widget)
2940 (insert tag ": *\n")
2941 (widget-put widget :inactive
2942 (cons value (cons from (- (point) from))))))))
2943
2944(defun custom-face-edit-activate (widget)
2945 "Make face widget WIDGET inactive for user modifications."
2946 (let ((inactive (widget-get widget :inactive))
2947 (inhibit-read-only t)
2948 (inhibit-modification-hooks t))
2949 (when (consp inactive)
2950 (save-excursion
2951 (goto-char (car (cdr inactive)))
2952 (delete-region (point) (+ (point) (cdr (cdr inactive))))
2953 (widget-put widget :inactive nil)
2954 (widget-apply widget :create)
2955 (widget-value-set widget (car inactive))
2956 (widget-setup)))))
2957
2958(defun custom-face-edit-delete (widget)
3127aa13 2959 "Remove WIDGET from the buffer."
3ea051cb
MB
2960 (let ((inactive (widget-get widget :inactive))
2961 (inhibit-read-only t)
2962 (inhibit-modification-hooks t))
2963 (if (not inactive)
2964 ;; Widget is alive, we don't have to do anything special
2965 (widget-default-delete widget)
2966 ;; WIDGET is already deleted because we did so to inactivate it;
2967 ;; now just get rid of the label we put in its place.
2968 (delete-region (car (cdr inactive))
2969 (+ (car (cdr inactive)) (cdr (cdr inactive))))
2970 (widget-put widget :inactive nil))))
ee1f522d 2971
3ea051cb
MB
2972
2973(defun custom-face-edit-attribute-tag (widget)
2974 "Returns the first :tag property in WIDGET or one of its children."
2975 (let ((tag (widget-get widget :tag)))
2976 (or (and (not (equal tag "")) tag)
2977 (let ((children (widget-get widget :children)))
2978 (while (and (null tag) children)
2979 (setq tag (custom-face-edit-attribute-tag (pop children))))
2980 tag))))
2981
d543e20b
PA
2982;;; The `custom-display' Widget.
2983
2984(define-widget 'custom-display 'menu-choice
2985 "Select a display type."
2986 :tag "Display"
2987 :value t
2988 :help-echo "Specify frames where the face attributes should be used."
2989 :args '((const :tag "all" t)
b9afd6dd 2990 (const :tag "defaults" default)
d543e20b
PA
2991 (checklist
2992 :offset 0
2993 :extra-offset 9
2994 :args ((group :sibling-args (:help-echo "\
2995Only match the specified window systems.")
2996 (const :format "Type: "
2997 type)
2998 (checklist :inline t
2999 :offset 0
3000 (const :format "X "
3001 :sibling-args (:help-echo "\
3002The X11 Window System.")
3003 x)
3004 (const :format "PM "
3005 :sibling-args (:help-echo "\
3006OS/2 Presentation Manager.")
3007 pm)
b97aca27 3008 (const :format "W32 "
d543e20b 3009 :sibling-args (:help-echo "\
b97aca27
GV
3010Windows NT/9X.")
3011 w32)
a0b1a022
AS
3012 (const :format "MAC "
3013 :sibling-args (:help-echo "\
3014Macintosh OS.")
3015 mac)
d543e20b
PA
3016 (const :format "DOS "
3017 :sibling-args (:help-echo "\
3018Plain MS-DOS.")
3019 pc)
3020 (const :format "TTY%n"
3021 :sibling-args (:help-echo "\
3022Plain text terminals.")
3023 tty)))
3024 (group :sibling-args (:help-echo "\
3025Only match the frames with the specified color support.")
3026 (const :format "Class: "
3027 class)
3028 (checklist :inline t
3029 :offset 0
3030 (const :format "Color "
3031 :sibling-args (:help-echo "\
3032Match color frames.")
3033 color)
3034 (const :format "Grayscale "
3035 :sibling-args (:help-echo "\
3036Match grayscale frames.")
3037 grayscale)
3038 (const :format "Monochrome%n"
3039 :sibling-args (:help-echo "\
3040Match frames with no color support.")
3041 mono)))
3042 (group :sibling-args (:help-echo "\
c4d9734c
JL
3043The minimum number of colors the frame should support.")
3044 (const :format "" min-colors)
3045 (integer :tag "Minimum number of colors" ))
3046 (group :sibling-args (:help-echo "\
d543e20b
PA
3047Only match frames with the specified intensity.")
3048 (const :format "\
3049Background brightness: "
3050 background)
3051 (checklist :inline t
3052 :offset 0
3053 (const :format "Light "
3054 :sibling-args (:help-echo "\
3055Match frames with light backgrounds.")
3056 light)
3057 (const :format "Dark\n"
3058 :sibling-args (:help-echo "\
3059Match frames with dark backgrounds.")
2b32d1a7
MB
3060 dark)))
3061 (group :sibling-args (:help-echo "\
3062Only match frames that support the specified face attributes.")
3063 (const :format "Supports attributes:" supports)
4abe16b5 3064 (custom-face-edit :inline t :format "%n%v"))))))
d543e20b
PA
3065
3066;;; The `custom-face' Widget.
3067
d478e69d 3068(defface custom-face-tag
b5555381 3069 `((t (:weight bold :height 1.2 :inherit variable-pitch)))
d543e20b 3070 "Face used for face tags."
bd042c03 3071 :group 'custom-faces)
d478e69d
MB
3072;; backward-compatibility alias
3073(put 'custom-face-tag-face 'face-alias 'custom-face-tag)
d543e20b 3074
d64478da
KH
3075(defcustom custom-face-default-form 'selected
3076 "Default form of displaying face definition."
3077 :type '(choice (const all)
3078 (const selected)
3079 (const lisp))
cd32a7ba
DN
3080 :group 'custom-buffer
3081 :version "20.3")
d64478da 3082
d543e20b
PA
3083(define-widget 'custom-face 'custom
3084 "Customize face."
d543e20b
PA
3085 :sample-face 'custom-face-tag-face
3086 :help-echo "Set or reset this face."
23c0fb21 3087 :documentation-property #'face-doc-string
d543e20b
PA
3088 :value-create 'custom-face-value-create
3089 :action 'custom-face-action
9097aeb7 3090 :custom-category 'face
d64478da 3091 :custom-form nil ; defaults to value of `custom-face-default-form'
d543e20b
PA
3092 :custom-set 'custom-face-set
3093 :custom-save 'custom-face-save
3094 :custom-reset-current 'custom-redraw
3095 :custom-reset-saved 'custom-face-reset-saved
25ac13b5 3096 :custom-reset-standard 'custom-face-reset-standard
4f985043 3097 :custom-standard-value 'custom-face-standard-value
d543e20b
PA
3098 :custom-menu 'custom-face-menu-create)
3099
d3d4df42 3100(define-widget 'custom-face-all 'editable-list
d543e20b
PA
3101 "An editable list of display specifications and attributes."
3102 :entry-format "%i %d %v"
3103 :insert-button-args '(:help-echo "Insert new display specification here.")
3104 :append-button-args '(:help-echo "Append new display specification here.")
3105 :delete-button-args '(:help-echo "Delete this display specification.")
3106 :args '((group :format "%v" custom-display custom-face-edit)))
3107
3108(defconst custom-face-all (widget-convert 'custom-face-all)
3109 "Converted version of the `custom-face-all' widget.")
3110
3111(define-widget 'custom-display-unselected 'item
3112 "A display specification that doesn't match the selected display."
3113 :match 'custom-display-unselected-match)
3114
3115(defun custom-display-unselected-match (widget value)
3116 "Non-nil if VALUE is an unselected display specification."
86bd10bc 3117 (not (face-spec-set-match-display value (selected-frame))))
d543e20b 3118
d3d4df42 3119(define-widget 'custom-face-selected 'group
d543e20b 3120 "Edit the attributes of the selected display in a face specification."
2dfa4c57
RS
3121 :args '((choice :inline t
3122 (group :tag "With Defaults" :inline t
3123 (group (const :tag "" default)
3124 (custom-face-edit :tag " Default\n Attributes"))
3125 (repeat :format ""
3126 :inline t
3127 (group custom-display-unselected sexp))
3128 (group (sexp :format "")
3129 (custom-face-edit :tag " Overriding\n Attributes"))
3130 (repeat :format ""
3131 :inline t
3132 sexp))
3133 (group :tag "No Defaults" :inline t
3134 (repeat :format ""
3135 :inline t
3136 (group custom-display-unselected sexp))
3137 (group (sexp :format "")
3138 (custom-face-edit :tag "\n Attributes"))
3139 (repeat :format ""
3140 :inline t
3141 sexp)))))
3142
3143
d543e20b
PA
3144
3145(defconst custom-face-selected (widget-convert 'custom-face-selected)
3146 "Converted version of the `custom-face-selected' widget.")
3147
3ea051cb 3148(defun custom-filter-face-spec (spec filter-index &optional default-filter)
f5b50baa
MB
3149 "Return a canonicalized version of SPEC using.
3150FILTER-INDEX is the index in the entry for each attribute in
3151`custom-face-attributes' at which the appropriate filter function can be
3152found, and DEFAULT-FILTER is the filter to apply for attributes that
3153don't specify one."
3154 (mapcar (lambda (entry)
3155 ;; Filter a single face-spec entry
3156 (let ((tests (car entry))
3157 (unfiltered-attrs
3158 ;; Handle both old- and new-style attribute syntax
3159 (if (listp (car (cdr entry)))
3160 (car (cdr entry))
3161 (cdr entry)))
3162 (filtered-attrs nil))
3163 ;; Filter each face attribute
3164 (while unfiltered-attrs
3165 (let* ((attr (pop unfiltered-attrs))
3166 (pre-filtered-value (pop unfiltered-attrs))
3167 (filter
3168 (or (nth filter-index (assq attr custom-face-attributes))
3169 default-filter))
3170 (filtered-value
3171 (if filter
3172 (funcall filter pre-filtered-value)
3173 pre-filtered-value)))
3174 (push filtered-value filtered-attrs)
3175 (push attr filtered-attrs)))
3176 ;;
3177 (list tests filtered-attrs)))
3178 spec))
3179
3180(defun custom-pre-filter-face-spec (spec)
3181 "Return SPEC changed as necessary for editing by the face customization widget.
3182SPEC must be a full face spec."
3ea051cb 3183 (custom-filter-face-spec spec 2))
f5b50baa
MB
3184
3185(defun custom-post-filter-face-spec (spec)
3186 "Return the customized SPEC in a form suitable for setting the face."
3ea051cb 3187 (custom-filter-face-spec spec 3))
f5b50baa 3188
d543e20b 3189(defun custom-face-value-create (widget)
944c91b6
PA
3190 "Create a list of the display specifications for WIDGET."
3191 (let ((buttons (widget-get widget :buttons))
d3d4df42 3192 children
944c91b6
PA
3193 (symbol (widget-get widget :value))
3194 (tag (widget-get widget :tag))
3195 (state (widget-get widget :custom-state))
3196 (begin (point))
3197 (is-last (widget-get widget :custom-last))
3198 (prefix (widget-get widget :custom-prefix)))
3199 (unless tag
3200 (setq tag (prin1-to-string symbol)))
3201 (cond ((eq custom-buffer-style 'tree)
da5ec617 3202 (insert prefix (if is-last " `--- " " |--- "))
944c91b6 3203 (push (widget-create-child-and-convert
c953515e 3204 widget 'custom-browse-face-tag)
944c91b6
PA
3205 buttons)
3206 (insert " " tag "\n")
3207 (widget-put widget :buttons buttons))
3208 (t
3209 ;; Create tag.
3210 (insert tag)
c069a9d3 3211 (widget-specify-sample widget begin (point))
944c91b6
PA
3212 (if (eq custom-buffer-style 'face)
3213 (insert " ")
a62ebc52
MB
3214 (if (string-match "face\\'" tag)
3215 (insert ":")
3216 (insert " face: ")))
944c91b6 3217 ;; Sample.
944c91b6
PA
3218 (push (widget-create-child-and-convert widget 'item
3219 :format "(%{%t%})"
3220 :sample-face symbol
3221 :tag "sample")
3222 buttons)
3223 ;; Visibility.
3224 (insert " ")
d3d4df42 3225 (push (widget-create-child-and-convert
944c91b6
PA
3226 widget 'visibility
3227 :help-echo "Hide or show this face."
7f663295
RS
3228 :on "Hide Face"
3229 :off "Show Face"
944c91b6
PA
3230 :action 'custom-toggle-parent
3231 (not (eq state 'hidden)))
3232 buttons)
3233 ;; Magic.
3234 (insert "\n")
3235 (let ((magic (widget-create-child-and-convert
3236 widget 'custom-magic nil)))
3237 (widget-put widget :custom-magic magic)
3238 (push magic buttons))
3239 ;; Update buttons.
3240 (widget-put widget :buttons buttons)
3241 ;; Insert documentation.
3242 (widget-default-format-handler widget ?h)
d3d4df42
DL
3243 ;; The comment field
3244 (unless (eq state 'hidden)
3245 (let* ((comment (get symbol 'face-comment))
3246 (comment-widget
3247 (widget-create-child-and-convert
3248 widget 'custom-comment
3249 :parent widget
3250 :value (or comment ""))))
3251 (widget-put widget :comment-widget comment-widget)
3252 (push comment-widget children)))
944c91b6
PA
3253 ;; See also.
3254 (unless (eq state 'hidden)
3255 (when (eq (widget-get widget :custom-level) 1)
3256 (custom-add-parent-links widget))
3257 (custom-add-see-also widget))
3258 ;; Editor.
3259 (unless (eq (preceding-char) ?\n)
3260 (insert "\n"))
3261 (unless (eq state 'hidden)
3262 (message "Creating face editor...")
3263 (custom-load-widget widget)
d64478da
KH
3264 (unless (widget-get widget :custom-form)
3265 (widget-put widget :custom-form custom-face-default-form))
944c91b6 3266 (let* ((symbol (widget-value widget))
61763509
PA
3267 (spec (or (get symbol 'customized-face)
3268 (get symbol 'saved-face)
944c91b6
PA
3269 (get symbol 'face-defface-spec)
3270 ;; Attempt to construct it.
d3d4df42 3271 (list (list t (custom-face-attributes-get
944c91b6
PA
3272 symbol (selected-frame))))))
3273 (form (widget-get widget :custom-form))
3274 (indent (widget-get widget :indent))
fa0b3d46
RS
3275 edit)
3276 ;; If the user has changed this face in some other way,
3277 ;; edit it as the user has specified it.
3278 (if (not (face-spec-match-p symbol spec (selected-frame)))
3279 (setq spec (list (list t (face-attr-construct symbol (selected-frame))))))
f5b50baa 3280 (setq spec (custom-pre-filter-face-spec spec))
fa0b3d46 3281 (setq edit (widget-create-child-and-convert
944c91b6
PA
3282 widget
3283 (cond ((and (eq form 'selected)
d3d4df42 3284 (widget-apply custom-face-selected
944c91b6
PA
3285 :match spec))
3286 (when indent (insert-char ?\ indent))
3287 'custom-face-selected)
3288 ((and (not (eq form 'lisp))
3289 (widget-apply custom-face-all
3290 :match spec))
3291 'custom-face-all)
d3d4df42 3292 (t
944c91b6
PA
3293 (when indent (insert-char ?\ indent))
3294 'sexp))
fa0b3d46 3295 :value spec))
944c91b6 3296 (custom-face-state-set widget)
d3d4df42
DL
3297 (push edit children)
3298 (widget-put widget :children children))
944c91b6 3299 (message "Creating face editor...done"))))))
d543e20b 3300
d3d4df42 3301(defvar custom-face-menu
eaa99205
CY
3302 `(("Set for current session" custom-face-set)
3303 ,@(when (or custom-file user-init-file)
3304 '(("Save for future sessions" custom-face-save-command)))
73e60f53 3305 ("---" ignore ignore)
0c731046
CY
3306 ("Reset to saved face" custom-face-reset-saved
3307 (lambda (widget)
3308 (or (get (widget-value widget) 'saved-face)
3309 (get (widget-value widget) 'saved-face-comment))))
73e60f53
CY
3310 ,@(when (or custom-file user-init-file)
3311 '(("Erase customization" custom-face-reset-standard
3312 (lambda (widget)
3313 (get (widget-value widget) 'face-defface-spec)))))
eaa99205
CY
3314 ("---" ignore ignore)
3315 ("Add comment" custom-comment-show custom-comment-invisible-p)
3316 ("Show all attributes" custom-face-edit-all
3317 (lambda (widget)
3318 (not (eq (widget-get widget :custom-form) 'all))))
3319 ("Show current attributes" custom-face-edit-selected
3320 (lambda (widget)
3321 (not (eq (widget-get widget :custom-form) 'selected))))
3322 ("Show Lisp expression" custom-face-edit-lisp
3323 (lambda (widget)
3324 (not (eq (widget-get widget :custom-form) 'lisp)))))
d543e20b 3325 "Alist of actions for the `custom-face' widget.
6d528fc5
PA
3326Each entry has the form (NAME ACTION FILTER) where NAME is the name of
3327the menu entry, ACTION is the function to call on the widget when the
3328menu is selected, and FILTER is a predicate which takes a `custom-face'
3329widget as an argument, and returns non-nil if ACTION is valid on that
19d63704 3330widget. If FILTER is nil, ACTION is always valid.")
d543e20b
PA
3331
3332(defun custom-face-edit-selected (widget)
3333 "Edit selected attributes of the value of WIDGET."
3334 (widget-put widget :custom-state 'unknown)
3335 (widget-put widget :custom-form 'selected)
3336 (custom-redraw widget))
3337
3338(defun custom-face-edit-all (widget)
3339 "Edit all attributes of the value of WIDGET."
3340 (widget-put widget :custom-state 'unknown)
3341 (widget-put widget :custom-form 'all)
3342 (custom-redraw widget))
3343
3344(defun custom-face-edit-lisp (widget)
2365594b 3345 "Edit the Lisp representation of the value of WIDGET."
d543e20b
PA
3346 (widget-put widget :custom-state 'unknown)
3347 (widget-put widget :custom-form 'lisp)
3348 (custom-redraw widget))
3349
3350(defun custom-face-state-set (widget)
3351 "Set the state of WIDGET."
d3d4df42
DL
3352 (let* ((symbol (widget-value widget))
3353 (comment (get symbol 'face-comment))
a4992f73
RS
3354 tmp temp
3355 (state
3356 (cond ((progn
3357 (setq tmp (get symbol 'customized-face))
3358 (setq temp (get symbol 'customized-face-comment))
3359 (or tmp temp))
3360 (if (equal temp comment)
3361 'set
3362 'changed))
3363 ((progn
3364 (setq tmp (get symbol 'saved-face))
3365 (setq temp (get symbol 'saved-face-comment))
3366 (or tmp temp))
3367 (if (equal temp comment)
70128967
CY
3368 (cond
3369 ((eq 'user (caar (get symbol 'theme-face)))
3370 'saved)
d358aa10 3371 ((eq 'changed (caar (get symbol 'theme-face)))
70128967
CY
3372 'changed)
3373 (t 'themed))
a4992f73
RS
3374 'changed))
3375 ((get symbol 'face-defface-spec)
3376 (if (equal comment nil)
3377 'standard
3378 'changed))
3379 (t
3380 'rogue))))
3381 ;; If the user called set-face-attribute to change the default
3382 ;; for new frames, this face is "set outside of Customize".
3383 (if (and (not (eq state 'rogue))
3384 (get symbol 'face-modified))
3385 (setq state 'changed))
3386 (widget-put widget :custom-state state)))
d543e20b
PA
3387
3388(defun custom-face-action (widget &optional event)
3389 "Show the menu for `custom-face' WIDGET.
3390Optional EVENT is the location for the menu."
3391 (if (eq (widget-get widget :custom-state) 'hidden)
6d528fc5 3392 (custom-toggle-hide widget)
d543e20b
PA
3393 (let* ((completion-ignore-case t)
3394 (symbol (widget-get widget :value))
25ac13b5
PA
3395 (answer (widget-choose (concat "Operation on "
3396 (custom-unlispify-tag-name symbol))
6d528fc5
PA
3397 (custom-menu-filter custom-face-menu
3398 widget)
3399 event)))
d543e20b
PA
3400 (if answer
3401 (funcall answer widget)))))
3402
3403(defun custom-face-set (widget)
3404 "Make the face attributes in WIDGET take effect."
3405 (let* ((symbol (widget-value widget))
3406 (child (car (widget-get widget :children)))
f5b50baa 3407 (value (custom-post-filter-face-spec (widget-value child)))
d3d4df42
DL
3408 (comment-widget (widget-get widget :comment-widget))
3409 (comment (widget-value comment-widget)))
3410 (when (equal comment "")
3411 (setq comment nil)
3412 ;; Make the comment invisible by hand if it's empty
164cfaeb 3413 (custom-comment-hide comment-widget))
d543e20b 3414 (put symbol 'customized-face value)
f5b50baa
MB
3415 (if (face-spec-choose value)
3416 (face-spec-set symbol value)
3417 ;; face-set-spec ignores empty attribute lists, so just give it
3418 ;; something harmless instead.
3419 (face-spec-set symbol '((t :foreground unspecified))))
25c6d447 3420 (custom-push-theme 'theme-face symbol 'user 'set value)
d3d4df42
DL
3421 (put symbol 'customized-face-comment comment)
3422 (put symbol 'face-comment comment)
d543e20b
PA
3423 (custom-face-state-set widget)
3424 (custom-redraw-magic widget)))
3425
896a6a5d
RS
3426(defun custom-face-save-command (widget)
3427 "Save in `.emacs' the face attributes in WIDGET."
3428 (custom-face-save widget)
3429 (custom-save-all))
3430
d543e20b 3431(defun custom-face-save (widget)
896a6a5d 3432 "Prepare for saving WIDGET's face attributes, but don't write `.emacs'."
d543e20b
PA
3433 (let* ((symbol (widget-value widget))
3434 (child (car (widget-get widget :children)))
e475612a 3435 (value (custom-post-filter-face-spec (widget-value child)))
d3d4df42
DL
3436 (comment-widget (widget-get widget :comment-widget))
3437 (comment (widget-value comment-widget)))
3438 (when (equal comment "")
3439 (setq comment nil)
3440 ;; Make the comment invisible by hand if it's empty
164cfaeb 3441 (custom-comment-hide comment-widget))
b76747af 3442 (custom-push-theme 'theme-face symbol 'user 'set value)
e475612a
MB
3443 (if (face-spec-choose value)
3444 (face-spec-set symbol value)
3445 ;; face-set-spec ignores empty attribute lists, so just give it
3446 ;; something harmless instead.
3447 (face-spec-set symbol '((t :foreground unspecified))))
4f985043
RS
3448 (unless (eq (widget-get widget :custom-state) 'standard)
3449 (put symbol 'saved-face value))
d543e20b 3450 (put symbol 'customized-face nil)
d3d4df42
DL
3451 (put symbol 'face-comment comment)
3452 (put symbol 'customized-face-comment nil)
3453 (put symbol 'saved-face-comment comment)
6321bddd 3454 (custom-save-all)
d543e20b
PA
3455 (custom-face-state-set widget)
3456 (custom-redraw-magic widget)))
3457
3458(defun custom-face-reset-saved (widget)
3459 "Restore WIDGET to the face's default attributes."
3460 (let* ((symbol (widget-value widget))
3461 (child (car (widget-get widget :children)))
d3d4df42
DL
3462 (value (get symbol 'saved-face))
3463 (comment (get symbol 'saved-face-comment))
3464 (comment-widget (widget-get widget :comment-widget)))
3465 (unless (or value comment)
d543e20b
PA
3466 (error "No saved value for this face"))
3467 (put symbol 'customized-face nil)
d3d4df42 3468 (put symbol 'customized-face-comment nil)
25c6d447 3469 (custom-push-theme 'theme-face symbol 'user 'set value)
25ac13b5 3470 (face-spec-set symbol value)
d3d4df42 3471 (put symbol 'face-comment comment)
d543e20b 3472 (widget-value-set child value)
d3d4df42
DL
3473 ;; This call manages the comment visibility
3474 (widget-value-set comment-widget (or comment ""))
d543e20b
PA
3475 (custom-face-state-set widget)
3476 (custom-redraw-magic widget)))
3477
4f985043
RS
3478(defun custom-face-standard-value (widget)
3479 (get (widget-value widget) 'face-defface-spec))
3480
25ac13b5 3481(defun custom-face-reset-standard (widget)
50137744
RS
3482 "Restore WIDGET to the face's standard attribute values.
3483This operation eliminates any saved attributes for the face,
19d63704 3484restoring it to the state of a face that has never been customized."
d543e20b
PA
3485 (let* ((symbol (widget-value widget))
3486 (child (car (widget-get widget :children)))
d3d4df42
DL
3487 (value (get symbol 'face-defface-spec))
3488 (comment-widget (widget-get widget :comment-widget)))
d543e20b 3489 (unless value
5dd0cad0 3490 (error "No standard setting for this face"))
d543e20b 3491 (put symbol 'customized-face nil)
d3d4df42 3492 (put symbol 'customized-face-comment nil)
d358aa10 3493 (custom-push-theme 'theme-face symbol 'user 'reset)
25c6d447 3494 (custom-theme-recalc-face symbol)
d3d4df42 3495 (when (or (get symbol 'saved-face) (get symbol 'saved-face-comment))
d543e20b 3496 (put symbol 'saved-face nil)
d3d4df42 3497 (put symbol 'saved-face-comment nil)
d543e20b 3498 (custom-save-all))
d3d4df42 3499 (put symbol 'face-comment nil)
d543e20b 3500 (widget-value-set child value)
d3d4df42
DL
3501 ;; This call manages the comment visibility
3502 (widget-value-set comment-widget "")
d543e20b
PA
3503 (custom-face-state-set widget)
3504 (custom-redraw-magic widget)))
3505
3506;;; The `face' Widget.
3507
1833b7b3
RS
3508(defvar widget-face-prompt-value-history nil
3509 "History of input to `widget-face-prompt-value'.")
3510
0e739597
DP
3511(define-widget 'face 'symbol
3512 "A Lisp face name (with sample)."
49698bb7 3513 :format "%{%t%}: (%{sample%}) %v"
0e739597
DP
3514 :tag "Face"
3515 :value 'default
3516 :sample-face-get 'widget-face-sample-face-get
3517 :notify 'widget-face-notify
3518 :match (lambda (widget value) (facep value))
1833b7b3
RS
3519 :complete-function (lambda ()
3520 (interactive)
3521 (lisp-complete-symbol 'facep))
1833b7b3
RS
3522 :prompt-match 'facep
3523 :prompt-history 'widget-face-prompt-value-history
1833b7b3
RS
3524 :validate (lambda (widget)
3525 (unless (facep (widget-value widget))
0e739597
DP
3526 (widget-put widget
3527 :error (format "Invalid face: %S"
3528 (widget-value widget)))
3529 widget)))
3530
3531(defun widget-face-sample-face-get (widget)
3532 (let ((value (widget-value widget)))
3533 (if (facep value)
3534 value
3535 'default)))
3536
3537(defun widget-face-notify (widget child &optional event)
3538 "Update the sample, and notify the parent."
3539 (overlay-put (widget-get widget :sample-overlay)
3540 'face (widget-apply widget :sample-face-get))
3541 (widget-default-notify widget child event))
1833b7b3 3542
d543e20b
PA
3543
3544;;; The `hook' Widget.
3545
3546(define-widget 'hook 'list
3547 "A emacs lisp hook"
f985c5f7 3548 :value-to-internal (lambda (widget value)
5aa3f181 3549 (if (and value (symbolp value))
f985c5f7
PA
3550 (list value)
3551 value))
3552 :match (lambda (widget value)
3553 (or (symbolp value)
4743fc91 3554 (widget-group-match widget value)))
2365594b
DL
3555 ;; Avoid adding undefined functions to the hook, especially for
3556 ;; things like `find-file-hook' or even more basic ones, to avoid
3557 ;; chaos.
3558 :set (lambda (symbol value)
d4881668
SM
3559 (dolist (elt value)
3560 (if (fboundp elt)
3561 (add-hook symbol elt))))
d543e20b
PA
3562 :convert-widget 'custom-hook-convert-widget
3563 :tag "Hook")
3564
3565(defun custom-hook-convert-widget (widget)
3c708e98 3566 ;; Handle `:options'.
d543e20b 3567 (let* ((options (widget-get widget :options))
d3d4df42 3568 (other `(editable-list :inline t
d543e20b
PA
3569 :entry-format "%i %d%v"
3570 (function :format " %v")))
3571 (args (if options
3572 (list `(checklist :inline t
3573 ,@(mapcar (lambda (entry)
3574 `(function-item ,entry))
3575 options))
3576 other)
3577 (list other))))
3578 (widget-put widget :args args)
3579 widget))
3580
944c91b6
PA
3581;;; The `custom-group-link' Widget.
3582
3583(define-widget 'custom-group-link 'link
3584 "Show parent in other window when activated."
b62c92bb 3585 :help-echo "Create customization buffer for this group."
944c91b6
PA
3586 :action 'custom-group-link-action)
3587
3588(defun custom-group-link-action (widget &rest ignore)
3589 (customize-group (widget-value widget)))
3590
d543e20b
PA
3591;;; The `custom-group' Widget.
3592
b62c92bb 3593(defcustom custom-group-tag-faces nil
d543e20b 3594 ;; In XEmacs, this ought to play games with font size.
d3d4df42 3595 ;; Fixme: make it do so in Emacs.
d543e20b
PA
3596 "Face used for group tags.
3597The first member is used for level 1 groups, the second for level 2,
d478e69d 3598and so forth. The remaining group tags are shown with `custom-group-tag'."
d543e20b 3599 :type '(repeat face)
bd042c03 3600 :group 'custom-faces)
d543e20b 3601
d478e69d 3602(defface custom-group-tag-1
16b20ed9
GM
3603 `((((class color)
3604 (background dark))
b5555381 3605 (:foreground "pink" :weight bold :height 1.2 :inherit variable-pitch))
ea81d57e
DN
3606 (((min-colors 88) (class color)
3607 (background light))
3608 (:foreground "red1" :weight bold :height 1.2 :inherit variable-pitch))
16b20ed9
GM
3609 (((class color)
3610 (background light))
b5555381
RS
3611 (:foreground "red" :weight bold :height 1.2 :inherit variable-pitch))
3612 (t (:weight bold)))
16b20ed9
GM
3613 "Face used for group tags."
3614 :group 'custom-faces)
d478e69d
MB
3615;; backward-compatibility alias
3616(put 'custom-group-tag-face-1 'face-alias 'custom-group-tag-1)
16b20ed9 3617
d478e69d 3618(defface custom-group-tag
16b20ed9
GM
3619 `((((class color)
3620 (background dark))
b5555381 3621 (:foreground "light blue" :weight bold :height 1.2))
ea81d57e
DN
3622 (((min-colors 88) (class color)
3623 (background light))
3624 (:foreground "blue1" :weight bold :height 1.2))
16b20ed9
GM
3625 (((class color)
3626 (background light))
b5555381
RS
3627 (:foreground "blue" :weight bold :height 1.2))
3628 (t (:weight bold)))
d543e20b 3629 "Face used for low level group tags."
bd042c03 3630 :group 'custom-faces)
d478e69d
MB
3631;; backward-compatibility alias
3632(put 'custom-group-tag-face 'face-alias 'custom-group-tag)
d543e20b
PA
3633
3634(define-widget 'custom-group 'custom
3635 "Customize group."
944c91b6 3636 :format "%v"
d543e20b
PA
3637 :sample-face-get 'custom-group-sample-face-get
3638 :documentation-property 'group-documentation
3639 :help-echo "Set or reset all members of this group."
3640 :value-create 'custom-group-value-create
3641 :action 'custom-group-action
9097aeb7 3642 :custom-category 'group
d543e20b
PA
3643 :custom-set 'custom-group-set
3644 :custom-save 'custom-group-save
3645 :custom-reset-current 'custom-group-reset-current
3646 :custom-reset-saved 'custom-group-reset-saved
25ac13b5 3647 :custom-reset-standard 'custom-group-reset-standard
d543e20b
PA
3648 :custom-menu 'custom-group-menu-create)
3649
3650(defun custom-group-sample-face-get (widget)
3651 ;; Use :sample-face.
3652 (or (nth (1- (widget-get widget :custom-level)) custom-group-tag-faces)
d478e69d 3653 'custom-group-tag))
d543e20b 3654
8691cfa7
RS
3655(define-widget 'custom-group-visibility 'visibility
3656 "An indicator and manipulator for hidden group contents."
3657 :create 'custom-group-visibility-create)
3658
3659(defun custom-group-visibility-create (widget)
3660 (let ((visible (widget-value widget)))
3661 (if visible
3662 (insert "--------")))
3663 (widget-default-create widget))
3664
4ee1cf9f
PA
3665(defun custom-group-members (symbol groups-only)
3666 "Return SYMBOL's custom group members.
3667If GROUPS-ONLY non-nil, return only those members that are groups."
3668 (if (not groups-only)
3669 (get symbol 'custom-group)
3670 (let (members)
3671 (dolist (entry (get symbol 'custom-group))
3672 (when (eq (nth 1 entry) 'custom-group)
3673 (push entry members)))
3674 (nreverse members))))
3675
d543e20b 3676(defun custom-group-value-create (widget)
944c91b6 3677 "Insert a customize group for WIDGET in the current buffer."
2de2cb02 3678 (unless (eq (widget-get widget :custom-state) 'hidden)
2ee398c4 3679 (custom-load-widget widget))
4ee1cf9f
PA
3680 (let* ((state (widget-get widget :custom-state))
3681 (level (widget-get widget :custom-level))
f985c5f7 3682 ;; (indent (widget-get widget :indent))
4ee1cf9f
PA
3683 (prefix (widget-get widget :custom-prefix))
3684 (buttons (widget-get widget :buttons))
3685 (tag (widget-get widget :tag))
3686 (symbol (widget-value widget))
3687 (members (custom-group-members symbol
3688 (and (eq custom-buffer-style 'tree)
3689 custom-browse-only-groups))))
944c91b6 3690 (cond ((and (eq custom-buffer-style 'tree)
c953515e 3691 (eq state 'hidden)
4ee1cf9f 3692 (or members (custom-unloaded-widget-p widget)))
c953515e 3693 (custom-browse-insert-prefix prefix)
944c91b6 3694 (push (widget-create-child-and-convert
d3d4df42 3695 widget 'custom-browse-visibility
da5ec617 3696 ;; :tag-glyph "plus"
df816618 3697 :tag "+")
944c91b6
PA
3698 buttons)
3699 (insert "-- ")
da5ec617 3700 ;; (widget-glyph-insert nil "-- " "horizontal")
944c91b6 3701 (push (widget-create-child-and-convert
c953515e 3702 widget 'custom-browse-group-tag)
944c91b6
PA
3703 buttons)
3704 (insert " " tag "\n")
3705 (widget-put widget :buttons buttons))
3706 ((and (eq custom-buffer-style 'tree)
4ee1cf9f 3707 (zerop (length members)))
c953515e 3708 (custom-browse-insert-prefix prefix)
da5ec617
PA
3709 (insert "[ ]-- ")
3710 ;; (widget-glyph-insert nil "[ ]" "empty")
3711 ;; (widget-glyph-insert nil "-- " "horizontal")
d3d4df42 3712 (push (widget-create-child-and-convert
c953515e 3713 widget 'custom-browse-group-tag)
944c91b6
PA
3714 buttons)
3715 (insert " " tag "\n")
3716 (widget-put widget :buttons buttons))
3717 ((eq custom-buffer-style 'tree)
c953515e 3718 (custom-browse-insert-prefix prefix)
4ee1cf9f 3719 (if (zerop (length members))
d3d4df42 3720 (progn
c953515e 3721 (custom-browse-insert-prefix prefix)
da5ec617
PA
3722 (insert "[ ]-- ")
3723 ;; (widget-glyph-insert nil "[ ]" "empty")
3724 ;; (widget-glyph-insert nil "-- " "horizontal")
d3d4df42 3725 (push (widget-create-child-and-convert
c953515e 3726 widget 'custom-browse-group-tag)
944c91b6
PA
3727 buttons)
3728 (insert " " tag "\n")
3729 (widget-put widget :buttons buttons))
d3d4df42
DL
3730 (push (widget-create-child-and-convert
3731 widget 'custom-browse-visibility
da5ec617
PA
3732 ;; :tag-glyph "minus"
3733 :tag "-")
944c91b6 3734 buttons)
da5ec617
PA
3735 (insert "-\\ ")
3736 ;; (widget-glyph-insert nil "-\\ " "top")
d3d4df42 3737 (push (widget-create-child-and-convert
c953515e 3738 widget 'custom-browse-group-tag)
944c91b6
PA
3739 buttons)
3740 (insert " " tag "\n")
3741 (widget-put widget :buttons buttons)
3742 (message "Creating group...")
4ee1cf9f 3743 (let* ((members (custom-sort-items members
da5ec617
PA
3744 custom-browse-sort-alphabetically
3745 custom-browse-order-groups))
944c91b6
PA
3746 (prefixes (widget-get widget :custom-prefixes))
3747 (custom-prefix-list (custom-prefix-add symbol prefixes))
944c91b6
PA
3748 (extra-prefix (if (widget-get widget :custom-last)
3749 " "
3750 " | "))
3751 (prefix (concat prefix extra-prefix))
3752 children entry)
3753 (while members
3754 (setq entry (car members)
3755 members (cdr members))
4ee1cf9f
PA
3756 (push (widget-create-child-and-convert
3757 widget (nth 1 entry)
3758 :group widget
3759 :tag (custom-unlispify-tag-name (nth 0 entry))
3760 :custom-prefixes custom-prefix-list
3761 :custom-level (1+ level)
3762 :custom-last (null members)
3763 :value (nth 0 entry)
3764 :custom-prefix prefix)
3765 children))
944c91b6
PA
3766 (widget-put widget :children (reverse children)))
3767 (message "Creating group...done")))
3768 ;; Nested style.
3769 ((eq state 'hidden)
3770 ;; Create level indicator.
26c7b3ef
RS
3771 (unless (eq custom-buffer-style 'links)
3772 (insert-char ?\ (* custom-buffer-indent (1- level)))
3773 (insert "-- "))
944c91b6
PA
3774 ;; Create tag.
3775 (let ((begin (point)))
3776 (insert tag)
3777 (widget-specify-sample widget begin (point)))
3778 (insert " group: ")
3779 ;; Create link/visibility indicator.
3780 (if (eq custom-buffer-style 'links)
3781 (push (widget-create-child-and-convert
d3d4df42 3782 widget 'custom-group-link
0c731046
CY
3783 :button-face 'custom-link
3784 :mouse-face 'highlight
b62c92bb 3785 :tag "Go to Group"
944c91b6
PA
3786 symbol)
3787 buttons)
d3d4df42 3788 (push (widget-create-child-and-convert
98d5aafe 3789 widget 'custom-group-visibility
944c91b6
PA
3790 :help-echo "Show members of this group."
3791 :action 'custom-toggle-parent
3792 (not (eq state 'hidden)))
3793 buttons))
3794 (insert " \n")
3795 ;; Create magic button.
3796 (let ((magic (widget-create-child-and-convert
3797 widget 'custom-magic nil)))
3798 (widget-put widget :custom-magic magic)
3799 (push magic buttons))
3800 ;; Update buttons.
3801 (widget-put widget :buttons buttons)
3802 ;; Insert documentation.
26c7b3ef
RS
3803 (if (and (eq custom-buffer-style 'links) (> level 1))
3804 (widget-put widget :documentation-indent 0))
944c91b6
PA
3805 (widget-default-format-handler widget ?h))
3806 ;; Nested style.
3807 (t ;Visible.
d377bee9
RS
3808 ;; Add parent groups references above the group.
3809 (if t ;;; This should test that the buffer
3810 ;;; was made to display a group.
3811 (when (eq level 1)
cd6c0940
RS
3812 (if (custom-add-parent-links widget
3813 "Go to parent group:")
d377bee9 3814 (insert "\n"))))
944c91b6
PA
3815 ;; Create level indicator.
3816 (insert-char ?\ (* custom-buffer-indent (1- level)))
3817 (insert "/- ")
3818 ;; Create tag.
3819 (let ((start (point)))
3820 (insert tag)
3821 (widget-specify-sample widget start (point)))
3822 (insert " group: ")
3823 ;; Create visibility indicator.
3824 (unless (eq custom-buffer-style 'links)
3825 (insert "--------")
d3d4df42 3826 (push (widget-create-child-and-convert
944c91b6
PA
3827 widget 'visibility
3828 :help-echo "Hide members of this group."
3829 :action 'custom-toggle-parent
3830 (not (eq state 'hidden)))
3831 buttons)
3832 (insert " "))
3833 ;; Create more dashes.
3834 ;; Use 76 instead of 75 to compensate for the temporary "<"
d3d4df42 3835 ;; added by `widget-insert'.
944c91b6
PA
3836 (insert-char ?- (- 76 (current-column)
3837 (* custom-buffer-indent level)))
3838 (insert "\\\n")
3839 ;; Create magic button.
3840 (let ((magic (widget-create-child-and-convert
d3d4df42 3841 widget 'custom-magic
944c91b6
PA
3842 :indent 0
3843 nil)))
3844 (widget-put widget :custom-magic magic)
3845 (push magic buttons))
3846 ;; Update buttons.
3847 (widget-put widget :buttons buttons)
3848 ;; Insert documentation.
3849 (widget-default-format-handler widget ?h)
d377bee9
RS
3850 ;; Parent groups.
3851 (if nil ;;; This should test that the buffer
3852 ;;; was not made to display a group.
3853 (when (eq level 1)
3854 (insert-char ?\ custom-buffer-indent)
3855 (custom-add-parent-links widget)))
d3d4df42 3856 (custom-add-see-also widget
944c91b6
PA
3857 (make-string (* custom-buffer-indent level)
3858 ?\ ))
3859 ;; Members.
3860 (message "Creating group...")
4ee1cf9f 3861 (let* ((members (custom-sort-items members
da5ec617
PA
3862 custom-buffer-sort-alphabetically
3863 custom-buffer-order-groups))
944c91b6
PA
3864 (prefixes (widget-get widget :custom-prefixes))
3865 (custom-prefix-list (custom-prefix-add symbol prefixes))
3866 (length (length members))
3867 (count 0)
3868 (children (mapcar (lambda (entry)
3869 (widget-insert "\n")
3870 (message "\
3871Creating group members... %2d%%"
3872 (/ (* 100.0 count) length))
3873 (setq count (1+ count))
3874 (prog1
3875 (widget-create-child-and-convert
3876 widget (nth 1 entry)
3877 :group widget
3878 :tag (custom-unlispify-tag-name
3879 (nth 0 entry))
3880 :custom-prefixes custom-prefix-list
3881 :custom-level (1+ level)
3882 :value (nth 0 entry))
3883 (unless (eq (preceding-char) ?\n)
3884 (widget-insert "\n"))))
3885 members)))
3886 (message "Creating group magic...")
fadbdfea 3887 (mapc 'custom-magic-reset children)
944c91b6
PA
3888 (message "Creating group state...")
3889 (widget-put widget :children children)
3890 (custom-group-state-update widget)
3891 (message "Creating group... done"))
3892 ;; End line
3893 (insert "\n")
3894 (insert-char ?\ (* custom-buffer-indent (1- level)))
3895 (insert "\\- " (widget-get widget :tag) " group end ")
3896 (insert-char ?- (- 75 (current-column) (* custom-buffer-indent level)))
3897 (insert "/\n")))))
d543e20b 3898
d3d4df42 3899(defvar custom-group-menu
eaa99205
CY
3900 `(("Set for current session" custom-group-set
3901 (lambda (widget)
3902 (eq (widget-get widget :custom-state) 'modified)))
3903 ,@(when (or custom-file user-init-file)
3904 '(("Save for future sessions" custom-group-save
3905 (lambda (widget)
3906 (memq (widget-get widget :custom-state) '(modified set))))))
3907 ("---" ignore ignore)
3908 ("Reset to current settings" custom-group-reset-current
6d528fc5 3909 (lambda (widget)
86bd10bc 3910 (memq (widget-get widget :custom-state) '(modified))))
0c731046 3911 ("Reset to saved settings" custom-group-reset-saved
6d528fc5 3912 (lambda (widget)
86bd10bc 3913 (memq (widget-get widget :custom-state) '(modified set))))
0a57ffed 3914 ,@(when (or custom-file user-init-file)
0c731046 3915 '(("Reset to standard settings" custom-group-reset-standard
73e60f53 3916 (lambda (widget)
eaa99205 3917 (memq (widget-get widget :custom-state) '(modified set saved)))))))
d543e20b 3918 "Alist of actions for the `custom-group' widget.
6d528fc5
PA
3919Each entry has the form (NAME ACTION FILTER) where NAME is the name of
3920the menu entry, ACTION is the function to call on the widget when the
3921menu is selected, and FILTER is a predicate which takes a `custom-group'
3922widget as an argument, and returns non-nil if ACTION is valid on that
d3d4df42 3923widget. If FILTER is nil, ACTION is always valid.")
d543e20b
PA
3924
3925(defun custom-group-action (widget &optional event)
3926 "Show the menu for `custom-group' WIDGET.
3927Optional EVENT is the location for the menu."
3928 (if (eq (widget-get widget :custom-state) 'hidden)
6d528fc5 3929 (custom-toggle-hide widget)
d543e20b 3930 (let* ((completion-ignore-case t)
25ac13b5
PA
3931 (answer (widget-choose (concat "Operation on "
3932 (custom-unlispify-tag-name
3933 (widget-get widget :value)))
6d528fc5
PA
3934 (custom-menu-filter custom-group-menu
3935 widget)
d543e20b
PA
3936 event)))
3937 (if answer
3938 (funcall answer widget)))))
3939
3940(defun custom-group-set (widget)
3941 "Set changes in all modified group members."
3942 (let ((children (widget-get widget :children)))
fadbdfea
DL
3943 (mapc (lambda (child)
3944 (when (eq (widget-get child :custom-state) 'modified)
3945 (widget-apply child :custom-set)))
d543e20b
PA
3946 children )))
3947
3948(defun custom-group-save (widget)
3949 "Save all modified group members."
3950 (let ((children (widget-get widget :children)))
fadbdfea
DL
3951 (mapc (lambda (child)
3952 (when (memq (widget-get child :custom-state) '(modified set))
3953 (widget-apply child :custom-save)))
d543e20b
PA
3954 children )))
3955
3956(defun custom-group-reset-current (widget)
3957 "Reset all modified group members."
3958 (let ((children (widget-get widget :children)))
fadbdfea
DL
3959 (mapc (lambda (child)
3960 (when (eq (widget-get child :custom-state) 'modified)
3961 (widget-apply child :custom-reset-current)))
d543e20b
PA
3962 children )))
3963
3964(defun custom-group-reset-saved (widget)
3965 "Reset all modified or set group members."
3966 (let ((children (widget-get widget :children)))
fadbdfea
DL
3967 (mapc (lambda (child)
3968 (when (memq (widget-get child :custom-state) '(modified set))
3969 (widget-apply child :custom-reset-saved)))
d543e20b
PA
3970 children )))
3971
25ac13b5 3972(defun custom-group-reset-standard (widget)
d543e20b
PA
3973 "Reset all modified, set, or saved group members."
3974 (let ((children (widget-get widget :children)))
fadbdfea
DL
3975 (mapc (lambda (child)
3976 (when (memq (widget-get child :custom-state)
3977 '(modified set saved))
3978 (widget-apply child :custom-reset-standard)))
d543e20b
PA
3979 children )))
3980
3981(defun custom-group-state-update (widget)
3982 "Update magic."
3983 (unless (eq (widget-get widget :custom-state) 'hidden)
3984 (let* ((children (widget-get widget :children))
3985 (states (mapcar (lambda (child)
3986 (widget-get child :custom-state))
3987 children))
25ac13b5
PA
3988 (magics custom-magic-alist)
3989 (found 'standard))
d543e20b
PA
3990 (while magics
3991 (let ((magic (car (car magics))))
3992 (if (and (not (eq magic 'hidden))
3993 (memq magic states))
3994 (setq found magic
3995 magics nil)
3996 (setq magics (cdr magics)))))
3997 (widget-put widget :custom-state found)))
3998 (custom-magic-reset widget))
f8d869d1
RS
3999\f
4000;;; Reading and writing the custom file.
d543e20b 4001
a1a4fa22 4002;;;###autoload
1e4ed6df 4003(defcustom custom-file nil
d543e20b 4004 "File used for storing customization information.
1e4ed6df 4005The default is nil, which means to use your init file
09b73f49
RS
4006as specified by `user-init-file'. If the value is not nil,
4007it should be an absolute file name.
4008
5aa971e3
LT
4009You can set this option through Custom, if you carefully read the
4010last paragraph below. However, usually it is simpler to write
4011something like the following in your init file:
4012
4013\(setq custom-file \"~/.emacs-custom.el\")
4014\(load custom-file)
4015
4016Note that both lines are necessary: the first line tells Custom to
4017save all customizations in this file, but does not load it.
4018
4019When you change this variable outside Custom, look in the
4020previous custom file \(usually your init file) for the
4021forms `(custom-set-variables ...)' and `(custom-set-faces ...)',
4022and copy them (whichever ones you find) to the new custom file.
4023This will preserve your existing customizations.
4024
4025If you save this option using Custom, Custom will write all
4026currently saved customizations, including the new one for this
4027option itself, into the file you specify, overwriting any
4028`custom-set-variables' and `custom-set-faces' forms already
4029present in that file. It will not delete any customizations from
4030the old custom file. You should do that manually if that is what you
4031want. You also have to put something like `\(load \"CUSTOM-FILE\")
4032in your init file, where CUSTOM-FILE is the actual name of the
4033file. Otherwise, Emacs will not load the file when it starts up,
4034and hence will not set `custom-file' to that file either."
4035 :type '(choice (const :tag "Your Emacs init file" nil)
4036 (file :format "%t:%v%d"
4037 :doc
4038 "Please read entire docstring below before setting \
4039this through Custom.
4040Click om \"More\" \(or position point there and press RETURN)
4041if only the first line of the docstring is shown."))
d543e20b
PA
4042 :group 'customize)
4043
176eb8cb
KH
4044(defun custom-file ()
4045 "Return the file name for saving customizations."
541044b0
RS
4046 (file-chase-links
4047 (or custom-file
4048 (let ((user-init-file user-init-file)
4049 (default-init-file
4050 (if (eq system-type 'ms-dos) "~/_emacs" "~/.emacs")))
4051 (when (null user-init-file)
4052 (if (or (file-exists-p default-init-file)
4053 (and (eq system-type 'windows-nt)
4054 (file-exists-p "~/_emacs")))
4055 ;; Started with -q, i.e. the file containing
4056 ;; Custom settings hasn't been read. Saving
4057 ;; settings there would overwrite other settings.
4058 (error "Saving settings from \"emacs -q\" would overwrite existing customizations"))
4059 (setq user-init-file default-init-file))
4060 user-init-file))))
176eb8cb 4061
f8d869d1
RS
4062;;;###autoload
4063(defun custom-save-all ()
4064 "Save all customizations in `custom-file'."
4065 (let* ((filename (custom-file))
4066 (recentf-exclude (if recentf-mode
4067 (cons (concat "\\`"
4068 (regexp-quote (custom-file))
4069 "\\'")
4070 recentf-exclude)))
4071 (old-buffer (find-buffer-visiting filename)))
4072 (with-current-buffer (or old-buffer (find-file-noselect filename))
4073 (let ((inhibit-read-only t))
4074 (custom-save-variables)
4075 (custom-save-faces))
4076 (let ((file-precious-flag t))
4077 (save-buffer))
4078 (unless old-buffer
4079 (kill-buffer (current-buffer))))))
16ecd4c5
RS
4080
4081;;;###autoload
4082(defun customize-save-customized ()
4083 "Save all user options which have been set in this session."
4084 (interactive)
4085 (mapatoms (lambda (symbol)
4086 (let ((face (get symbol 'customized-face))
4087 (value (get symbol 'customized-value))
4088 (face-comment (get symbol 'customized-face-comment))
4089 (variable-comment
4090 (get symbol 'customized-variable-comment)))
4091 (when face
4092 (put symbol 'saved-face face)
4093 (custom-push-theme 'theme-face symbol 'user 'set value)
4094 (put symbol 'customized-face nil))
4095 (when value
4096 (put symbol 'saved-value value)
4097 (custom-push-theme 'theme-value symbol 'user 'set value)
4098 (put symbol 'customized-value nil))
4099 (when variable-comment
4100 (put symbol 'saved-variable-comment variable-comment)
4101 (put symbol 'customized-variable-comment nil))
4102 (when face-comment
4103 (put symbol 'saved-face-comment face-comment)
4104 (put symbol 'customized-face-comment nil)))))
4105 ;; We really should update all custom buffers here.
4106 (custom-save-all))
f8d869d1
RS
4107\f
4108;; Editing the custom file contents in a buffer.
4109
d543e20b 4110(defun custom-save-delete (symbol)
f8d869d1 4111 "Delete all calls to SYMBOL from the contents of the current buffer.
a34511a1 4112Leave point at the old location of the first such call,
f8d869d1
RS
4113or (if there were none) at the end of the buffer.
4114
4115This function does not save the buffer."
d543e20b 4116 (goto-char (point-min))
cbe8bb8e
KH
4117 ;; Skip all whitespace and comments.
4118 (while (forward-comment 1))
4119 (or (eobp)
4120 (save-excursion (forward-sexp (buffer-size)))) ; Test for scan errors.
a34511a1
RS
4121 (let (first)
4122 (catch 'found
4123 (while t ;; We exit this loop only via throw.
4124 ;; Skip all whitespace and comments.
4125 (while (forward-comment 1))
4126 (let ((start (point))
4127 (sexp (condition-case nil
4128 (read (current-buffer))
4129 (end-of-file (throw 'found nil)))))
4130 (when (and (listp sexp)
4131 (eq (car sexp) symbol))
4132 (delete-region start (point))
4133 (unless first
4134 (setq first (point)))))))
4135 (if first
4136 (goto-char first)
189638d5
GM
4137 ;; Move in front of local variables, otherwise long Custom
4138 ;; entries would make them ineffective.
4139 (let ((pos (point-max))
4140 (case-fold-search t))
4141 (save-excursion
4142 (goto-char (point-max))
4143 (search-backward "\n\^L" (max (- (point-max) 3000) (point-min))
4144 'move)
4145 (when (search-forward "Local Variables:" nil t)
4146 (setq pos (line-beginning-position))))
4147 (goto-char pos)))))
d543e20b
PA
4148
4149(defun custom-save-variables ()
4150 "Save all customized variables in `custom-file'."
4151 (save-excursion
4152 (custom-save-delete 'custom-set-variables)
d151422c
MR
4153 (let ((standard-output (current-buffer))
4154 (saved-list (make-list 1 0))
4155 sort-fold-case)
4156 ;; First create a sorted list of saved variables.
4157 (mapatoms
4158 (lambda (symbol)
d358aa10
CY
4159 (if (and (get symbol 'saved-value)
4160 (eq 'user (car (car-safe (get symbol 'theme-value)))))
d151422c
MR
4161 (nconc saved-list (list symbol)))))
4162 (setq saved-list (sort (cdr saved-list) 'string<))
d543e20b
PA
4163 (unless (bolp)
4164 (princ "\n"))
aec2bb63 4165 (princ "(custom-set-variables
99b398e0
RS
4166 ;; custom-set-variables was added by Custom.
4167 ;; If you edit it by hand, you could mess it up, so be careful.
4168 ;; Your init file should contain only one such instance.
4169 ;; If there is more than one, they won't work right.\n")
d9f67134
SM
4170 (dolist (symbol saved-list)
4171 (let ((spec (car-safe (get symbol 'theme-value)))
4172 (value (get symbol 'saved-value))
4173 (requests (get symbol 'custom-requests))
4174 (now (not (or (custom-variable-p symbol)
4175 (and (not (boundp symbol))
4176 (not (eq (get symbol 'force-value)
4177 'rogue))))))
40627755 4178 (comment (get symbol 'saved-variable-comment)))
d9f67134
SM
4179 ;; Check `requests'.
4180 (dolist (request requests)
4181 (when (and (symbolp request) (not (featurep request)))
4182 (message "Unknown requested feature: %s" request)
4183 (setq requests (delq request requests))))
d358aa10 4184 (when (or (and spec (eq (car spec) 'user))
d9f67134
SM
4185 comment
4186 (and (null spec) (get symbol 'saved-value)))
4187 (unless (bolp)
4188 (princ "\n"))
4189 (princ " '(")
4190 (prin1 symbol)
4191 (princ " ")
4192 (prin1 (car value))
4193 (when (or now requests comment)
4194 (princ " ")
4195 (prin1 now)
4196 (when (or requests comment)
4197 (princ " ")
4198 (prin1 requests)
4199 (when comment
4200 (princ " ")
4201 (prin1 comment))))
4202 (princ ")"))))
a34511a1
RS
4203 (if (bolp)
4204 (princ " "))
d543e20b
PA
4205 (princ ")")
4206 (unless (looking-at "\n")
4207 (princ "\n")))))
4208
4209(defun custom-save-faces ()
4210 "Save all customized faces in `custom-file'."
4211 (save-excursion
c942535f 4212 (custom-save-delete 'custom-reset-faces)
d543e20b 4213 (custom-save-delete 'custom-set-faces)
d151422c
MR
4214 (let ((standard-output (current-buffer))
4215 (saved-list (make-list 1 0))
4216 sort-fold-case)
4217 ;; First create a sorted list of saved faces.
4218 (mapatoms
4219 (lambda (symbol)
d358aa10
CY
4220 (if (and (get symbol 'saved-face)
4221 (eq 'user (car (car-safe (get symbol 'theme-face)))))
d151422c
MR
4222 (nconc saved-list (list symbol)))))
4223 (setq saved-list (sort (cdr saved-list) 'string<))
4224 ;; The default face must be first, since it affects the others.
4225 (if (memq 'default saved-list)
4226 (setq saved-list (cons 'default (delq 'default saved-list))))
d543e20b
PA
4227 (unless (bolp)
4228 (princ "\n"))
aec2bb63 4229 (princ "(custom-set-faces
99b398e0
RS
4230 ;; custom-set-faces was added by Custom.
4231 ;; If you edit it by hand, you could mess it up, so be careful.
4232 ;; Your init file should contain only one such instance.
4233 ;; If there is more than one, they won't work right.\n")
d9f67134
SM
4234 (dolist (symbol saved-list)
4235 (let ((spec (car-safe (get symbol 'theme-face)))
4236 (value (get symbol 'saved-face))
4237 (now (not (or (get symbol 'face-defface-spec)
4238 (and (not (custom-facep symbol))
4239 (not (get symbol 'force-face))))))
4240 (comment (get symbol 'saved-face-comment)))
d358aa10 4241 (when (or (and spec (eq (nth 0 spec) 'user))
d9f67134
SM
4242 comment
4243 (and (null spec) (get symbol 'saved-face)))
4244 ;; Don't print default face here.
4245 (unless (bolp)
4246 (princ "\n"))
4247 (princ " '(")
4248 (prin1 symbol)
4249 (princ " ")
4250 (prin1 value)
4251 (when (or now comment)
4252 (princ " ")
4253 (prin1 now)
4254 (when comment
4255 (princ " ")
4256 (prin1 comment)))
4257 (princ ")"))))
a34511a1
RS
4258 (if (bolp)
4259 (princ " "))
d543e20b
PA
4260 (princ ")")
4261 (unless (looking-at "\n")
08b4ae6c 4262 (princ "\n")))))
f8d869d1 4263\f
d543e20b
PA
4264;;; The Customize Menu.
4265
bd042c03
PA
4266;;; Menu support
4267
25ac13b5
PA
4268(defcustom custom-menu-nesting 2
4269 "Maximum nesting in custom menus."
4270 :type 'integer
6aaedd12 4271 :group 'custom-menu)
d543e20b
PA
4272
4273(defun custom-face-menu-create (widget symbol)
4274 "Ignoring WIDGET, create a menu entry for customization face SYMBOL."
4275 (vector (custom-unlispify-menu-entry symbol)
86bd10bc 4276 `(customize-face ',symbol)
d543e20b
PA
4277 t))
4278
4279(defun custom-variable-menu-create (widget symbol)
4280 "Ignoring WIDGET, create a menu entry for customization variable SYMBOL."
4281 (let ((type (get symbol 'custom-type)))
4282 (unless (listp type)
4283 (setq type (list type)))
4284 (if (and type (widget-get type :custom-menu))
4285 (widget-apply type :custom-menu symbol)
4286 (vector (custom-unlispify-menu-entry symbol)
86bd10bc 4287 `(customize-variable ',symbol)
d543e20b
PA
4288 t))))
4289
bd042c03 4290;; Add checkboxes to boolean variable entries.
d543e20b
PA
4291(widget-put (get 'boolean 'widget-type)
4292 :custom-menu (lambda (widget symbol)
4293 (vector (custom-unlispify-menu-entry symbol)
86bd10bc 4294 `(customize-variable ',symbol)
d543e20b
PA
4295 ':style 'toggle
4296 ':selected symbol)))
4297
d04a3972
DL
4298(defun custom-group-menu-create (widget symbol)
4299 "Ignoring WIDGET, create a menu entry for customization group SYMBOL."
4300 `( ,(custom-unlispify-menu-entry symbol t)
4301 :filter (lambda (&rest junk)
3b2f3d30
SM
4302 (let ((menu (custom-menu-create ',symbol)))
4303 (if (consp menu) (cdr menu) menu)))))
d543e20b 4304
bd042c03
PA
4305;;;###autoload
4306(defun custom-menu-create (symbol)
d543e20b 4307 "Create menu for customization group SYMBOL.
d543e20b 4308The menu is in a format applicable to `easy-menu-define'."
bd042c03 4309 (let* ((item (vector (custom-unlispify-menu-entry symbol)
86bd10bc 4310 `(customize-group ',symbol)
bd042c03
PA
4311 t)))
4312 (if (and (or (not (boundp 'custom-menu-nesting))
4313 (>= custom-menu-nesting 0))
2de2cb02
MR
4314 (progn
4315 (custom-load-symbol symbol)
4316 (< (length (get symbol 'custom-group)) widget-menu-max-size)))
d543e20b 4317 (let ((custom-prefix-list (custom-prefix-add symbol
25ac13b5 4318 custom-prefix-list))
da5ec617
PA
4319 (members (custom-sort-items (get symbol 'custom-group)
4320 custom-menu-sort-alphabetically
4321 custom-menu-order-groups)))
d543e20b
PA
4322 `(,(custom-unlispify-menu-entry symbol t)
4323 ,item
4324 "--"
4325 ,@(mapcar (lambda (entry)
4326 (widget-apply (if (listp (nth 1 entry))
4327 (nth 1 entry)
4328 (list (nth 1 entry)))
4329 :custom-menu (nth 0 entry)))
25ac13b5 4330 members)))
d543e20b
PA
4331 item)))
4332
4333;;;###autoload
bd042c03
PA
4334(defun customize-menu-create (symbol &optional name)
4335 "Return a customize menu for customization group SYMBOL.
d3d4df42 4336If optional NAME is given, use that as the name of the menu.
bd042c03
PA
4337Otherwise the menu will be named `Customize'.
4338The format is suitable for use with `easy-menu-define'."
4339 (unless name
4340 (setq name "Customize"))
d04a3972
DL
4341 `(,name
4342 :filter (lambda (&rest junk)
3b2f3d30
SM
4343 (let ((menu (custom-menu-create ',symbol)))
4344 (if (consp menu) (cdr menu) menu)))))
d543e20b 4345
bd042c03
PA
4346;;; The Custom Mode.
4347
e4105348 4348(defvar custom-mode-map
b92aaee0
SM
4349 ;; This keymap should be dense, but a dense keymap would prevent inheriting
4350 ;; "\r" bindings from the parent map.
e4105348
SM
4351 ;; Actually, this misfeature of dense keymaps was fixed on 2001-11-26.
4352 (let ((map (make-keymap)))
4353 (set-keymap-parent map widget-keymap)
4354 (suppress-keymap map)
4355 (define-key map " " 'scroll-up)
4356 (define-key map "\177" 'scroll-down)
91f48803 4357 (define-key map "\C-c\C-c" 'Custom-set)
e4105348
SM
4358 (define-key map "\C-x\C-s" 'Custom-save)
4359 (define-key map "q" 'Custom-buffer-done)
4360 (define-key map "u" 'Custom-goto-parent)
4361 (define-key map "n" 'widget-forward)
4362 (define-key map "p" 'widget-backward)
e6038ca3 4363 (define-key map [mouse-1] 'widget-move-and-invoke)
e4105348
SM
4364 map)
4365 "Keymap for `custom-mode'.")
0f3335c0 4366
d3d4df42 4367(easy-menu-define Custom-mode-menu
bd042c03
PA
4368 custom-mode-map
4369 "Menu used in customization buffers."
4370 `("Custom"
944c91b6 4371 ,(customize-menu-create 'customize)
ab678382
RS
4372 ["Set" Custom-set t]
4373 ["Save" Custom-save t]
0c731046
CY
4374 ["Reset to current settings" Custom-reset-current t]
4375 ["Reset to saved settings" Custom-reset-saved t]
73e60f53 4376 ["Erase customizations" Custom-reset-standard t]
91f48803 4377 ["Info" (info "(emacs)Easy Customization") t]))
bd042c03 4378
b62c92bb
RS
4379(defun Custom-goto-parent ()
4380 "Go to the parent group listed at the top of this buffer.
4381If several parents are listed, go to the first of them."
4382 (interactive)
4383 (save-excursion
4384 (goto-char (point-min))
4385 (if (search-forward "\nGo to parent group: " nil t)
4386 (let* ((button (get-char-property (point) 'button))
4387 (parent (downcase (widget-get button :tag))))
4388 (customize-group parent)))))
4389
bd042c03 4390(defcustom custom-mode-hook nil
d3d4df42 4391 "Hook called when entering Custom mode."
bd042c03 4392 :type 'hook
6aaedd12 4393 :group 'custom-buffer )
bd042c03 4394
b62c92bb
RS
4395(defun custom-state-buffer-message (widget)
4396 (if (eq (widget-get (widget-get widget :parent) :custom-state) 'modified)
4397 (message "To install your edits, invoke [State] and choose the Set operation")))
8691cfa7 4398
bd042c03
PA
4399(defun custom-mode ()
4400 "Major mode for editing customization buffers.
4401
4402The following commands are available:
4403
4404Move to next button or editable field. \\[widget-forward]
4405Move to previous button or editable field. \\[widget-backward]
4ee1cf9f
PA
4406\\<widget-field-keymap>\
4407Complete content of editable text field. \\[widget-complete]
4408\\<custom-mode-map>\
0f3335c0 4409Invoke button under the mouse pointer. \\[Custom-move-and-invoke]
25ac13b5 4410Invoke button under point. \\[widget-button-press]
107736a2
RS
4411Set all options from current text. \\[Custom-set]
4412Make values in current text permanent. \\[Custom-save]
4413Make text match actual option values. \\[Custom-reset-current]
4414Reset options to permanent settings. \\[Custom-reset-saved]
4415Erase customizations; set options
4416 and buffer text to the standard values. \\[Custom-reset-standard]
bd042c03
PA
4417
4418Entry to this mode calls the value of `custom-mode-hook'
4419if that value is non-nil."
4420 (kill-all-local-variables)
4421 (setq major-mode 'custom-mode
4422 mode-name "Custom")
4423 (use-local-map custom-mode-map)
ab678382 4424 (easy-menu-add Custom-mode-menu)
bd042c03 4425 (make-local-variable 'custom-options)
9b7826f4 4426 (make-local-variable 'custom-local-buffer)
b62c92bb 4427 (make-local-variable 'widget-documentation-face)
d478e69d 4428 (setq widget-documentation-face 'custom-documentation)
3aec85bf 4429 (make-local-variable 'widget-button-face)
87911bdb
CY
4430 (setq widget-button-face custom-button)
4431 (set (make-local-variable 'widget-button-pressed-face) custom-button-pressed)
85a5eb0e 4432 (set (make-local-variable 'widget-mouse-face) custom-button-mouse)
87911bdb 4433
d3d4df42
DL
4434 ;; When possible, use relief for buttons, not bracketing. This test
4435 ;; may not be optimal.
4436 (when custom-raised-buttons
4437 (set (make-local-variable 'widget-push-button-prefix) "")
4438 (set (make-local-variable 'widget-push-button-suffix) "")
4439 (set (make-local-variable 'widget-link-prefix) "")
4440 (set (make-local-variable 'widget-link-suffix) ""))
b62c92bb 4441 (add-hook 'widget-edit-functions 'custom-state-buffer-message nil t)
9598ae53 4442 (run-mode-hooks 'custom-mode-hook))
d543e20b 4443
7f352f86
DL
4444(put 'custom-mode 'mode-class 'special)
4445
2365594b
DL
4446(add-to-list
4447 'debug-ignored-errors
4448 "^No user options have changed defaults in recent Emacs versions$")
4449
d543e20b
PA
4450;;; The End.
4451
4452(provide 'cus-edit)
4453
f7105ede 4454;; arch-tag: 64533aa4-1b1a-48c3-8812-f9dc718e8a6f
d3d4df42 4455;;; cus-edit.el ends here