]> code.delx.au - gnu-emacs/blob - lisp/cus-edit.el
(display-time-string-forms): Test display-time-day-and-date
[gnu-emacs] / lisp / cus-edit.el
1 ;;; cus-edit.el --- Tools for customization Emacs.
2 ;;
3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
4 ;;
5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6 ;; Keywords: help, faces
7 ;; Version: 1.90
8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
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., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
26
27 ;;; Commentary:
28 ;;
29 ;; This file implements the code to create and edit customize buffers.
30 ;;
31 ;; See `custom.el'.
32
33 ;;; Code:
34
35 (require 'cus-face)
36 (require 'wid-edit)
37 (require 'easymenu)
38 (eval-when-compile (require 'cl))
39
40 (condition-case nil
41 (require 'cus-load)
42 (error nil))
43
44 (defun custom-face-display-set (face spec &optional frame)
45 (face-spec-set face spec frame))
46
47 (defun custom-display-match-frame (display frame)
48 (face-spec-set-match-display display frame))
49
50 (define-widget-keywords :custom-prefixes :custom-menu :custom-show
51 :custom-magic :custom-state :custom-level :custom-form
52 :custom-set :custom-save :custom-reset-current :custom-reset-saved
53 :custom-reset-factory)
54
55 (put 'custom-define-hook 'custom-type 'hook)
56 (put 'custom-define-hook 'factory-value '(nil))
57 (custom-add-to-group 'customize 'custom-define-hook 'custom-variable)
58
59 ;;; Customization Groups.
60
61 (defgroup emacs nil
62 "Customization of the One True Editor."
63 :link '(custom-manual "(emacs)Top"))
64
65 ;; Most of these groups are stolen from `finder.el',
66 (defgroup editing nil
67 "Basic text editing facilities."
68 :group 'emacs)
69
70 (defgroup abbrev nil
71 "Abbreviation handling, typing shortcuts, macros."
72 :tag "Abbreviations"
73 :group 'editing)
74
75 (defgroup matching nil
76 "Various sorts of searching and matching."
77 :group 'editing)
78
79 (defgroup emulations nil
80 "Emulations of other editors."
81 :group 'editing)
82
83 (defgroup mouse nil
84 "Mouse support."
85 :group 'editing)
86
87 (defgroup outlines nil
88 "Support for hierarchical outlining."
89 :group 'editing)
90
91 (defgroup external nil
92 "Interfacing to external utilities."
93 :group 'emacs)
94
95 (defgroup bib nil
96 "Code related to the `bib' bibliography processor."
97 :tag "Bibliography"
98 :group 'external)
99
100 (defgroup processes nil
101 "Process, subshell, compilation, and job control support."
102 :group 'external
103 :group 'development)
104
105 (defgroup programming nil
106 "Support for programming in other languages."
107 :group 'emacs)
108
109 (defgroup languages nil
110 "Specialized modes for editing programming languages."
111 :group 'programming)
112
113 (defgroup lisp nil
114 "Lisp support, including Emacs Lisp."
115 :group 'languages
116 :group 'development)
117
118 (defgroup c nil
119 "Support for the C language and related languages."
120 :group 'languages)
121
122 (defgroup tools nil
123 "Programming tools."
124 :group 'programming)
125
126 (defgroup oop nil
127 "Support for object-oriented programming."
128 :group 'programming)
129
130 (defgroup applications nil
131 "Applications written in Emacs."
132 :group 'emacs)
133
134 (defgroup calendar nil
135 "Calendar and time management support."
136 :group 'applications)
137
138 (defgroup mail nil
139 "Modes for electronic-mail handling."
140 :group 'applications)
141
142 (defgroup news nil
143 "Support for netnews reading and posting."
144 :group 'applications)
145
146 (defgroup games nil
147 "Games, jokes and amusements."
148 :group 'applications)
149
150 (defgroup development nil
151 "Support for further development of Emacs."
152 :group 'emacs)
153
154 (defgroup docs nil
155 "Support for Emacs documentation."
156 :group 'development)
157
158 (defgroup extensions nil
159 "Emacs Lisp language extensions."
160 :group 'development)
161
162 (defgroup internal nil
163 "Code for Emacs internals, build process, defaults."
164 :group 'development)
165
166 (defgroup maint nil
167 "Maintenance aids for the Emacs development group."
168 :tag "Maintenance"
169 :group 'development)
170
171 (defgroup environment nil
172 "Fitting Emacs with its environment."
173 :group 'emacs)
174
175 (defgroup comm nil
176 "Communications, networking, remote access to files."
177 :tag "Communication"
178 :group 'environment)
179
180 (defgroup hardware nil
181 "Support for interfacing with exotic hardware."
182 :group 'environment)
183
184 (defgroup terminals nil
185 "Support for terminal types."
186 :group 'environment)
187
188 (defgroup unix nil
189 "Front-ends/assistants for, or emulators of, UNIX features."
190 :group 'environment)
191
192 (defgroup vms nil
193 "Support code for vms."
194 :group 'environment)
195
196 (defgroup i18n nil
197 "Internationalization and alternate character-set support."
198 :group 'environment
199 :group 'editing)
200
201 (defgroup frames nil
202 "Support for Emacs frames and window systems."
203 :group 'environment)
204
205 (defgroup data nil
206 "Support editing files of data."
207 :group 'emacs)
208
209 (defgroup wp nil
210 "Word processing."
211 :group 'emacs)
212
213 (defgroup tex nil
214 "Code related to the TeX formatter."
215 :group 'wp)
216
217 (defgroup faces nil
218 "Support for multiple fonts."
219 :group 'emacs)
220
221 (defgroup hypermedia nil
222 "Support for links between text or other media types."
223 :group 'emacs)
224
225 (defgroup help nil
226 "Support for on-line help systems."
227 :group 'emacs)
228
229 (defgroup local nil
230 "Code local to your site."
231 :group 'emacs)
232
233 (defgroup customize '((widgets custom-group))
234 "Customization of the Customization support."
235 :link '(custom-manual "(custom)Top")
236 :link '(url-link :tag "Development Page"
237 "http://www.dina.kvl.dk/~abraham/custom/")
238 :prefix "custom-"
239 :group 'help)
240
241 (defgroup custom-faces nil
242 "Faces used by customize."
243 :group 'customize
244 :group 'faces)
245
246 (defgroup abbrev-mode nil
247 "Word abbreviations mode."
248 :group 'abbrev)
249
250 (defgroup alloc nil
251 "Storage allocation and gc for GNU Emacs Lisp interpreter."
252 :tag "Storage Allocation"
253 :group 'internal)
254
255 (defgroup undo nil
256 "Undoing changes in buffers."
257 :group 'editing)
258
259 (defgroup modeline nil
260 "Content of the modeline."
261 :group 'environment)
262
263 (defgroup fill nil
264 "Indenting and filling text."
265 :group 'editing)
266
267 (defgroup editing-basics nil
268 "Most basic editing facilities."
269 :group 'editing)
270
271 (defgroup display nil
272 "How characters are displayed in buffers."
273 :group 'environment)
274
275 (defgroup execute nil
276 "Executing external commands."
277 :group 'processes)
278
279 (defgroup installation nil
280 "The Emacs installation."
281 :group 'environment)
282
283 (defgroup dired nil
284 "Directory editing."
285 :group 'environment)
286
287 (defgroup limits nil
288 "Internal Emacs limits."
289 :group 'internal)
290
291 (defgroup debug nil
292 "Debugging Emacs itself."
293 :group 'development)
294
295 (defgroup minibuffer nil
296 "Controling the behaviour of the minibuffer."
297 :group 'environment)
298
299 (defgroup keyboard nil
300 "Input from the keyboard."
301 :group 'environment)
302
303 (defgroup mouse nil
304 "Input from the mouse."
305 :group 'environment)
306
307 (defgroup menu nil
308 "Input from the menus."
309 :group 'environment)
310
311 (defgroup auto-save nil
312 "Preventing accidential loss of data."
313 :group 'data)
314
315 (defgroup processes-basics nil
316 "Basic stuff dealing with processes."
317 :group 'processes)
318
319 (defgroup windows nil
320 "Windows within a frame."
321 :group 'processes)
322
323 ;;; Utilities.
324
325 (defun custom-quote (sexp)
326 "Quote SEXP iff it is not self quoting."
327 (if (or (memq sexp '(t nil))
328 (and (symbolp sexp)
329 (eq (aref (symbol-name sexp) 0) ?:))
330 (and (listp sexp)
331 (memq (car sexp) '(lambda)))
332 (stringp sexp)
333 (numberp sexp)
334 (and (fboundp 'characterp)
335 (characterp sexp)))
336 sexp
337 (list 'quote sexp)))
338
339 (defun custom-split-regexp-maybe (regexp)
340 "If REGEXP is a string, split it to a list at `\\|'.
341 You can get the original back with from the result with:
342 (mapconcat 'identity result \"\\|\")
343
344 IF REGEXP is not a string, return it unchanged."
345 (if (stringp regexp)
346 (let ((start 0)
347 all)
348 (while (string-match "\\\\|" regexp start)
349 (setq all (cons (substring regexp start (match-beginning 0)) all)
350 start (match-end 0)))
351 (nreverse (cons (substring regexp start) all)))
352 regexp))
353
354 (defun custom-variable-prompt ()
355 ;; Code stolen from `help.el'.
356 "Prompt for a variable, defaulting to the variable at point.
357 Return a list suitable for use in `interactive'."
358 (let ((v (variable-at-point))
359 (enable-recursive-minibuffers t)
360 val)
361 (setq val (completing-read
362 (if v
363 (format "Customize variable (default %s): " v)
364 "Customize variable: ")
365 obarray (lambda (symbol)
366 (and (boundp symbol)
367 (or (get symbol 'custom-type)
368 (user-variable-p symbol))))))
369 (list (if (equal val "")
370 v (intern val)))))
371
372 (defun custom-menu-filter (menu widget)
373 "Convert MENU to the form used by `widget-choose'.
374 MENU should be in the same format as `custom-variable-menu'.
375 WIDGET is the widget to apply the filter entries of MENU on."
376 (let ((result nil)
377 current name action filter)
378 (while menu
379 (setq current (car menu)
380 name (nth 0 current)
381 action (nth 1 current)
382 filter (nth 2 current)
383 menu (cdr menu))
384 (if (or (null filter) (funcall filter widget))
385 (push (cons name action) result)
386 (push name result)))
387 (nreverse result)))
388
389 ;;; Unlispify.
390
391 (defvar custom-prefix-list nil
392 "List of prefixes that should be ignored by `custom-unlispify'")
393
394 (defcustom custom-unlispify-menu-entries t
395 "Display menu entries as words instead of symbols if non nil."
396 :group 'customize
397 :type 'boolean)
398
399 (defun custom-unlispify-menu-entry (symbol &optional no-suffix)
400 "Convert symbol into a menu entry."
401 (cond ((not custom-unlispify-menu-entries)
402 (symbol-name symbol))
403 ((get symbol 'custom-tag)
404 (if no-suffix
405 (get symbol 'custom-tag)
406 (concat (get symbol 'custom-tag) "...")))
407 (t
408 (save-excursion
409 (set-buffer (get-buffer-create " *Custom-Work*"))
410 (erase-buffer)
411 (princ symbol (current-buffer))
412 (goto-char (point-min))
413 (when (and (eq (get symbol 'custom-type) 'boolean)
414 (re-search-forward "-p\\'" nil t))
415 (replace-match "" t t)
416 (goto-char (point-min)))
417 (let ((prefixes custom-prefix-list)
418 prefix)
419 (while prefixes
420 (setq prefix (car prefixes))
421 (if (search-forward prefix (+ (point) (length prefix)) t)
422 (progn
423 (setq prefixes nil)
424 (delete-region (point-min) (point)))
425 (setq prefixes (cdr prefixes)))))
426 (subst-char-in-region (point-min) (point-max) ?- ?\ t)
427 (capitalize-region (point-min) (point-max))
428 (unless no-suffix
429 (goto-char (point-max))
430 (insert "..."))
431 (buffer-string)))))
432
433 (defcustom custom-unlispify-tag-names t
434 "Display tag names as words instead of symbols if non nil."
435 :group 'customize
436 :type 'boolean)
437
438 (defun custom-unlispify-tag-name (symbol)
439 "Convert symbol into a menu entry."
440 (let ((custom-unlispify-menu-entries custom-unlispify-tag-names))
441 (custom-unlispify-menu-entry symbol t)))
442
443 (defun custom-prefix-add (symbol prefixes)
444 ;; Addd SYMBOL to list of ignored PREFIXES.
445 (cons (or (get symbol 'custom-prefix)
446 (concat (symbol-name symbol) "-"))
447 prefixes))
448
449 ;;; Guess.
450
451 (defcustom custom-guess-name-alist
452 '(("-p\\'" boolean)
453 ("-hook\\'" hook)
454 ("-face\\'" face)
455 ("-file\\'" file)
456 ("-function\\'" function)
457 ("-functions\\'" (repeat function))
458 ("-list\\'" (repeat sexp))
459 ("-alist\\'" (repeat (cons sexp sexp))))
460 "Alist of (MATCH TYPE).
461
462 MATCH should be a regexp matching the name of a symbol, and TYPE should
463 be a widget suitable for editing the value of that symbol. The TYPE
464 of the first entry where MATCH matches the name of the symbol will be
465 used.
466
467 This is used for guessing the type of variables not declared with
468 customize."
469 :type '(repeat (group (regexp :tag "Match") (sexp :tag "Type")))
470 :group 'customize)
471
472 (defcustom custom-guess-doc-alist
473 '(("\\`\\*?Non-nil " boolean))
474 "Alist of (MATCH TYPE).
475
476 MATCH should be a regexp matching a documentation string, and TYPE
477 should be a widget suitable for editing the value of a variable with
478 that documentation string. The TYPE of the first entry where MATCH
479 matches the name of the symbol will be used.
480
481 This is used for guessing the type of variables not declared with
482 customize."
483 :type '(repeat (group (regexp :tag "Match") (sexp :tag "Type")))
484 :group 'customize)
485
486 (defun custom-guess-type (symbol)
487 "Guess a widget suitable for editing the value of SYMBOL.
488 This is done by matching SYMBOL with `custom-guess-name-alist' and
489 if that fails, the doc string with `custom-guess-doc-alist'."
490 (let ((name (symbol-name symbol))
491 (names custom-guess-name-alist)
492 current found)
493 (while names
494 (setq current (car names)
495 names (cdr names))
496 (when (string-match (nth 0 current) name)
497 (setq found (nth 1 current)
498 names nil)))
499 (unless found
500 (let ((doc (documentation-property symbol 'variable-documentation))
501 (docs custom-guess-doc-alist))
502 (when doc
503 (while docs
504 (setq current (car docs)
505 docs (cdr docs))
506 (when (string-match (nth 0 current) doc)
507 (setq found (nth 1 current)
508 docs nil))))))
509 found))
510
511 ;;; Custom Mode Commands.
512
513 (defvar custom-options nil
514 "Customization widgets in the current buffer.")
515
516 (defun custom-set ()
517 "Set changes in all modified options."
518 (interactive)
519 (let ((children custom-options))
520 (mapcar (lambda (child)
521 (when (eq (widget-get child :custom-state) 'modified)
522 (widget-apply child :custom-set)))
523 children)))
524
525 (defun custom-save ()
526 "Set all modified group members and save them."
527 (interactive)
528 (let ((children custom-options))
529 (mapcar (lambda (child)
530 (when (memq (widget-get child :custom-state) '(modified set))
531 (widget-apply child :custom-save)))
532 children))
533 (custom-save-all))
534
535 (defvar custom-reset-menu
536 '(("Current" . custom-reset-current)
537 ("Saved" . custom-reset-saved)
538 ("Factory Settings" . custom-reset-factory))
539 "Alist of actions for the `Reset' button.
540 The key is a string containing the name of the action, the value is a
541 lisp function taking the widget as an element which will be called
542 when the action is chosen.")
543
544 (defun custom-reset (event)
545 "Select item from reset menu."
546 (let* ((completion-ignore-case t)
547 (answer (widget-choose "Reset to"
548 custom-reset-menu
549 event)))
550 (if answer
551 (funcall answer))))
552
553 (defun custom-reset-current ()
554 "Reset all modified group members to their current value."
555 (interactive)
556 (let ((children custom-options))
557 (mapcar (lambda (child)
558 (when (eq (widget-get child :custom-state) 'modified)
559 (widget-apply child :custom-reset-current)))
560 children)))
561
562 (defun custom-reset-saved ()
563 "Reset all modified or set group members to their saved value."
564 (interactive)
565 (let ((children custom-options))
566 (mapcar (lambda (child)
567 (when (eq (widget-get child :custom-state) 'modified)
568 (widget-apply child :custom-reset-current)))
569 children)))
570
571 (defun custom-reset-factory ()
572 "Reset all modified, set, or saved group members to their standard settings."
573 (interactive)
574 (let ((children custom-options))
575 (mapcar (lambda (child)
576 (when (eq (widget-get child :custom-state) 'modified)
577 (widget-apply child :custom-reset-current)))
578 children)))
579
580 ;;; The Customize Commands
581
582 (defun custom-prompt-variable (prompt-var prompt-val)
583 "Prompt for a variable and a value and return them as a list.
584 PROMPT-VAR is the prompt for the variable, and PROMPT-VAL is the
585 prompt for the value. The %s escape in PROMPT-VAL is replaced with
586 the name of the variable.
587
588 If the variable has a `variable-interactive' property, that is used as if
589 it were the arg to `interactive' (which see) to interactively read the value.
590
591 If the variable has a `custom-type' property, it must be a widget and the
592 `:prompt-value' property of that widget will be used for reading the value."
593 (let* ((var (read-variable prompt-var))
594 (minibuffer-help-form '(describe-variable var)))
595 (list var
596 (let ((prop (get var 'variable-interactive))
597 (type (get var 'custom-type))
598 (prompt (format prompt-val var)))
599 (unless (listp type)
600 (setq type (list type)))
601 (cond (prop
602 ;; Use VAR's `variable-interactive' property
603 ;; as an interactive spec for prompting.
604 (call-interactively (list 'lambda '(arg)
605 (list 'interactive prop)
606 'arg)))
607 (type
608 (widget-prompt-value type
609 prompt
610 (if (boundp var)
611 (symbol-value var))
612 (not (boundp var))))
613 (t
614 (eval-minibuffer prompt)))))))
615
616 ;;;###autoload
617 (defun custom-set-value (var val)
618 "Set VARIABLE to VALUE. VALUE is a Lisp object.
619
620 If VARIABLE has a `variable-interactive' property, that is used as if
621 it were the arg to `interactive' (which see) to interactively read the value.
622
623 If VARIABLE has a `custom-type' property, it must be a widget and the
624 `:prompt-value' property of that widget will be used for reading the value."
625 (interactive (custom-prompt-variable "Set variable: "
626 "Set %s to value: "))
627
628 (set var val))
629
630 ;;;###autoload
631 (defun custom-set-variable (var val)
632 "Set the default for VARIABLE to VALUE. VALUE is a Lisp object.
633
634 If VARIABLE has a `custom-set' property, that is used for setting
635 VARIABLE, otherwise `set-default' is used.
636
637 The `customized-value' property of the VARIABLE will be set to a list
638 with a quoted VALUE as its sole list member.
639
640 If VARIABLE has a `variable-interactive' property, that is used as if
641 it were the arg to `interactive' (which see) to interactively read the value.
642
643 If VARIABLE has a `custom-type' property, it must be a widget and the
644 `:prompt-value' property of that widget will be used for reading the value. "
645 (interactive (custom-prompt-variable "Set variable: "
646 "Set customized value for %s to: "))
647 (funcall (or (get var 'custom-set) 'set-default) var val)
648 (put var 'customized-value (list (custom-quote val))))
649
650 ;;;###autoload
651 (defun customize ()
652 "Select a customization buffer which you can use to set user options.
653 User options are structured into \"groups\".
654 Initially the top-level group `Emacs' and its immediate subgroups
655 are shown; the contents of those subgroups are initially hidden."
656 (interactive)
657 (customize 'emacs))
658
659 ;;;###autoload
660 (defun customize-group (group)
661 "Customize GROUP, which must be a customization group."
662 (interactive (list (completing-read "Customize group: (default emacs) "
663 obarray
664 (lambda (symbol)
665 (get symbol 'custom-group))
666 t)))
667
668 (when (stringp group)
669 (if (string-equal "" group)
670 (setq group 'emacs)
671 (setq group (intern group))))
672 (custom-buffer-create (list (list group 'custom-group))))
673
674 ;;;###autoload
675 (defun customize-other-window (symbol)
676 "Customize SYMBOL, which must be a customization group."
677 (interactive (list (completing-read "Customize group: (default emacs) "
678 obarray
679 (lambda (symbol)
680 (get symbol 'custom-group))
681 t)))
682
683 (when (stringp symbol)
684 (if (string-equal "" symbol)
685 (setq symbol 'emacs)
686 (setq symbol (intern symbol))))
687 (custom-buffer-create-other-window (list (list symbol 'custom-group))))
688
689 ;;;###autoload
690 (defun customize-variable (symbol)
691 "Customize SYMBOL, which must be a variable."
692 (interactive (custom-variable-prompt))
693 (custom-buffer-create (list (list symbol 'custom-variable))))
694
695 ;;;###autoload
696 (defun customize-variable-other-window (symbol)
697 "Customize SYMBOL, which must be a variable.
698 Show the buffer in another window, but don't select it."
699 (interactive (custom-variable-prompt))
700 (custom-buffer-create-other-window (list (list symbol 'custom-variable))))
701
702 ;;;###autoload
703 (defun customize-face (&optional symbol)
704 "Customize SYMBOL, which should be a face name or nil.
705 If SYMBOL is nil, customize all faces."
706 (interactive (list (completing-read "Customize face: (default all) "
707 obarray 'custom-facep)))
708 (if (or (null symbol) (and (stringp symbol) (zerop (length symbol))))
709 (let ((found nil))
710 (message "Looking for faces...")
711 (mapcar (lambda (symbol)
712 (setq found (cons (list symbol 'custom-face) found)))
713 (nreverse (mapcar 'intern
714 (sort (mapcar 'symbol-name (face-list))
715 'string<))))
716
717 (custom-buffer-create found))
718 (if (stringp symbol)
719 (setq symbol (intern symbol)))
720 (unless (symbolp symbol)
721 (error "Should be a symbol %S" symbol))
722 (custom-buffer-create (list (list symbol 'custom-face)))))
723
724 ;;;###autoload
725 (defun customize-face-other-window (&optional symbol)
726 "Show customization buffer for FACE in other window."
727 (interactive (list (completing-read "Customize face: "
728 obarray 'custom-facep)))
729 (if (or (null symbol) (and (stringp symbol) (zerop (length symbol))))
730 ()
731 (if (stringp symbol)
732 (setq symbol (intern symbol)))
733 (unless (symbolp symbol)
734 (error "Should be a symbol %S" symbol))
735 (custom-buffer-create-other-window (list (list symbol 'custom-face)))))
736
737 ;;;###autoload
738 (defun customize-customized ()
739 "Customize all user options set since the last save in this session."
740 (interactive)
741 (let ((found nil))
742 (mapatoms (lambda (symbol)
743 (and (get symbol 'customized-face)
744 (custom-facep symbol)
745 (setq found (cons (list symbol 'custom-face) found)))
746 (and (get symbol 'customized-value)
747 (boundp symbol)
748 (setq found
749 (cons (list symbol 'custom-variable) found)))))
750 (if found
751 (custom-buffer-create found)
752 (error "No customized user options"))))
753
754 ;;;###autoload
755 (defun customize-saved ()
756 "Customize all already saved user options."
757 (interactive)
758 (let ((found nil))
759 (mapatoms (lambda (symbol)
760 (and (get symbol 'saved-face)
761 (custom-facep symbol)
762 (setq found (cons (list symbol 'custom-face) found)))
763 (and (get symbol 'saved-value)
764 (boundp symbol)
765 (setq found
766 (cons (list symbol 'custom-variable) found)))))
767 (if found
768 (custom-buffer-create found)
769 (error "No saved user options"))))
770
771 ;;;###autoload
772 (defun customize-apropos (regexp &optional all)
773 "Customize all user options matching REGEXP.
774 If ALL (e.g., started with a prefix key), include options which are not
775 user-settable."
776 (interactive "sCustomize regexp: \nP")
777 (let ((found nil))
778 (mapatoms (lambda (symbol)
779 (when (string-match regexp (symbol-name symbol))
780 (when (get symbol 'custom-group)
781 (setq found (cons (list symbol 'custom-group) found)))
782 (when (custom-facep symbol)
783 (setq found (cons (list symbol 'custom-face) found)))
784 (when (and (boundp symbol)
785 (or (get symbol 'saved-value)
786 (get symbol 'factory-value)
787 (if all
788 (get symbol 'variable-documentation)
789 (user-variable-p symbol))))
790 (setq found
791 (cons (list symbol 'custom-variable) found))))))
792 (if found
793 (custom-buffer-create found)
794 (error "No matches"))))
795
796 ;;; Buffer.
797
798 ;;;###autoload
799 (defun custom-buffer-create (options)
800 "Create a buffer containing OPTIONS.
801 OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where
802 SYMBOL is a customization option, and WIDGET is a widget for editing
803 that option."
804 (kill-buffer (get-buffer-create "*Customization*"))
805 (switch-to-buffer (get-buffer-create "*Customization*"))
806 (custom-buffer-create-internal options))
807
808 ;;;###autoload
809 (defun custom-buffer-create-other-window (options)
810 "Create a buffer containing OPTIONS.
811 OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where
812 SYMBOL is a customization option, and WIDGET is a widget for editing
813 that option."
814 (kill-buffer (get-buffer-create "*Customization*"))
815 (let ((window (selected-window)))
816 (switch-to-buffer-other-window (get-buffer-create "*Customization*"))
817 (custom-buffer-create-internal options)
818 (select-window window)))
819
820
821 (defun custom-buffer-create-internal (options)
822 (message "Creating customization buffer...")
823 (custom-mode)
824 (widget-insert "This is a customization buffer.
825 Push RET or click mouse-2 on the word ")
826 ;; (put-text-property 1 2 'start-open nil)
827 (widget-create 'info-link
828 :tag "help"
829 :help-echo "Read the online help."
830 "(custom)The Customization Buffer")
831 (widget-insert " for more information.\n\n")
832 (setq custom-options
833 (if (= (length options) 1)
834 (mapcar (lambda (entry)
835 (widget-create (nth 1 entry)
836 :custom-state 'unknown
837 :tag (custom-unlispify-tag-name
838 (nth 0 entry))
839 :value (nth 0 entry)))
840 options)
841 (let ((count 0)
842 (length (length options)))
843 (mapcar (lambda (entry)
844 (prog2
845 (message "Creating customization items %2d%%..."
846 (/ (* 100.0 count) length))
847 (widget-create (nth 1 entry)
848 :tag (custom-unlispify-tag-name
849 (nth 0 entry))
850 :value (nth 0 entry))
851 (setq count (1+ count))
852 (unless (eq (preceding-char) ?\n)
853 (widget-insert "\n"))
854 (widget-insert "\n")))
855 options))))
856 (unless (eq (preceding-char) ?\n)
857 (widget-insert "\n"))
858 (widget-insert "\n")
859 (message "Creating customization magic...")
860 (mapcar 'custom-magic-reset custom-options)
861 (message "Creating customization buttons...")
862 (widget-create 'push-button
863 :tag "Set"
864 :help-echo "Set all modifications for this session."
865 :action (lambda (widget &optional event)
866 (custom-set)))
867 (widget-insert " ")
868 (widget-create 'push-button
869 :tag "Save"
870 :help-echo "\
871 Make the modifications default for future sessions."
872 :action (lambda (widget &optional event)
873 (custom-save)))
874 (widget-insert " ")
875 (widget-create 'push-button
876 :tag "Reset"
877 :help-echo "Undo all modifications."
878 :action (lambda (widget &optional event)
879 (custom-reset event)))
880 (widget-insert " ")
881 (widget-create 'push-button
882 :tag "Done"
883 :help-echo "Bury the buffer."
884 :action (lambda (widget &optional event)
885 (bury-buffer)
886 ;; Steal button release event.
887 (if (and (fboundp 'button-press-event-p)
888 (fboundp 'next-command-event))
889 ;; XEmacs
890 (and event
891 (button-press-event-p event)
892 (next-command-event))
893 ;; Emacs
894 (when (memq 'down (event-modifiers event))
895 (read-event)))))
896 (widget-insert "\n")
897 (message "Creating customization setup...")
898 (widget-setup)
899 (goto-char (point-min))
900 (forward-line 3) ;Kludge: bob is writable in XEmacs.
901 (message "Creating customization buffer...done"))
902
903 ;;; Modification of Basic Widgets.
904 ;;
905 ;; We add extra properties to the basic widgets needed here. This is
906 ;; fine, as long as we are careful to stay within out own namespace.
907 ;;
908 ;; We want simple widgets to be displayed by default, but complex
909 ;; widgets to be hidden.
910
911 (widget-put (get 'item 'widget-type) :custom-show t)
912 (widget-put (get 'editable-field 'widget-type)
913 :custom-show (lambda (widget value)
914 (let ((pp (pp-to-string value)))
915 (cond ((string-match "\n" pp)
916 nil)
917 ((> (length pp) 40)
918 nil)
919 (t t)))))
920 (widget-put (get 'menu-choice 'widget-type) :custom-show t)
921
922 ;;; The `custom-manual' Widget.
923
924 (define-widget 'custom-manual 'info-link
925 "Link to the manual entry for this customization option."
926 :help-echo "Read the manual entry for this option."
927 :tag "Manual")
928
929 ;;; The `custom-magic' Widget.
930
931 (defface custom-invalid-face '((((class color))
932 (:foreground "yellow" :background "red"))
933 (t
934 (:bold t :italic t :underline t)))
935 "Face used when the customize item is invalid.")
936
937 (defface custom-rogue-face '((((class color))
938 (:foreground "pink" :background "black"))
939 (t
940 (:underline t)))
941 "Face used when the customize item is not defined for customization.")
942
943 (defface custom-modified-face '((((class color))
944 (:foreground "white" :background "blue"))
945 (t
946 (:italic t :bold)))
947 "Face used when the customize item has been modified.")
948
949 (defface custom-set-face '((((class color))
950 (:foreground "blue" :background "white"))
951 (t
952 (:italic t)))
953 "Face used when the customize item has been set.")
954
955 (defface custom-changed-face '((((class color))
956 (:foreground "white" :background "blue"))
957 (t
958 (:italic t)))
959 "Face used when the customize item has been changed.")
960
961 (defface custom-saved-face '((t (:underline t)))
962 "Face used when the customize item has been saved.")
963
964 (defcustom custom-magic-alist '((nil "#" underline "\
965 uninitialized, you should not see this.")
966 (unknown "?" italic "\
967 unknown, you should not see this.")
968 (hidden "-" default "\
969 hidden, press the state button to show.")
970 (invalid "x" custom-invalid-face "\
971 the value displayed for this item is invalid and cannot be set.")
972 (modified "*" custom-modified-face "\
973 you have edited the item, and can now set it.")
974 (set "+" custom-set-face "\
975 you have set this item, but not saved it.")
976 (changed ":" custom-changed-face "\
977 this item has been changed outside customize.")
978 (saved "!" custom-saved-face "\
979 this item has been saved.")
980 (rogue "@" custom-rogue-face "\
981 this item is not prepared for customization.")
982 (factory " " nil "\
983 this item is unchanged from its standard setting."))
984 "Alist of customize option states.
985 Each entry is of the form (STATE MAGIC FACE DESCRIPTION), where
986
987 STATE is one of the following symbols:
988
989 `nil'
990 For internal use, should never occur.
991 `unknown'
992 For internal use, should never occur.
993 `hidden'
994 This item is not being displayed.
995 `invalid'
996 This item is modified, but has an invalid form.
997 `modified'
998 This item is modified, and has a valid form.
999 `set'
1000 This item has been set but not saved.
1001 `changed'
1002 The current value of this item has been changed temporarily.
1003 `saved'
1004 This item is marked for saving.
1005 `rogue'
1006 This item has no customization information.
1007 `factory'
1008 This item is unchanged from the standard setting.
1009
1010 MAGIC is a string used to present that state.
1011
1012 FACE is a face used to present the state.
1013
1014 DESCRIPTION is a string describing the state.
1015
1016 The list should be sorted most significant first."
1017 :type '(list (checklist :inline t
1018 (group (const nil)
1019 (string :tag "Magic")
1020 face
1021 (string :tag "Description"))
1022 (group (const unknown)
1023 (string :tag "Magic")
1024 face
1025 (string :tag "Description"))
1026 (group (const hidden)
1027 (string :tag "Magic")
1028 face
1029 (string :tag "Description"))
1030 (group (const invalid)
1031 (string :tag "Magic")
1032 face
1033 (string :tag "Description"))
1034 (group (const modified)
1035 (string :tag "Magic")
1036 face
1037 (string :tag "Description"))
1038 (group (const set)
1039 (string :tag "Magic")
1040 face
1041 (string :tag "Description"))
1042 (group (const changed)
1043 (string :tag "Magic")
1044 face
1045 (string :tag "Description"))
1046 (group (const saved)
1047 (string :tag "Magic")
1048 face
1049 (string :tag "Description"))
1050 (group (const rogue)
1051 (string :tag "Magic")
1052 face
1053 (string :tag "Description"))
1054 (group (const factory)
1055 (string :tag "Magic")
1056 face
1057 (string :tag "Description")))
1058 (editable-list :inline t
1059 (group symbol
1060 (string :tag "Magic")
1061 face
1062 (string :tag "Description"))))
1063 :group 'customize
1064 :group 'custom-faces)
1065
1066 (defcustom custom-group-magic-alist '((nil "#" underline "\
1067 uninitialized, you should not see this.")
1068 (unknown "?" italic "\
1069 unknown, you should not see this.")
1070 (hidden "-" default "\
1071 group now hidden; click on the asterisks above to show contents.")
1072 (invalid "x" custom-invalid-face "\
1073 the value displayed for this item is invalid and cannot be set.")
1074 (modified "*" custom-modified-face "\
1075 you have edited something in this group, and can now set it.")
1076 (set "+" custom-set-face "\
1077 something in this group has been set, but not yet saved.")
1078 (changed ":" custom-changed-face "\
1079 this item has been changed outside customize.")
1080 (saved "!" custom-saved-face "\
1081 something in this group has been set and saved.")
1082 (rogue "@" custom-rogue-face "\
1083 this item is not prepared for customization.")
1084 (factory " " nil "\
1085 nothing in this group has been changed."))
1086 "Alist of customize option states.
1087 Each entry is of the form (STATE MAGIC FACE DESCRIPTION), where
1088
1089 STATE is one of the following symbols:
1090
1091 `nil'
1092 For internal use, should never occur.
1093 `unknown'
1094 For internal use, should never occur.
1095 `hidden'
1096 This item is not being displayed.
1097 `invalid'
1098 This item is modified, but has an invalid form.
1099 `modified'
1100 This item is modified, and has a valid form.
1101 `set'
1102 This item has been set but not saved.
1103 `changed'
1104 The current value of this item has been changed temporarily.
1105 `saved'
1106 This item is marked for saving.
1107 `rogue'
1108 This item has no customization information.
1109 `factory'
1110 This item is unchanged from the standard setting.
1111
1112 MAGIC is a string used to present that state.
1113
1114 FACE is a face used to present the state.
1115
1116 DESCRIPTION is a string describing the state.
1117
1118 The list should be sorted most significant first."
1119 :type '(list (checklist :inline t
1120 (group (const nil)
1121 (string :tag "Magic")
1122 face
1123 (string :tag "Description"))
1124 (group (const unknown)
1125 (string :tag "Magic")
1126 face
1127 (string :tag "Description"))
1128 (group (const hidden)
1129 (string :tag "Magic")
1130 face
1131 (string :tag "Description"))
1132 (group (const invalid)
1133 (string :tag "Magic")
1134 face
1135 (string :tag "Description"))
1136 (group (const modified)
1137 (string :tag "Magic")
1138 face
1139 (string :tag "Description"))
1140 (group (const set)
1141 (string :tag "Magic")
1142 face
1143 (string :tag "Description"))
1144 (group (const changed)
1145 (string :tag "Magic")
1146 face
1147 (string :tag "Description"))
1148 (group (const saved)
1149 (string :tag "Magic")
1150 face
1151 (string :tag "Description"))
1152 (group (const rogue)
1153 (string :tag "Magic")
1154 face
1155 (string :tag "Description"))
1156 (group (const factory)
1157 (string :tag "Magic")
1158 face
1159 (string :tag "Description")))
1160 (editable-list :inline t
1161 (group symbol
1162 (string :tag "Magic")
1163 face
1164 (string :tag "Description"))))
1165 :group 'customize
1166 :group 'custom-faces)
1167
1168 (defcustom custom-magic-show 'long
1169 "Show long description of the state of each customization option."
1170 :type '(choice (const :tag "no" nil)
1171 (const short)
1172 (const long))
1173 :group 'customize)
1174
1175 (defcustom custom-magic-show-button t
1176 "Show a magic button indicating the state of each customization option."
1177 :type 'boolean
1178 :group 'customize)
1179
1180 (define-widget 'custom-magic 'default
1181 "Show and manipulate state for a customization option."
1182 :format "%v"
1183 :action 'widget-choice-item-action
1184 :notify 'ignore
1185 :value-get 'ignore
1186 :value-create 'custom-magic-value-create
1187 :value-delete 'widget-children-value-delete)
1188
1189 (defun custom-magic-value-create (widget)
1190 ;; Create compact status report for WIDGET.
1191 (let* ((parent (widget-get widget :parent))
1192 (state (widget-get parent :custom-state))
1193 (entry (assq state (if (eq (car parent) 'custom-group)
1194 custom-group-magic-alist
1195 custom-magic-alist)))
1196 (magic (nth 1 entry))
1197 (face (nth 2 entry))
1198 (text (nth 3 entry))
1199 (lisp (eq (widget-get parent :custom-form) 'lisp))
1200 children)
1201 (when custom-magic-show
1202 (push (widget-create-child-and-convert widget 'choice-item
1203 :help-echo "\
1204 Change the state of this item."
1205 :format "%[%t%]"
1206 :tag "State")
1207 children)
1208 (insert ": ")
1209 (if (eq custom-magic-show 'long)
1210 (insert text)
1211 (insert (symbol-name state)))
1212 (when lisp
1213 (insert " (lisp)"))
1214 (insert "\n"))
1215 (when custom-magic-show-button
1216 (when custom-magic-show
1217 (let ((indent (widget-get parent :indent)))
1218 (when indent
1219 (insert-char ? indent))))
1220 (push (widget-create-child-and-convert widget 'choice-item
1221 :button-face face
1222 :help-echo "Change the state."
1223 :format "%[%t%]"
1224 :tag (if lisp
1225 (concat "(" magic ")")
1226 (concat "[" magic "]")))
1227 children)
1228 (insert " "))
1229 (widget-put widget :children children)))
1230
1231 (defun custom-magic-reset (widget)
1232 "Redraw the :custom-magic property of WIDGET."
1233 (let ((magic (widget-get widget :custom-magic)))
1234 (widget-value-set magic (widget-value magic))))
1235
1236 ;;; The `custom-level' Widget.
1237
1238 (define-widget 'custom-level 'item
1239 "The custom level buttons."
1240 :format "%[%t%]"
1241 :help-echo "Expand or collapse this item."
1242 :action 'custom-level-action)
1243
1244 (defun custom-level-action (widget &optional event)
1245 "Toggle visibility for parent to WIDGET."
1246 (custom-toggle-hide (widget-get widget :parent)))
1247
1248 ;;; The `custom' Widget.
1249
1250 (define-widget 'custom 'default
1251 "Customize a user option."
1252 :convert-widget 'custom-convert-widget
1253 :format "%l%[%t%]: %v%m%h%a"
1254 :format-handler 'custom-format-handler
1255 :notify 'custom-notify
1256 :custom-level 1
1257 :custom-state 'hidden
1258 :documentation-property 'widget-subclass-responsibility
1259 :value-create 'widget-subclass-responsibility
1260 :value-delete 'widget-children-value-delete
1261 :value-get 'widget-item-value-get
1262 :validate 'widget-editable-list-validate
1263 :match (lambda (widget value) (symbolp value)))
1264
1265 (defun custom-convert-widget (widget)
1266 ;; Initialize :value and :tag from :args in WIDGET.
1267 (let ((args (widget-get widget :args)))
1268 (when args
1269 (widget-put widget :value (widget-apply widget
1270 :value-to-internal (car args)))
1271 (widget-put widget :tag (custom-unlispify-tag-name (car args)))
1272 (widget-put widget :args nil)))
1273 widget)
1274
1275 (defun custom-format-handler (widget escape)
1276 ;; We recognize extra escape sequences.
1277 (let* ((buttons (widget-get widget :buttons))
1278 (state (widget-get widget :custom-state))
1279 (level (widget-get widget :custom-level)))
1280 (cond ((eq escape ?l)
1281 (when level
1282 (push (widget-create-child-and-convert
1283 widget 'custom-level (make-string level ?*))
1284 buttons)
1285 (widget-insert " ")
1286 (widget-put widget :buttons buttons)))
1287 ((eq escape ?L)
1288 (when (eq state 'hidden)
1289 (widget-insert " ...")))
1290 ((eq escape ?m)
1291 (and (eq (preceding-char) ?\n)
1292 (widget-get widget :indent)
1293 (insert-char ? (widget-get widget :indent)))
1294 (let ((magic (widget-create-child-and-convert
1295 widget 'custom-magic nil)))
1296 (widget-put widget :custom-magic magic)
1297 (push magic buttons)
1298 (widget-put widget :buttons buttons)))
1299 ((eq escape ?a)
1300 (let* ((symbol (widget-get widget :value))
1301 (links (get symbol 'custom-links))
1302 (many (> (length links) 2)))
1303 (when links
1304 (and (eq (preceding-char) ?\n)
1305 (widget-get widget :indent)
1306 (insert-char ? (widget-get widget :indent)))
1307 (insert "See also ")
1308 (while links
1309 (push (widget-create-child-and-convert widget (car links))
1310 buttons)
1311 (setq links (cdr links))
1312 (cond ((null links)
1313 (insert ".\n"))
1314 ((null (cdr links))
1315 (if many
1316 (insert ", and ")
1317 (insert " and ")))
1318 (t
1319 (insert ", "))))
1320 (widget-put widget :buttons buttons))))
1321 (t
1322 (widget-default-format-handler widget escape)))))
1323
1324 (defun custom-notify (widget &rest args)
1325 "Keep track of changes."
1326 (unless (memq (widget-get widget :custom-state) '(nil unknown hidden))
1327 (widget-put widget :custom-state 'modified))
1328 (let ((buffer-undo-list t))
1329 (custom-magic-reset widget))
1330 (apply 'widget-default-notify widget args))
1331
1332 (defun custom-redraw (widget)
1333 "Redraw WIDGET with current settings."
1334 (let ((line (count-lines (point-min) (point)))
1335 (column (current-column))
1336 (pos (point))
1337 (from (marker-position (widget-get widget :from)))
1338 (to (marker-position (widget-get widget :to))))
1339 (save-excursion
1340 (widget-value-set widget (widget-value widget))
1341 (custom-redraw-magic widget))
1342 (when (and (>= pos from) (<= pos to))
1343 (condition-case nil
1344 (progn
1345 (goto-line line)
1346 (move-to-column column))
1347 (error nil)))))
1348
1349 (defun custom-redraw-magic (widget)
1350 "Redraw WIDGET state with current settings."
1351 (while widget
1352 (let ((magic (widget-get widget :custom-magic)))
1353 (unless magic
1354 (debug))
1355 (widget-value-set magic (widget-value magic))
1356 (when (setq widget (widget-get widget :group))
1357 (custom-group-state-update widget))))
1358 (widget-setup))
1359
1360 (defun custom-show (widget value)
1361 "Non-nil if WIDGET should be shown with VALUE by default."
1362 (let ((show (widget-get widget :custom-show)))
1363 (cond ((null show)
1364 nil)
1365 ((eq t show)
1366 t)
1367 (t
1368 (funcall show widget value)))))
1369
1370 (defvar custom-load-recursion nil
1371 "Hack to avoid recursive dependencies.")
1372
1373 (defun custom-load-symbol (symbol)
1374 "Load all dependencies for SYMBOL."
1375 (unless custom-load-recursion
1376 (let ((custom-load-recursion t)
1377 (loads (get symbol 'custom-loads))
1378 load)
1379 (while loads
1380 (setq load (car loads)
1381 loads (cdr loads))
1382 (cond ((symbolp load)
1383 (condition-case nil
1384 (require load)
1385 (error nil)))
1386 ((assoc load load-history))
1387 (t
1388 (condition-case nil
1389 (load-library load)
1390 (error nil))))))))
1391
1392 (defun custom-load-widget (widget)
1393 "Load all dependencies for WIDGET."
1394 (custom-load-symbol (widget-value widget)))
1395
1396 (defun custom-toggle-hide (widget)
1397 "Toggle visibility of WIDGET."
1398 (let ((state (widget-get widget :custom-state)))
1399 (cond ((memq state '(invalid modified))
1400 (error "There are unset changes"))
1401 ((eq state 'hidden)
1402 (widget-put widget :custom-state 'unknown))
1403 (t
1404 (widget-put widget :custom-state 'hidden)))
1405 (custom-redraw widget)))
1406
1407 ;;; The `custom-variable' Widget.
1408
1409 (defface custom-variable-sample-face '((t (:underline t)))
1410 "Face used for unpushable variable tags."
1411 :group 'custom-faces)
1412
1413 (defface custom-variable-button-face '((t (:underline t :bold t)))
1414 "Face used for pushable variable tags."
1415 :group 'custom-faces)
1416
1417 (define-widget 'custom-variable 'custom
1418 "Customize variable."
1419 :format "%l%v%m%h%a"
1420 :help-echo "Set or reset this variable."
1421 :documentation-property 'variable-documentation
1422 :custom-state nil
1423 :custom-menu 'custom-variable-menu-create
1424 :custom-form 'edit
1425 :value-create 'custom-variable-value-create
1426 :action 'custom-variable-action
1427 :custom-set 'custom-variable-set
1428 :custom-save 'custom-variable-save
1429 :custom-reset-current 'custom-redraw
1430 :custom-reset-saved 'custom-variable-reset-saved
1431 :custom-reset-factory 'custom-variable-reset-factory)
1432
1433 (defun custom-variable-type (symbol)
1434 "Return a widget suitable for editing the value of SYMBOL.
1435 If SYMBOL has a `custom-type' property, use that.
1436 Otherwise, look up symbol in `custom-guess-type-alist'."
1437 (let* ((type (or (get symbol 'custom-type)
1438 (and (not (get symbol 'factory-value))
1439 (custom-guess-type symbol))
1440 'sexp))
1441 (options (get symbol 'custom-options))
1442 (tmp (if (listp type)
1443 (copy-sequence type)
1444 (list type))))
1445 (when options
1446 (widget-put tmp :options options))
1447 tmp))
1448
1449 (defun custom-variable-value-create (widget)
1450 "Here is where you edit the variables value."
1451 (custom-load-widget widget)
1452 (let* ((buttons (widget-get widget :buttons))
1453 (children (widget-get widget :children))
1454 (form (widget-get widget :custom-form))
1455 (state (widget-get widget :custom-state))
1456 (symbol (widget-get widget :value))
1457 (tag (widget-get widget :tag))
1458 (type (custom-variable-type symbol))
1459 (conv (widget-convert type))
1460 (get (or (get symbol 'custom-get) 'default-value))
1461 (set (or (get symbol 'custom-set) 'set-default))
1462 (value (if (default-boundp symbol)
1463 (funcall get symbol)
1464 (widget-get conv :value))))
1465 ;; If the widget is new, the child determine whether it is hidden.
1466 (cond (state)
1467 ((custom-show type value)
1468 (setq state 'unknown))
1469 (t
1470 (setq state 'hidden)))
1471 ;; If we don't know the state, see if we need to edit it in lisp form.
1472 (when (eq state 'unknown)
1473 (unless (widget-apply conv :match value)
1474 ;; (widget-apply (widget-convert type) :match value)
1475 (setq form 'lisp)))
1476 ;; Now we can create the child widget.
1477 (cond ((eq state 'hidden)
1478 ;; Indicate hidden value.
1479 (push (widget-create-child-and-convert
1480 widget 'item
1481 :format "%{%t%}: ..."
1482 :sample-face 'custom-variable-sample-face
1483 :tag tag
1484 :parent widget)
1485 children))
1486 ((eq form 'lisp)
1487 ;; In lisp mode edit the saved value when possible.
1488 (let* ((value (cond ((get symbol 'saved-value)
1489 (car (get symbol 'saved-value)))
1490 ((get symbol 'factory-value)
1491 (car (get symbol 'factory-value)))
1492 ((default-boundp symbol)
1493 (custom-quote (funcall get symbol)))
1494 (t
1495 (custom-quote (widget-get conv :value))))))
1496 (push (widget-create-child-and-convert
1497 widget 'sexp
1498 :button-face 'custom-variable-button-face
1499 :tag (symbol-name symbol)
1500 :parent widget
1501 :value value)
1502 children)))
1503 (t
1504 ;; Edit mode.
1505 (push (widget-create-child-and-convert
1506 widget type
1507 :tag tag
1508 :button-face 'custom-variable-button-face
1509 :sample-face 'custom-variable-sample-face
1510 :value value)
1511 children)))
1512 ;; Now update the state.
1513 (unless (eq (preceding-char) ?\n)
1514 (widget-insert "\n"))
1515 (if (eq state 'hidden)
1516 (widget-put widget :custom-state state)
1517 (custom-variable-state-set widget))
1518 (widget-put widget :custom-form form)
1519 (widget-put widget :buttons buttons)
1520 (widget-put widget :children children)))
1521
1522 (defun custom-variable-state-set (widget)
1523 "Set the state of WIDGET."
1524 (let* ((symbol (widget-value widget))
1525 (get (or (get symbol 'custom-get) 'default-value))
1526 (value (if (default-boundp symbol)
1527 (funcall get symbol)
1528 (widget-get widget :value)))
1529 tmp
1530 (state (cond ((setq tmp (get symbol 'customized-value))
1531 (if (condition-case nil
1532 (equal value (eval (car tmp)))
1533 (error nil))
1534 'set
1535 'changed))
1536 ((setq tmp (get symbol 'saved-value))
1537 (if (condition-case nil
1538 (equal value (eval (car tmp)))
1539 (error nil))
1540 'saved
1541 'changed))
1542 ((setq tmp (get symbol 'factory-value))
1543 (if (condition-case nil
1544 (equal value (eval (car tmp)))
1545 (error nil))
1546 'factory
1547 'changed))
1548 (t 'rogue))))
1549 (widget-put widget :custom-state state)))
1550
1551 (defvar custom-variable-menu
1552 '(("Hide" custom-toggle-hide
1553 (lambda (widget)
1554 (not (memq (widget-get widget :custom-state) '(modified invalid)))))
1555 ("Edit" custom-variable-edit
1556 (lambda (widget)
1557 (not (eq (widget-get widget :custom-form) 'edit))))
1558 ("Edit Lisp" custom-variable-edit-lisp
1559 (lambda (widget)
1560 (not (eq (widget-get widget :custom-form) 'lisp))))
1561 ("Set" custom-variable-set
1562 (lambda (widget)
1563 (eq (widget-get widget :custom-state) 'modified)))
1564 ("Save" custom-variable-save
1565 (lambda (widget)
1566 (memq (widget-get widget :custom-state) '(modified set changed rogue))))
1567 ("Reset to Current" custom-redraw
1568 (lambda (widget)
1569 (and (default-boundp (widget-value widget))
1570 (memq (widget-get widget :custom-state) '(modified)))))
1571 ("Reset to Saved" custom-variable-reset-saved
1572 (lambda (widget)
1573 (and (get (widget-value widget) 'saved-value)
1574 (memq (widget-get widget :custom-state)
1575 '(modified set changed rogue)))))
1576 ("Reset to Standard Settings" custom-variable-reset-factory
1577 (lambda (widget)
1578 (and (get (widget-value widget) 'factory-value)
1579 (memq (widget-get widget :custom-state)
1580 '(modified set changed saved rogue))))))
1581 "Alist of actions for the `custom-variable' widget.
1582 Each entry has the form (NAME ACTION FILTER) where NAME is the name of
1583 the menu entry, ACTION is the function to call on the widget when the
1584 menu is selected, and FILTER is a predicate which takes a `custom-variable'
1585 widget as an argument, and returns non-nil if ACTION is valid on that
1586 widget. If FILTER is nil, ACTION is always valid.")
1587
1588 (defun custom-variable-action (widget &optional event)
1589 "Show the menu for `custom-variable' WIDGET.
1590 Optional EVENT is the location for the menu."
1591 (if (eq (widget-get widget :custom-state) 'hidden)
1592 (custom-toggle-hide widget)
1593 (let* ((completion-ignore-case t)
1594 (answer (widget-choose (custom-unlispify-tag-name
1595 (widget-get widget :value))
1596 (custom-menu-filter custom-variable-menu
1597 widget)
1598 event)))
1599 (if answer
1600 (funcall answer widget)))))
1601
1602 (defun custom-variable-edit (widget)
1603 "Edit value of WIDGET."
1604 (widget-put widget :custom-state 'unknown)
1605 (widget-put widget :custom-form 'edit)
1606 (custom-redraw widget))
1607
1608 (defun custom-variable-edit-lisp (widget)
1609 "Edit the lisp representation of the value of WIDGET."
1610 (widget-put widget :custom-state 'unknown)
1611 (widget-put widget :custom-form 'lisp)
1612 (custom-redraw widget))
1613
1614 (defun custom-variable-set (widget)
1615 "Set the current value for the variable being edited by WIDGET."
1616 (let* ((form (widget-get widget :custom-form))
1617 (state (widget-get widget :custom-state))
1618 (child (car (widget-get widget :children)))
1619 (symbol (widget-value widget))
1620 (set (or (get symbol 'custom-set) 'set-default))
1621 val)
1622 (cond ((eq state 'hidden)
1623 (error "Cannot set hidden variable."))
1624 ((setq val (widget-apply child :validate))
1625 (goto-char (widget-get val :from))
1626 (error "%s" (widget-get val :error)))
1627 ((eq form 'lisp)
1628 (funcall set symbol (eval (setq val (widget-value child))))
1629 (put symbol 'customized-value (list val)))
1630 (t
1631 (funcall set symbol (setq val (widget-value child)))
1632 (put symbol 'customized-value (list (custom-quote val)))))
1633 (custom-variable-state-set widget)
1634 (custom-redraw-magic widget)))
1635
1636 (defun custom-variable-save (widget)
1637 "Set the default value for the variable being edited by WIDGET."
1638 (let* ((form (widget-get widget :custom-form))
1639 (state (widget-get widget :custom-state))
1640 (child (car (widget-get widget :children)))
1641 (symbol (widget-value widget))
1642 (set (or (get symbol 'custom-set) 'set-default))
1643 val)
1644 (cond ((eq state 'hidden)
1645 (error "Cannot set hidden variable."))
1646 ((setq val (widget-apply child :validate))
1647 (goto-char (widget-get val :from))
1648 (error "%s" (widget-get val :error)))
1649 ((eq form 'lisp)
1650 (put symbol 'saved-value (list (widget-value child)))
1651 (funcall set symbol (eval (widget-value child))))
1652 (t
1653 (put symbol
1654 'saved-value (list (custom-quote (widget-value
1655 child))))
1656 (funcall set symbol (widget-value child))))
1657 (put symbol 'customized-value nil)
1658 (custom-save-all)
1659 (custom-variable-state-set widget)
1660 (custom-redraw-magic widget)))
1661
1662 (defun custom-variable-reset-saved (widget)
1663 "Restore the saved value for the variable being edited by WIDGET."
1664 (let* ((symbol (widget-value widget))
1665 (set (or (get symbol 'custom-set) 'set-default)))
1666 (if (get symbol 'saved-value)
1667 (condition-case nil
1668 (funcall set symbol (eval (car (get symbol 'saved-value))))
1669 (error nil))
1670 (error "No saved value for %s" symbol))
1671 (put symbol 'customized-value nil)
1672 (widget-put widget :custom-state 'unknown)
1673 (custom-redraw widget)))
1674
1675 (defun custom-variable-reset-factory (widget)
1676 "Restore the standard setting for the variable being edited by WIDGET."
1677 (let* ((symbol (widget-value widget))
1678 (set (or (get symbol 'custom-set) 'set-default)))
1679 (if (get symbol 'factory-value)
1680 (funcall set symbol (eval (car (get symbol 'factory-value))))
1681 (error "No standard setting known for %S" symbol))
1682 (put symbol 'customized-value nil)
1683 (when (get symbol 'saved-value)
1684 (put symbol 'saved-value nil)
1685 (custom-save-all))
1686 (widget-put widget :custom-state 'unknown)
1687 (custom-redraw widget)))
1688
1689 ;;; The `custom-face-edit' Widget.
1690
1691 (define-widget 'custom-face-edit 'checklist
1692 "Edit face attributes."
1693 :format "%t: %v"
1694 :tag "Attributes"
1695 :extra-offset 12
1696 :button-args '(:help-echo "Control whether this attribute have any effect.")
1697 :args (mapcar (lambda (att)
1698 (list 'group
1699 :inline t
1700 :sibling-args (widget-get (nth 1 att) :sibling-args)
1701 (list 'const :format "" :value (nth 0 att))
1702 (nth 1 att)))
1703 custom-face-attributes))
1704
1705 ;;; The `custom-display' Widget.
1706
1707 (define-widget 'custom-display 'menu-choice
1708 "Select a display type."
1709 :tag "Display"
1710 :value t
1711 :help-echo "Specify frames where the face attributes should be used."
1712 :args '((const :tag "all" t)
1713 (checklist
1714 :offset 0
1715 :extra-offset 9
1716 :args ((group :sibling-args (:help-echo "\
1717 Only match the specified window systems.")
1718 (const :format "Type: "
1719 type)
1720 (checklist :inline t
1721 :offset 0
1722 (const :format "X "
1723 :sibling-args (:help-echo "\
1724 The X11 Window System.")
1725 x)
1726 (const :format "PM "
1727 :sibling-args (:help-echo "\
1728 OS/2 Presentation Manager.")
1729 pm)
1730 (const :format "Win32 "
1731 :sibling-args (:help-echo "\
1732 Windows NT/95/97.")
1733 win32)
1734 (const :format "DOS "
1735 :sibling-args (:help-echo "\
1736 Plain MS-DOS.")
1737 pc)
1738 (const :format "TTY%n"
1739 :sibling-args (:help-echo "\
1740 Plain text terminals.")
1741 tty)))
1742 (group :sibling-args (:help-echo "\
1743 Only match the frames with the specified color support.")
1744 (const :format "Class: "
1745 class)
1746 (checklist :inline t
1747 :offset 0
1748 (const :format "Color "
1749 :sibling-args (:help-echo "\
1750 Match color frames.")
1751 color)
1752 (const :format "Grayscale "
1753 :sibling-args (:help-echo "\
1754 Match grayscale frames.")
1755 grayscale)
1756 (const :format "Monochrome%n"
1757 :sibling-args (:help-echo "\
1758 Match frames with no color support.")
1759 mono)))
1760 (group :sibling-args (:help-echo "\
1761 Only match frames with the specified intensity.")
1762 (const :format "\
1763 Background brightness: "
1764 background)
1765 (checklist :inline t
1766 :offset 0
1767 (const :format "Light "
1768 :sibling-args (:help-echo "\
1769 Match frames with light backgrounds.")
1770 light)
1771 (const :format "Dark\n"
1772 :sibling-args (:help-echo "\
1773 Match frames with dark backgrounds.")
1774 dark)))))))
1775
1776 ;;; The `custom-face' Widget.
1777
1778 (defface custom-face-tag-face '((t (:underline t)))
1779 "Face used for face tags."
1780 :group 'custom-faces)
1781
1782 (define-widget 'custom-face 'custom
1783 "Customize face."
1784 :format "%l%{%t%}: %s%m%h%a%v"
1785 :format-handler 'custom-face-format-handler
1786 :sample-face 'custom-face-tag-face
1787 :help-echo "Set or reset this face."
1788 :documentation-property '(lambda (face)
1789 (face-doc-string face))
1790 :value-create 'custom-face-value-create
1791 :action 'custom-face-action
1792 :custom-form 'selected
1793 :custom-set 'custom-face-set
1794 :custom-save 'custom-face-save
1795 :custom-reset-current 'custom-redraw
1796 :custom-reset-saved 'custom-face-reset-saved
1797 :custom-reset-factory 'custom-face-reset-factory
1798 :custom-menu 'custom-face-menu-create)
1799
1800 (defun custom-face-format-handler (widget escape)
1801 ;; We recognize extra escape sequences.
1802 (let (child
1803 (symbol (widget-get widget :value)))
1804 (cond ((eq escape ?s)
1805 (and (string-match "XEmacs" emacs-version)
1806 ;; XEmacs cannot display initialized faces.
1807 (not (custom-facep symbol))
1808 (copy-face 'custom-face-empty symbol))
1809 (setq child (widget-create-child-and-convert
1810 widget 'item
1811 :format "(%{%t%})\n"
1812 :sample-face symbol
1813 :tag "sample")))
1814 (t
1815 (custom-format-handler widget escape)))
1816 (when child
1817 (widget-put widget
1818 :buttons (cons child (widget-get widget :buttons))))))
1819
1820 (define-widget 'custom-face-all 'editable-list
1821 "An editable list of display specifications and attributes."
1822 :entry-format "%i %d %v"
1823 :insert-button-args '(:help-echo "Insert new display specification here.")
1824 :append-button-args '(:help-echo "Append new display specification here.")
1825 :delete-button-args '(:help-echo "Delete this display specification.")
1826 :args '((group :format "%v" custom-display custom-face-edit)))
1827
1828 (defconst custom-face-all (widget-convert 'custom-face-all)
1829 "Converted version of the `custom-face-all' widget.")
1830
1831 (define-widget 'custom-display-unselected 'item
1832 "A display specification that doesn't match the selected display."
1833 :match 'custom-display-unselected-match)
1834
1835 (defun custom-display-unselected-match (widget value)
1836 "Non-nil if VALUE is an unselected display specification."
1837 (not (custom-display-match-frame value (selected-frame))))
1838
1839 (define-widget 'custom-face-selected 'group
1840 "Edit the attributes of the selected display in a face specification."
1841 :args '((repeat :format ""
1842 :inline t
1843 (group custom-display-unselected sexp))
1844 (group (sexp :format "") custom-face-edit)
1845 (repeat :format ""
1846 :inline t
1847 sexp)))
1848
1849 (defconst custom-face-selected (widget-convert 'custom-face-selected)
1850 "Converted version of the `custom-face-selected' widget.")
1851
1852 (defun custom-face-value-create (widget)
1853 ;; Create a list of the display specifications.
1854 (unless (eq (preceding-char) ?\n)
1855 (insert "\n"))
1856 (when (not (eq (widget-get widget :custom-state) 'hidden))
1857 (message "Creating face editor...")
1858 (custom-load-widget widget)
1859 (let* ((symbol (widget-value widget))
1860 (spec (or (get symbol 'saved-face)
1861 (get symbol 'factory-face)
1862 ;; Attempt to construct it.
1863 (list (list t (custom-face-attributes-get
1864 symbol (selected-frame))))))
1865 (form (widget-get widget :custom-form))
1866 (indent (widget-get widget :indent))
1867 (edit (widget-create-child-and-convert
1868 widget
1869 (cond ((and (eq form 'selected)
1870 (widget-apply custom-face-selected :match spec))
1871 (when indent (insert-char ?\ indent))
1872 'custom-face-selected)
1873 ((and (not (eq form 'lisp))
1874 (widget-apply custom-face-all :match spec))
1875 'custom-face-all)
1876 (t
1877 (when indent (insert-char ?\ indent))
1878 'sexp))
1879 :value spec)))
1880 (custom-face-state-set widget)
1881 (widget-put widget :children (list edit)))
1882 (message "Creating face editor...done")))
1883
1884 (defvar custom-face-menu
1885 '(("Hide" custom-toggle-hide
1886 (lambda (widget)
1887 (not (memq (widget-get widget :custom-state) '(modified invalid)))))
1888 ("Edit Selected" custom-face-edit-selected
1889 (lambda (widget)
1890 (not (eq (widget-get widget :custom-form) 'selected))))
1891 ("Edit All" custom-face-edit-all
1892 (lambda (widget)
1893 (not (eq (widget-get widget :custom-form) 'all))))
1894 ("Edit Lisp" custom-face-edit-lisp
1895 (lambda (widget)
1896 (not (eq (widget-get widget :custom-form) 'lisp))))
1897 ("Set" custom-face-set)
1898 ("Save" custom-face-save)
1899 ("Reset to Saved" custom-face-reset-saved
1900 (lambda (widget)
1901 (get (widget-value widget) 'saved-face)))
1902 ("Reset to Standard Setting" custom-face-reset-factory
1903 (lambda (widget)
1904 (get (widget-value widget) 'factory-face))))
1905 "Alist of actions for the `custom-face' widget.
1906 Each entry has the form (NAME ACTION FILTER) where NAME is the name of
1907 the menu entry, ACTION is the function to call on the widget when the
1908 menu is selected, and FILTER is a predicate which takes a `custom-face'
1909 widget as an argument, and returns non-nil if ACTION is valid on that
1910 widget. If FILTER is nil, ACTION is always valid.")
1911
1912 (defun custom-face-edit-selected (widget)
1913 "Edit selected attributes of the value of WIDGET."
1914 (widget-put widget :custom-state 'unknown)
1915 (widget-put widget :custom-form 'selected)
1916 (custom-redraw widget))
1917
1918 (defun custom-face-edit-all (widget)
1919 "Edit all attributes of the value of WIDGET."
1920 (widget-put widget :custom-state 'unknown)
1921 (widget-put widget :custom-form 'all)
1922 (custom-redraw widget))
1923
1924 (defun custom-face-edit-lisp (widget)
1925 "Edit the lisp representation of the value of WIDGET."
1926 (widget-put widget :custom-state 'unknown)
1927 (widget-put widget :custom-form 'lisp)
1928 (custom-redraw widget))
1929
1930 (defun custom-face-state-set (widget)
1931 "Set the state of WIDGET."
1932 (let ((symbol (widget-value widget)))
1933 (widget-put widget :custom-state (cond ((get symbol 'customized-face)
1934 'set)
1935 ((get symbol 'saved-face)
1936 'saved)
1937 ((get symbol 'factory-face)
1938 'factory)
1939 (t
1940 'rogue)))))
1941
1942 (defun custom-face-action (widget &optional event)
1943 "Show the menu for `custom-face' WIDGET.
1944 Optional EVENT is the location for the menu."
1945 (if (eq (widget-get widget :custom-state) 'hidden)
1946 (custom-toggle-hide widget)
1947 (let* ((completion-ignore-case t)
1948 (symbol (widget-get widget :value))
1949 (answer (widget-choose (custom-unlispify-tag-name symbol)
1950 (custom-menu-filter custom-face-menu
1951 widget)
1952 event)))
1953 (if answer
1954 (funcall answer widget)))))
1955
1956 (defun custom-face-set (widget)
1957 "Make the face attributes in WIDGET take effect."
1958 (let* ((symbol (widget-value widget))
1959 (child (car (widget-get widget :children)))
1960 (value (widget-value child)))
1961 (put symbol 'customized-face value)
1962 (custom-face-display-set symbol value)
1963 (custom-face-state-set widget)
1964 (custom-redraw-magic widget)))
1965
1966 (defun custom-face-save (widget)
1967 "Make the face attributes in WIDGET default."
1968 (let* ((symbol (widget-value widget))
1969 (child (car (widget-get widget :children)))
1970 (value (widget-value child)))
1971 (custom-face-display-set symbol value)
1972 (put symbol 'saved-face value)
1973 (put symbol 'customized-face nil)
1974 (custom-face-state-set widget)
1975 (custom-redraw-magic widget)))
1976
1977 (defun custom-face-reset-saved (widget)
1978 "Restore WIDGET to the face's default attributes."
1979 (let* ((symbol (widget-value widget))
1980 (child (car (widget-get widget :children)))
1981 (value (get symbol 'saved-face)))
1982 (unless value
1983 (error "No saved value for this face"))
1984 (put symbol 'customized-face nil)
1985 (custom-face-display-set symbol value)
1986 (widget-value-set child value)
1987 (custom-face-state-set widget)
1988 (custom-redraw-magic widget)))
1989
1990 (defun custom-face-reset-factory (widget)
1991 "Restore WIDGET to the face's standard settings."
1992 (let* ((symbol (widget-value widget))
1993 (child (car (widget-get widget :children)))
1994 (value (get symbol 'factory-face)))
1995 (unless value
1996 (error "No standard setting for this face"))
1997 (put symbol 'customized-face nil)
1998 (when (get symbol 'saved-face)
1999 (put symbol 'saved-face nil)
2000 (custom-save-all))
2001 (custom-face-display-set symbol value)
2002 (widget-value-set child value)
2003 (custom-face-state-set widget)
2004 (custom-redraw-magic widget)))
2005
2006 ;;; The `face' Widget.
2007
2008 (define-widget 'face 'default
2009 "Select and customize a face."
2010 :convert-widget 'widget-item-convert-widget
2011 :format "%[%t%]: %v"
2012 :tag "Face"
2013 :value 'default
2014 :value-create 'widget-face-value-create
2015 :value-delete 'widget-face-value-delete
2016 :value-get 'widget-item-value-get
2017 :validate 'widget-editable-list-validate
2018 :action 'widget-face-action
2019 :match '(lambda (widget value) (symbolp value)))
2020
2021 (defun widget-face-value-create (widget)
2022 ;; Create a `custom-face' child.
2023 (let* ((symbol (widget-value widget))
2024 (child (widget-create-child-and-convert
2025 widget 'custom-face
2026 :format "%t %s%m%h%v"
2027 :custom-level nil
2028 :value symbol)))
2029 (custom-magic-reset child)
2030 (setq custom-options (cons child custom-options))
2031 (widget-put widget :children (list child))))
2032
2033 (defun widget-face-value-delete (widget)
2034 ;; Remove the child from the options.
2035 (let ((child (car (widget-get widget :children))))
2036 (setq custom-options (delq child custom-options))
2037 (widget-children-value-delete widget)))
2038
2039 (defvar face-history nil
2040 "History of entered face names.")
2041
2042 (defun widget-face-action (widget &optional event)
2043 "Prompt for a face."
2044 (let ((answer (completing-read "Face: "
2045 (mapcar (lambda (face)
2046 (list (symbol-name face)))
2047 (face-list))
2048 nil nil nil
2049 'face-history)))
2050 (unless (zerop (length answer))
2051 (widget-value-set widget (intern answer))
2052 (widget-apply widget :notify widget event)
2053 (widget-setup))))
2054
2055 ;;; The `hook' Widget.
2056
2057 (define-widget 'hook 'list
2058 "A emacs lisp hook"
2059 :convert-widget 'custom-hook-convert-widget
2060 :tag "Hook")
2061
2062 (defun custom-hook-convert-widget (widget)
2063 ;; Handle `:custom-options'.
2064 (let* ((options (widget-get widget :options))
2065 (other `(editable-list :inline t
2066 :entry-format "%i %d%v"
2067 (function :format " %v")))
2068 (args (if options
2069 (list `(checklist :inline t
2070 ,@(mapcar (lambda (entry)
2071 `(function-item ,entry))
2072 options))
2073 other)
2074 (list other))))
2075 (widget-put widget :args args)
2076 widget))
2077
2078 ;;; The `custom-group' Widget.
2079
2080 (defcustom custom-group-tag-faces '(custom-group-tag-face-1)
2081 ;; In XEmacs, this ought to play games with font size.
2082 "Face used for group tags.
2083 The first member is used for level 1 groups, the second for level 2,
2084 and so forth. The remaining group tags are shown with
2085 `custom-group-tag-face'."
2086 :type '(repeat face)
2087 :group 'custom-faces)
2088
2089 (defface custom-group-tag-face-1 '((((class color)
2090 (background dark))
2091 (:foreground "pink" :underline t))
2092 (((class color)
2093 (background light))
2094 (:foreground "red" :underline t))
2095 (t (:underline t)))
2096 "Face used for group tags.")
2097
2098 (defface custom-group-tag-face '((((class color)
2099 (background dark))
2100 (:foreground "light blue" :underline t))
2101 (((class color)
2102 (background light))
2103 (:foreground "blue" :underline t))
2104 (t (:underline t)))
2105 "Face used for low level group tags."
2106 :group 'custom-faces)
2107
2108 (define-widget 'custom-group 'custom
2109 "Customize group."
2110 :format "%l%{%t%}:%L\n%m%h%a%v"
2111 :sample-face-get 'custom-group-sample-face-get
2112 :documentation-property 'group-documentation
2113 :help-echo "Set or reset all members of this group."
2114 :value-create 'custom-group-value-create
2115 :action 'custom-group-action
2116 :custom-set 'custom-group-set
2117 :custom-save 'custom-group-save
2118 :custom-reset-current 'custom-group-reset-current
2119 :custom-reset-saved 'custom-group-reset-saved
2120 :custom-reset-factory 'custom-group-reset-factory
2121 :custom-menu 'custom-group-menu-create)
2122
2123 (defun custom-group-sample-face-get (widget)
2124 ;; Use :sample-face.
2125 (or (nth (1- (widget-get widget :custom-level)) custom-group-tag-faces)
2126 'custom-group-tag-face))
2127
2128 (defun custom-group-value-create (widget)
2129 (let ((state (widget-get widget :custom-state)))
2130 (unless (eq state 'hidden)
2131 (message "Creating group...")
2132 (custom-load-widget widget)
2133 (let* ((level (widget-get widget :custom-level))
2134 (symbol (widget-value widget))
2135 (members (get symbol 'custom-group))
2136 (prefixes (widget-get widget :custom-prefixes))
2137 (custom-prefix-list (custom-prefix-add symbol prefixes))
2138 (length (length members))
2139 (count 0)
2140 (children (mapcar (lambda (entry)
2141 (widget-insert "\n")
2142 (message "Creating group members... %2d%%"
2143 (/ (* 100.0 count) length))
2144 (setq count (1+ count))
2145 (prog1
2146 (widget-create-child-and-convert
2147 widget (nth 1 entry)
2148 :group widget
2149 :tag (custom-unlispify-tag-name
2150 (nth 0 entry))
2151 :custom-prefixes custom-prefix-list
2152 :custom-level (1+ level)
2153 :value (nth 0 entry))
2154 (unless (eq (preceding-char) ?\n)
2155 (widget-insert "\n"))))
2156 members)))
2157 (message "Creating group magic...")
2158 (mapcar 'custom-magic-reset children)
2159 (message "Creating group state...")
2160 (widget-put widget :children children)
2161 (custom-group-state-update widget)
2162 (message "Creating group... done")))))
2163
2164 (defvar custom-group-menu
2165 '(("Hide" custom-toggle-hide
2166 (lambda (widget)
2167 (not (memq (widget-get widget :custom-state) '(modified invalid)))))
2168 ("Set" custom-group-set
2169 (lambda (widget)
2170 (eq (widget-get widget :custom-state) 'modified)))
2171 ("Save" custom-group-save
2172 (lambda (widget)
2173 (memq (widget-get widget :custom-state) '(modified set))))
2174 ("Reset to Current" custom-group-reset-current
2175 (lambda (widget)
2176 (and (default-boundp (widget-value widget))
2177 (memq (widget-get widget :custom-state) '(modified)))))
2178 ("Reset to Saved" custom-group-reset-saved
2179 (lambda (widget)
2180 (and (get (widget-value widget) 'saved-value)
2181 (memq (widget-get widget :custom-state) '(modified set)))))
2182 ("Reset to Standard Settings" custom-group-reset-factory
2183 (lambda (widget)
2184 (and (get (widget-value widget) 'factory-value)
2185 (memq (widget-get widget :custom-state) '(modified set saved))))))
2186 "Alist of actions for the `custom-group' widget.
2187 Each entry has the form (NAME ACTION FILTER) where NAME is the name of
2188 the menu entry, ACTION is the function to call on the widget when the
2189 menu is selected, and FILTER is a predicate which takes a `custom-group'
2190 widget as an argument, and returns non-nil if ACTION is valid on that
2191 widget. If FILTER is nil, ACTION is always valid.")
2192
2193 (defun custom-group-action (widget &optional event)
2194 "Show the menu for `custom-group' WIDGET.
2195 Optional EVENT is the location for the menu."
2196 (if (eq (widget-get widget :custom-state) 'hidden)
2197 (custom-toggle-hide widget)
2198 (let* ((completion-ignore-case t)
2199 (answer (widget-choose (custom-unlispify-tag-name
2200 (widget-get widget :value))
2201 (custom-menu-filter custom-group-menu
2202 widget)
2203 event)))
2204 (if answer
2205 (funcall answer widget)))))
2206
2207 (defun custom-group-set (widget)
2208 "Set changes in all modified group members."
2209 (let ((children (widget-get widget :children)))
2210 (mapcar (lambda (child)
2211 (when (eq (widget-get child :custom-state) 'modified)
2212 (widget-apply child :custom-set)))
2213 children )))
2214
2215 (defun custom-group-save (widget)
2216 "Save all modified group members."
2217 (let ((children (widget-get widget :children)))
2218 (mapcar (lambda (child)
2219 (when (memq (widget-get child :custom-state) '(modified set))
2220 (widget-apply child :custom-save)))
2221 children )))
2222
2223 (defun custom-group-reset-current (widget)
2224 "Reset all modified group members."
2225 (let ((children (widget-get widget :children)))
2226 (mapcar (lambda (child)
2227 (when (eq (widget-get child :custom-state) 'modified)
2228 (widget-apply child :custom-reset-current)))
2229 children )))
2230
2231 (defun custom-group-reset-saved (widget)
2232 "Reset all modified or set group members."
2233 (let ((children (widget-get widget :children)))
2234 (mapcar (lambda (child)
2235 (when (memq (widget-get child :custom-state) '(modified set))
2236 (widget-apply child :custom-reset-saved)))
2237 children )))
2238
2239 (defun custom-group-reset-factory (widget)
2240 "Reset all modified, set, or saved group members."
2241 (let ((children (widget-get widget :children)))
2242 (mapcar (lambda (child)
2243 (when (memq (widget-get child :custom-state)
2244 '(modified set saved))
2245 (widget-apply child :custom-reset-factory)))
2246 children )))
2247
2248 (defun custom-group-state-update (widget)
2249 "Update magic."
2250 (unless (eq (widget-get widget :custom-state) 'hidden)
2251 (let* ((children (widget-get widget :children))
2252 (states (mapcar (lambda (child)
2253 (widget-get child :custom-state))
2254 children))
2255 (magics custom-group-magic-alist)
2256 (found 'factory))
2257 (while magics
2258 (let ((magic (car (car magics))))
2259 (if (and (not (eq magic 'hidden))
2260 (memq magic states))
2261 (setq found magic
2262 magics nil)
2263 (setq magics (cdr magics)))))
2264 (widget-put widget :custom-state found)))
2265 (custom-magic-reset widget))
2266
2267 ;;; The `custom-save-all' Function.
2268
2269 (defcustom custom-file "~/.emacs"
2270 "File used for storing customization information.
2271 If you change this from the default \"~/.emacs\" you need to
2272 explicitly load that file for the settings to take effect."
2273 :type 'file
2274 :group 'customize)
2275
2276 (defun custom-save-delete (symbol)
2277 "Delete the call to SYMBOL form `custom-file'.
2278 Leave point at the location of the call, or after the last expression."
2279 (set-buffer (find-file-noselect custom-file))
2280 (goto-char (point-min))
2281 (catch 'found
2282 (while t
2283 (let ((sexp (condition-case nil
2284 (read (current-buffer))
2285 (end-of-file (throw 'found nil)))))
2286 (when (and (listp sexp)
2287 (eq (car sexp) symbol))
2288 (delete-region (save-excursion
2289 (backward-sexp)
2290 (point))
2291 (point))
2292 (throw 'found nil))))))
2293
2294 (defun custom-save-variables ()
2295 "Save all customized variables in `custom-file'."
2296 (save-excursion
2297 (custom-save-delete 'custom-set-variables)
2298 (let ((standard-output (current-buffer)))
2299 (unless (bolp)
2300 (princ "\n"))
2301 (princ "(custom-set-variables")
2302 (mapatoms (lambda (symbol)
2303 (let ((value (get symbol 'saved-value))
2304 (requests (get symbol 'custom-requests))
2305 (now (not (or (get symbol 'factory-value)
2306 (and (not (boundp symbol))
2307 (not (get symbol 'force-value)))))))
2308 (when value
2309 (princ "\n '(")
2310 (princ symbol)
2311 (princ " ")
2312 (prin1 (car value))
2313 (cond (requests
2314 (if now
2315 (princ " t ")
2316 (princ " nil "))
2317 (prin1 requests)
2318 (princ ")"))
2319 (now
2320 (princ " t)"))
2321 (t
2322 (princ ")")))))))
2323 (princ ")")
2324 (unless (looking-at "\n")
2325 (princ "\n")))))
2326
2327 (defun custom-save-faces ()
2328 "Save all customized faces in `custom-file'."
2329 (save-excursion
2330 (custom-save-delete 'custom-set-faces)
2331 (let ((standard-output (current-buffer)))
2332 (unless (bolp)
2333 (princ "\n"))
2334 (princ "(custom-set-faces")
2335 (let ((value (get 'default 'saved-face)))
2336 ;; The default face must be first, since it affects the others.
2337 (when value
2338 (princ "\n '(default ")
2339 (prin1 value)
2340 (if (or (get 'default 'factory-face)
2341 (and (not (custom-facep 'default))
2342 (not (get 'default 'force-face))))
2343 (princ ")")
2344 (princ " t)"))))
2345 (mapatoms (lambda (symbol)
2346 (let ((value (get symbol 'saved-face)))
2347 (when (and (not (eq symbol 'default))
2348 ;; Don't print default face here.
2349 value)
2350 (princ "\n '(")
2351 (princ symbol)
2352 (princ " ")
2353 (prin1 value)
2354 (if (or (get symbol 'factory-face)
2355 (and (not (custom-facep symbol))
2356 (not (get symbol 'force-face))))
2357 (princ ")")
2358 (princ " t)"))))))
2359 (princ ")")
2360 (unless (looking-at "\n")
2361 (princ "\n")))))
2362
2363 ;;;###autoload
2364 (defun custom-save-customized ()
2365 "Save all user options which have been set in this session."
2366 (interactive)
2367 (mapatoms (lambda (symbol)
2368 (let ((face (get symbol 'customized-face))
2369 (value (get symbol 'customized-value)))
2370 (when face
2371 (put symbol 'saved-face face)
2372 (put symbol 'customized-face nil))
2373 (when value
2374 (put symbol 'saved-value value)
2375 (put symbol 'customized-value nil)))))
2376 ;; We really should update all custom buffers here.
2377 (custom-save-all))
2378
2379 ;;;###autoload
2380 (defun custom-save-all ()
2381 "Save all customizations in `custom-file'."
2382 (custom-save-variables)
2383 (custom-save-faces)
2384 (save-excursion
2385 (set-buffer (find-file-noselect custom-file))
2386 (save-buffer)))
2387
2388 ;;; The Customize Menu.
2389
2390 ;;; Menu support
2391
2392 (unless (string-match "XEmacs" emacs-version)
2393 (defconst custom-help-menu '("Customize"
2394 ["Update menu..." custom-menu-update t]
2395 ["Group..." customize t]
2396 ["Variable..." customize-variable t]
2397 ["Face..." customize-face t]
2398 ["Saved..." customize-customized t]
2399 ["Apropos..." customize-apropos t])
2400 ;; This menu should be identical to the one defined in `menu-bar.el'.
2401 "Customize menu")
2402
2403 (defun custom-menu-reset ()
2404 "Reset customize menu."
2405 (remove-hook 'custom-define-hook 'custom-menu-reset)
2406 (define-key global-map [menu-bar help-menu customize-menu]
2407 (cons (car custom-help-menu)
2408 (easy-menu-create-keymaps (car custom-help-menu)
2409 (cdr custom-help-menu)))))
2410
2411 (defun custom-menu-update (event)
2412 "Update customize menu."
2413 (interactive "e")
2414 (add-hook 'custom-define-hook 'custom-menu-reset)
2415 (let* ((emacs (widget-apply '(custom-group) :custom-menu 'emacs))
2416 (menu `(,(car custom-help-menu)
2417 ,emacs
2418 ,@(cdr (cdr custom-help-menu)))))
2419 (let ((map (easy-menu-create-keymaps (car menu) (cdr menu))))
2420 (define-key global-map [menu-bar help-menu customize-menu]
2421 (cons (car menu) map)))))
2422
2423 (defcustom custom-menu-nesting 2
2424 "Maximum nesting in custom menus."
2425 :type 'integer
2426 :group 'customize))
2427
2428 (defun custom-face-menu-create (widget symbol)
2429 "Ignoring WIDGET, create a menu entry for customization face SYMBOL."
2430 (vector (custom-unlispify-menu-entry symbol)
2431 `(custom-buffer-create '((,symbol custom-face)))
2432 t))
2433
2434 (defun custom-variable-menu-create (widget symbol)
2435 "Ignoring WIDGET, create a menu entry for customization variable SYMBOL."
2436 (let ((type (get symbol 'custom-type)))
2437 (unless (listp type)
2438 (setq type (list type)))
2439 (if (and type (widget-get type :custom-menu))
2440 (widget-apply type :custom-menu symbol)
2441 (vector (custom-unlispify-menu-entry symbol)
2442 `(custom-buffer-create '((,symbol custom-variable)))
2443 t))))
2444
2445 ;; Add checkboxes to boolean variable entries.
2446 (widget-put (get 'boolean 'widget-type)
2447 :custom-menu (lambda (widget symbol)
2448 (vector (custom-unlispify-menu-entry symbol)
2449 `(custom-buffer-create
2450 '((,symbol custom-variable)))
2451 ':style 'toggle
2452 ':selected symbol)))
2453
2454 (if (string-match "XEmacs" emacs-version)
2455 ;; XEmacs can create menus dynamically.
2456 (defun custom-group-menu-create (widget symbol)
2457 "Ignoring WIDGET, create a menu entry for customization group SYMBOL."
2458 `( ,(custom-unlispify-menu-entry symbol t)
2459 :filter (lambda (&rest junk)
2460 (cdr (custom-menu-create ',symbol)))))
2461 ;; But emacs can't.
2462 (defun custom-group-menu-create (widget symbol)
2463 "Ignoring WIDGET, create a menu entry for customization group SYMBOL."
2464 ;; Limit the nesting.
2465 (let ((custom-menu-nesting (1- custom-menu-nesting)))
2466 (custom-menu-create symbol))))
2467
2468 ;;;###autoload
2469 (defun custom-menu-create (symbol)
2470 "Create menu for customization group SYMBOL.
2471 The menu is in a format applicable to `easy-menu-define'."
2472 (let* ((item (vector (custom-unlispify-menu-entry symbol)
2473 `(custom-buffer-create '((,symbol custom-group)))
2474 t)))
2475 (if (and (or (not (boundp 'custom-menu-nesting))
2476 (>= custom-menu-nesting 0))
2477 (< (length (get symbol 'custom-group)) widget-menu-max-size))
2478 (let ((custom-prefix-list (custom-prefix-add symbol
2479 custom-prefix-list)))
2480 (custom-load-symbol symbol)
2481 `(,(custom-unlispify-menu-entry symbol t)
2482 ,item
2483 "--"
2484 ,@(mapcar (lambda (entry)
2485 (widget-apply (if (listp (nth 1 entry))
2486 (nth 1 entry)
2487 (list (nth 1 entry)))
2488 :custom-menu (nth 0 entry)))
2489 (get symbol 'custom-group))))
2490 item)))
2491
2492 ;;;###autoload
2493 (defun customize-menu-create (symbol &optional name)
2494 "Return a customize menu for customization group SYMBOL.
2495 If optional NAME is given, use that as the name of the menu.
2496 Otherwise the menu will be named `Customize'.
2497 The format is suitable for use with `easy-menu-define'."
2498 (unless name
2499 (setq name "Customize"))
2500 (if (string-match "XEmacs" emacs-version)
2501 ;; We can delay it under XEmacs.
2502 `(,name
2503 :filter (lambda (&rest junk)
2504 (cdr (custom-menu-create ',symbol))))
2505 ;; But we must create it now under Emacs.
2506 (cons name (cdr (custom-menu-create symbol)))))
2507
2508 ;;; The Custom Mode.
2509
2510 (defvar custom-mode-map nil
2511 "Keymap for `custom-mode'.")
2512
2513 (unless custom-mode-map
2514 (setq custom-mode-map (make-sparse-keymap))
2515 (set-keymap-parent custom-mode-map widget-keymap)
2516 (define-key custom-mode-map "q" 'bury-buffer))
2517
2518 (easy-menu-define custom-mode-customize-menu
2519 custom-mode-map
2520 "Menu used to customize customization buffers."
2521 (customize-menu-create 'customize))
2522
2523 (easy-menu-define custom-mode-menu
2524 custom-mode-map
2525 "Menu used in customization buffers."
2526 `("Custom"
2527 ["Set" custom-set t]
2528 ["Save" custom-save t]
2529 ["Reset to Current" custom-reset-current t]
2530 ["Reset to Saved" custom-reset-saved t]
2531 ["Reset to Standard Settings" custom-reset-factory t]
2532 ["Info" (Info-goto-node "(custom)The Customization Buffer") t]))
2533
2534 (defcustom custom-mode-hook nil
2535 "Hook called when entering custom-mode."
2536 :type 'hook
2537 :group 'customize)
2538
2539 (defun custom-mode ()
2540 "Major mode for editing customization buffers.
2541
2542 The following commands are available:
2543
2544 Move to next button or editable field. \\[widget-forward]
2545 Move to previous button or editable field. \\[widget-backward]
2546 Activate button under the mouse pointer. \\[widget-button-click]
2547 Activate button under point. \\[widget-button-press]
2548 Set all modifications. \\[custom-set]
2549 Make all modifications default. \\[custom-save]
2550 Reset all modified options. \\[custom-reset-current]
2551 Reset all modified or set options. \\[custom-reset-saved]
2552 Reset all options. \\[custom-reset-factory]
2553
2554 Entry to this mode calls the value of `custom-mode-hook'
2555 if that value is non-nil."
2556 (kill-all-local-variables)
2557 (setq major-mode 'custom-mode
2558 mode-name "Custom")
2559 (use-local-map custom-mode-map)
2560 (easy-menu-add custom-mode-customize-menu)
2561 (easy-menu-add custom-mode-menu)
2562 (make-local-variable 'custom-options)
2563 (run-hooks 'custom-mode-hook))
2564
2565 ;;; The End.
2566
2567 (provide 'cus-edit)
2568
2569 ;; cus-edit.el ends here