comparison lisp/cus-edit.el @ 209:41ff10fd062f r20-4b3

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