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