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