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