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