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