comparison lisp/custom.el @ 2544:b4a8cd0dd8df

[xemacs-hg @ 2005-02-03 04:29:32 by ben] behavior ws #1: custom updates cus-dep.el: If a directory has no custom dependencies, write a blank custom-load file rather than deleting the file, so that time-based rebuild checking will work. cus-edit.el: Split out code in custom-load-symbol. Support loading of the new custom-defines file. cus-edit.el: Split long menus. custom.el: Sync with FSF 21.3.
author ben
date Thu, 03 Feb 2005 04:29:33 +0000
parents c9b6a2fec10d
children cef5f57bb9e2
comparison
equal deleted inserted replaced
2543:5e6de1feeafc 2544:b4a8cd0dd8df
1 ;;; custom.el -- Tools for declaring and initializing options. 1 ;;; custom.el --- tools for declaring and initializing options
2 2 ;;
3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc. 3 ;; Copyright (C) 1996, 1997, 1999, 2001, 2002 Free Software Foundation, Inc.
4 4 ;;
5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> 5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6 ;; Maintainer: Hrvoje Niksic <hniksic@xemacs.org> 6 ;; Maintainer: XEmacs Development Group
7 ;; Keywords: help, faces, dumped 7 ;; Keywords: help, faces, dumped
8 ;; Version: 1.9960-x
9 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
10 8
11 ;; This file is part of XEmacs. 9 ;; This file is part of XEmacs.
12 10
13 ;; XEmacs is free software; you can redistribute it and/or modify 11 ;; XEmacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by 12 ;; it under the terms of the GNU General Public License as published by
23 ;; You should have received a copy of the GNU General Public License 21 ;; You should have received a copy of the GNU General Public License
24 ;; along with XEmacs; see the file COPYING. If not, write to the 22 ;; along with XEmacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, 23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA. 24 ;; Boston, MA 02111-1307, USA.
27 25
28 ;;; Synched with: ??? Partially synched to 21.2 by Ben Wing. 26 ;;; Synched with: FSF 21.3.
29 27
30 ;;; Commentary: 28 ;;; Commentary:
31 29
32 ;; This file is dumped with XEmacs. 30 ;; This file is dumped with XEmacs.
33 31
34 ;; This file only contain the code needed to declare and initialize 32 ;;
33 ;; This file only contains the code needed to declare and initialize
35 ;; user options. The code to customize options is autoloaded from 34 ;; user options. The code to customize options is autoloaded from
36 ;; `cus-edit.el'. 35 ;; `cus-edit.el' and is documented in the XEmacs Lisp Reference manual.
37 ;; 36
38 ;; The code implementing face declarations is in `cus-face.el' 37 ;; The code implementing face declarations is in `cus-face.el'.
39 38
40 ;;; Code: 39 ;;; Code:
41 40
42 ;; it is now safe to put the `provide' anywhere. if an error occurs while 41 ;; it is now safe to put the `provide' anywhere. if an error occurs while
43 ;; loading, all provides (and fsets) will be undone. put it first to 42 ;; loading, all provides (and fsets) will be undone. put it first to
44 ;; prevent require/provide loop with custom and cus-face. 43 ;; prevent require/provide loop with custom and cus-face.
45 (provide 'custom) 44 (provide 'custom)
46 45
47 ;; BEGIN SYNC WITH FSF 21.2
48
49 (eval-when-compile 46 (eval-when-compile
50 (load "cl-macs" nil t) 47 (load "cl-macs" nil t)
51 ;; To elude warnings. 48 ;; To elude warnings.
52 (require 'cus-face)) 49 (require 'cus-face))
53 50
57 (require 'widget) 54 (require 'widget)
58 55
59 (defvar custom-define-hook nil 56 (defvar custom-define-hook nil
60 ;; Customize information for this option is in `cus-edit.el'. 57 ;; Customize information for this option is in `cus-edit.el'.
61 "Hook called after defining each customize option.") 58 "Hook called after defining each customize option.")
59
60 (defvar custom-dont-initialize nil
61 "Non-nil means `defcustom' should not initialize the variable.
62 That is used for the sake of `custom-make-dependencies'.
63 Users should not set it.")
64
65 (defvar custom-current-group-alist nil
66 "Alist of (FILE . GROUP) indicating the current group to use for FILE.")
62 67
63 ;;; The `defcustom' Macro. 68 ;;; The `defcustom' Macro.
64 69
65 (defun custom-initialize-default (symbol value) 70 (defun custom-initialize-default (symbol value)
66 "Initialize SYMBOL with VALUE. 71 "Initialize SYMBOL with VALUE.
129 (set-default symbol (eval value))))) 134 (set-default symbol (eval value)))))
130 135
131 (defun custom-declare-variable (symbol default doc &rest args) 136 (defun custom-declare-variable (symbol default doc &rest args)
132 "Like `defcustom', but SYMBOL and DEFAULT are evaluated as normal arguments. 137 "Like `defcustom', but SYMBOL and DEFAULT are evaluated as normal arguments.
133 DEFAULT should be an expression to evaluate to compute the default value, 138 DEFAULT should be an expression to evaluate to compute the default value,
134 not the default value itself." 139 not the default value itself.
135 ;; Remember the standard setting. 140
141 DEFAULT is stored as SYMBOL's value in the standard theme. See
142 `custom-known-themes' for a list of known themes. For backwards
143 compatibility, DEFAULT is also stored in SYMBOL's property
144 `standard-value'. At the same time, SYMBOL's property `force-value' is
145 set to nil, as the value is no longer rogue."
146 ;; Remember the standard setting. The value should be in the standard
147 ;; theme, not in this property. However, his would require changeing
148 ;; the C source of defvar and others as well...
136 (put symbol 'standard-value (list default)) 149 (put symbol 'standard-value (list default))
137 ;; Maybe this option was rogue in an earlier version. It no longer is. 150 ;; Maybe this option was rogue in an earlier version. It no longer is.
138 (when (eq (get symbol 'force-value) 'rogue) 151 (when (eq (get symbol 'force-value) 'rogue)
139 ;; It no longer is. 152 ;; It no longer is.
140 (put symbol 'force-value nil)) 153 (put symbol 'force-value nil))
141 (when doc 154 (when doc
142 (put symbol 'variable-documentation doc)) 155 (put symbol 'variable-documentation doc))
143 (let ((initialize 'custom-initialize-reset) 156 (let ((initialize 'custom-initialize-reset)
144 (requests nil)) 157 (requests nil))
158 (unless (memq :group args)
159 (custom-add-to-group (custom-current-group) symbol 'custom-variable))
145 (while args 160 (while args
146 (let ((arg (car args))) 161 (let ((arg (car args)))
147 (setq args (cdr args)) 162 (setq args (cdr args))
148 (check-argument-type 'keywordp arg) 163 (check-argument-type 'keywordp arg)
149 (let ((keyword arg) 164 (let ((keyword arg)
150 (value (car args))) 165 (value (car args)))
151 (unless args 166 (unless args
152 (signal 'error (list "Keyword is missing an argument" keyword))) 167 (signal 'error (list "Keyword is missing an argument" keyword)))
153 (setq args (cdr args)) 168 (setq args (cdr args))
154 (cond ((eq keyword :initialize) 169 (cond ((eq keyword :initialize)
155 (setq initialize value)) 170 (setq initialize value))
156 ((eq keyword :set) 171 ((eq keyword :set)
157 (put symbol 'custom-set value)) 172 (put symbol 'custom-set value))
158 ((eq keyword :get) 173 ((eq keyword :get)
159 (put symbol 'custom-get value)) 174 (put symbol 'custom-get value))
160 ((eq keyword :require) 175 ((eq keyword :require)
161 (setq requests (cons value requests))) 176 (push value requests))
162 ((eq keyword :type) 177 ((eq keyword :type)
163 (put symbol 'custom-type value)) 178 (put symbol 'custom-type (purecopy value)))
164 ((eq keyword :options) 179 ((eq keyword :options)
165 (if (get symbol 'custom-options) 180 (if (get symbol 'custom-options)
166 ;; Slow safe code to avoid duplicates. 181 ;; Slow safe code to avoid duplicates.
167 (mapc (lambda (option) 182 (mapc (lambda (option)
168 (custom-add-option symbol option)) 183 (custom-add-option symbol option))
169 value) 184 value)
170 ;; Fast code for the common case. 185 ;; Fast code for the common case.
171 (put symbol 'custom-options (copy-sequence value)))) 186 (put symbol 'custom-options (copy-sequence value))))
172 (t 187 (t
173 (custom-handle-keyword symbol keyword value 188 (custom-handle-keyword symbol keyword value
174 'custom-variable)))))) 189 'custom-variable))))))
175 (put symbol 'custom-requests requests) 190 (put symbol 'custom-requests requests)
176 ;; Do the actual initialization. 191 ;; Do the actual initialization.
177 (funcall initialize symbol default)) 192 (unless custom-dont-initialize
193 (funcall initialize symbol default)))
178 ;; #### This is a rough equivalent of LOADHIST_ATTACH. However, 194 ;; #### This is a rough equivalent of LOADHIST_ATTACH. However,
179 ;; LOADHIST_ATTACH also checks for `initialized'. 195 ;; LOADHIST_ATTACH also checks for `initialized'.
180 (push symbol current-load-list) 196 (push (cons 'defvar symbol) current-load-list)
181 (run-hooks 'custom-define-hook) 197 (run-hooks 'custom-define-hook)
182 symbol) 198 symbol)
183 199
184 (defmacro defcustom (symbol value doc &rest args) 200 (defmacro defcustom (symbol value doc &rest args)
185 "Declare SYMBOL as a customizable variable that defaults to VALUE. 201 "Declare SYMBOL as a customizable variable that defaults to VALUE.
191 207
192 [KEYWORD VALUE]... 208 [KEYWORD VALUE]...
193 209
194 The following keywords are meaningful: 210 The following keywords are meaningful:
195 211
196 :type VALUE should be a widget type for editing the symbols value. 212 :type VALUE should be a widget type for editing the symbol's value.
197 The default is `sexp'. 213 The default is `sexp'.
198 :options VALUE should be a list of valid members of the widget type. 214 :options VALUE should be a list of valid members of the widget type.
199 :group VALUE should be a customization group. 215 :group VALUE should be a customization group.
200 Add SYMBOL to that group. 216 Add SYMBOL to that group.
217 :link LINK-DATA
218 Include an external link after the documentation string for this
219 item. This is a sentence containing an active field which
220 references some other documentation.
221
222 There are three alternatives you can use for LINK-DATA:
223
224 (custom-manual INFO-NODE)
225 Link to an Info node; INFO-NODE is a string which specifies
226 the node name, as in \"(emacs)Top\". The link appears as
227 `[manual]' in the customization buffer.
228
229 (info-link INFO-NODE)
230 Like `custom-manual' except that the link appears in the
231 customization buffer with the Info node name.
232
233 (url-link URL)
234 Link to a web page; URL is a string which specifies the URL.
235 The link appears in the customization buffer as URL.
236
237 You can specify the text to use in the customization buffer by
238 adding `:tag NAME' after the first element of the LINK-DATA; for
239 example, (info-link :tag \"foo\" \"(emacs)Top\") makes a link to the
240 Emacs manual which appears in the buffer as `foo'.
241
242 An item can have more than one external link; however, most items
243 have none at all.
201 :initialize 244 :initialize
202 VALUE should be a function used to initialize the 245 VALUE should be a function used to initialize the
203 variable. It takes two arguments, the symbol and value 246 variable. It takes two arguments, the symbol and value
204 given in the `defcustom' call. The default is 247 given in the `defcustom' call. The default is
205 `custom-initialize-reset' 248 `custom-initialize-reset'.
206 :set VALUE should be a function to set the value of the symbol. 249 :set VALUE should be a function to set the value of the symbol.
207 It takes two arguments, the symbol to set and the value to 250 It takes two arguments, the symbol to set and the value to
208 give it. The default choice of function is `custom-set-default'. 251 give it. The default choice of function is `custom-set-default'.
209 :get VALUE should be a function to extract the value of symbol. 252 :get VALUE should be a function to extract the value of symbol.
210 The function takes one argument, a symbol, and should return 253 The function takes one argument, a symbol, and should return
217 it does (require VALUE) first. 260 it does (require VALUE) first.
218 :version 261 :version
219 VALUE should be a string specifying that the variable was 262 VALUE should be a string specifying that the variable was
220 first introduced, or its default value was changed, in Emacs 263 first introduced, or its default value was changed, in Emacs
221 version VERSION. 264 version VERSION.
222 :set-after VARIABLE 265 :tag LABEL
223 Specifies that SYMBOL should be set after VARIABLE when 266 Use LABEL, a string, instead of the item's name, to label the item
224 both have been customized. 267 in customization menus and buffers.
268 :load FILE
269 Load file FILE (a string) before displaying this customization
270 item. Loading is done with `load', and only if the file is
271 not already loaded.
272 :set-after VARIABLES
273 Specifies that SYMBOL should be set after the list of variables
274 VARIABLES when both have been customized.
225 275
226 Read the section about customization in the Emacs Lisp manual for more 276 Read the section about customization in the Emacs Lisp manual for more
227 information." 277 information."
228 `(custom-declare-variable (quote ,symbol) (quote ,value) ,doc ,@args)) 278 `(custom-declare-variable (quote ,symbol) (quote ,value) ,doc ,@args))
229
230 ;; END SYNC WITH FSF 21.2
231 279
232 ;;; The `defface' Macro. 280 ;;; The `defface' Macro.
233 281
234 (defmacro defface (face spec doc &rest args) 282 (defmacro defface (face spec doc &rest args)
235 "Declare FACE as a customizable face that defaults to SPEC. 283 "Declare FACE as a customizable face that defaults to SPEC.
275 Read the section about customization in the Emacs Lisp manual for more 323 Read the section about customization in the Emacs Lisp manual for more
276 information." 324 information."
277 `(custom-declare-face (quote ,face) ,spec ,doc ,@args)) 325 `(custom-declare-face (quote ,face) ,spec ,doc ,@args))
278 326
279 ;;; The `defgroup' Macro. 327 ;;; The `defgroup' Macro.
328
329 (defun custom-current-group ()
330 (cdr (assoc load-file-name custom-current-group-alist)))
280 331
281 (defun custom-declare-group (symbol members doc &rest args) 332 (defun custom-declare-group (symbol members doc &rest args)
282 "Like `defgroup', but SYMBOL is evaluated as a normal argument." 333 "Like `defgroup', but SYMBOL is evaluated as a normal argument."
283 (while members 334 (while members
284 (apply 'custom-add-to-group symbol (car members)) 335 (apply 'custom-add-to-group symbol (car members))
285 (pop members)) 336 (pop members))
286 (put symbol 'custom-group (nconc members (get symbol 'custom-group)))
287 (when doc 337 (when doc
288 (put symbol 'group-documentation doc)) 338 (put symbol 'group-documentation doc))
289 (while args 339 (while args
290 (let ((arg (car args))) 340 (let ((arg (car args)))
291 (setq args (cdr args)) 341 (setq args (cdr args))
292 (check-argument-type 'keywordp arg) 342 (check-argument-type 'keywordp arg)
293 (let ((keyword arg) 343 (let ((keyword arg)
294 (value (car args))) 344 (value (car args)))
295 (unless args 345 (unless args
296 (signal 'error (list "Keyword is missing an argument" keyword))) 346 (signal 'error (list "Keyword is missing an argument" keyword)))
297 (setq args (cdr args)) 347 (setq args (cdr args))
298 (cond ((eq keyword :prefix) 348 (cond ((eq keyword :prefix)
299 (put symbol 'custom-prefix value)) 349 (put symbol 'custom-prefix value))
300 (t 350 (t
301 (custom-handle-keyword symbol keyword value 351 (custom-handle-keyword symbol keyword value
302 'custom-group)))))) 352 'custom-group))))))
353 ;; Record the group on the `current' list.
354 (let ((elt (assoc load-file-name custom-current-group-alist)))
355 (if elt (setcdr elt symbol)
356 (push (cons load-file-name symbol) custom-current-group-alist)))
303 (run-hooks 'custom-define-hook) 357 (run-hooks 'custom-define-hook)
304 symbol) 358 symbol)
305 359
306 (defmacro defgroup (symbol members doc &rest args) 360 (defmacro defgroup (symbol members doc &rest args)
307 "Declare SYMBOL as a customization group containing MEMBERS. 361 "Declare SYMBOL as a customization group containing MEMBERS.
316 370
317 The remaining arguments should have the form 371 The remaining arguments should have the form
318 372
319 [KEYWORD VALUE]... 373 [KEYWORD VALUE]...
320 374
321 The following KEYWORD's are defined: 375 The following KEYWORDs are defined:
322 376
323 :group VALUE should be a customization group. 377 :group VALUE should be a customization group.
324 Add SYMBOL to that group. 378 Add SYMBOL to that group.
325 379
326 Read the section about customization in the Emacs Lisp manual for more 380 Read the section about customization in the Emacs Lisp manual for more
327 information." 381 information."
382
383 ;; XEmacs: Evidently a purposeful omission from the docs:
384 ;:version VALUE should be a string specifying that the group was introduced
385 ; in Emacs version VERSION.
386 ;
387
388 ;; FSF: (not a problem for XEmacs)
389 ;; It is better not to use backquote in this file,
390 ;; because that makes a bootstrapping problem
391 ;; if you need to recompile all the Lisp files using interpreted code.
392 ; (nconc (list 'custom-declare-group (list 'quote symbol) members doc) args))
328 `(custom-declare-group (quote ,symbol) ,members ,doc ,@args)) 393 `(custom-declare-group (quote ,symbol) ,members ,doc ,@args))
329 394
330 (defvar custom-group-hash-table (make-hash-table :size 300 :test 'eq) 395 (defvar custom-group-hash-table (make-hash-table :size 300 :test 'eq)
331 "Hash-table of non-empty groups.") 396 "Hash-table of non-empty groups.")
332 397
333 (defun custom-add-to-group (group option widget) 398 (defun custom-add-to-group (group option widget)
334 "To existing GROUP add a new OPTION of type WIDGET. 399 "To existing GROUP add a new OPTION of type WIDGET.
335 If there already is an entry for that option, overwrite it." 400 If there already is an entry for OPTION and WIDGET, nothing is done."
336 (let* ((members (get group 'custom-group)) 401 (let ((members (get group 'custom-group))
337 (old (assq option members))) 402 (entry (list option widget)))
338 (if old 403 (unless (member entry members)
339 (setcar (cdr old) widget) 404 (put group 'custom-group (nconc members (list entry)))))
340 (put group 'custom-group (nconc members (list (list option widget))))))
341 (puthash group t custom-group-hash-table)) 405 (puthash group t custom-group-hash-table))
406
407 (defun custom-group-of-mode (mode)
408 "Return the custom group corresponding to the major or minor MODE.
409 If no such group is found, return nil."
410 (or (get mode 'custom-mode-group)
411 (if (or (get mode 'custom-group)
412 (and (string-match "-mode\\'" (symbol-name mode))
413 (get (setq mode (intern (substring (symbol-name mode)
414 0 (match-beginning 0))))
415 'custom-group)))
416 mode)))
342 417
343 ;;; Properties. 418 ;;; Properties.
344 419
345 (defun custom-handle-all-keywords (symbol args type) 420 (defun custom-handle-all-keywords (symbol args type)
346 "For customization option SYMBOL, handle keyword arguments ARGS. 421 "For customization option SYMBOL, handle keyword arguments ARGS.
347 Third argument TYPE is the custom option type." 422 Third argument TYPE is the custom option type."
423 (unless (memq :group args)
424 (custom-add-to-group (custom-current-group) symbol type))
348 (while args 425 (while args
349 (let ((arg (car args))) 426 (let ((arg (car args)))
350 (setq args (cdr args)) 427 (setq args (cdr args))
351 (check-argument-type 'keywordp arg) 428 (check-argument-type 'keywordp arg)
352 (let ((keyword arg) 429 (let ((keyword arg)
418 (puthash symbol t custom-group-hash-table) 495 (puthash symbol t custom-group-hash-table)
419 (let ((loads (get symbol 'custom-loads))) 496 (let ((loads (get symbol 'custom-loads)))
420 (unless (member load loads) 497 (unless (member load loads)
421 (put symbol 'custom-loads (cons load loads))))) 498 (put symbol 'custom-loads (cons load loads)))))
422 499
423 ;;; deftheme macro 500 (defun custom-autoload (symbol load)
501 "Mark SYMBOL as autoloaded custom variable and add dependency LOAD."
502 (put symbol 'custom-autoload t)
503 (custom-add-load symbol load))
504
505 ;; This test is also in the C code of `user-variable-p'.
506 (defun custom-variable-p (variable)
507 "Return non-nil if VARIABLE is a custom variable."
508 (or (get variable 'standard-value)
509 (get variable 'custom-autoload)))
510
511 ;;; Loading files needed to customize a symbol.
512 ;;; This is in custom.el because menu-bar.el needs it for toggle cmds.
513
514 (defvar custom-load-recursion nil
515 "Hack to avoid recursive dependencies.")
516
517 (defun custom-load-symbol (symbol)
518 "Load all dependencies for SYMBOL."
519 (unless custom-load-recursion
520 (let ((custom-load-recursion t))
521 (dolist (load (get symbol 'custom-loads))
522 (cond ((symbolp load) (condition-case nil (require load) (error nil)))
523 ;; This is subsumed by the test below, but it's much faster.
524 ((assoc load load-history))
525 ;; This was just (assoc (locate-library load) load-history)
526 ;; but has been optimized not to load locate-library
527 ;; if not necessary.
528 ((let ((regexp (concat "\\(\\`\\|/\\)" (regexp-quote load)
529 "\\(\\'\\|\\.\\)"))
530 (found nil))
531 (dolist (loaded load-history)
532 (and (stringp (car loaded))
533 (string-match regexp (car loaded))
534 (setq found t)))
535 found))
536 ;; Without this, we would load cus-edit recursively.
537 ;; We are still loading it when we call this,
538 ;; and it is not in load-history yet.
539 ((equal load "cus-edit"))
540 (t (condition-case nil (load load) (error nil))))))))
424 541
425 (defvar custom-known-themes '(user standard) 542 (defvar custom-known-themes '(user standard)
426 "Themes that have been defthemed.") 543 "Themes that have been define with `deftheme'.
427 544 The default value is the list (user standard). The theme `standard'
428 ;; #### add strings for group 545 contains the Emacs standard settings from the original Lisp files. The
429 ;; #### during bootstrap we cannot use cl-macs stuff 546 theme `user' contains all the the settings the user customized and saved.
430 (defun* custom-define-theme (theme feature &optional doc 547 Additional themes declared with the `deftheme' macro will be added to
431 &key short-description immediate variable-reset-string 548 the front of this list.")
432 variable-set-string face-set-string face-reset-string 549
433 &allow-other-keys) 550 (defun custom-declare-theme (theme feature &optional doc &rest args)
434 (push theme custom-known-themes) 551 "Like `deftheme', but THEME is evaluated as a normal argument.
552 FEATURE is the feature this theme provides. This symbol is created
553 from THEME by `custom-make-theme-feature'."
554 (add-to-list 'custom-known-themes theme)
435 (put theme 'theme-feature feature) 555 (put theme 'theme-feature feature)
436 (put theme 'theme-documentation doc) 556 (when doc
437 (if immediate (put theme 'theme-immediate immediate)) 557 (put theme 'theme-documentation doc))
438 (if variable-reset-string 558 (while args
439 (put theme 'theme-variable-reset-string variable-reset-string )) 559 (let ((arg (car args)))
440 (if variable-set-string 560 (setq args (cdr args))
441 (put theme 'theme-variable-set-string variable-set-string )) 561 (check-argument-type 'keywordp arg)
442 (if face-reset-string 562 (let ((keyword arg)
443 (put theme 'theme-face-reset-string face-reset-string )) 563 (value (car args)))
444 (if face-set-string 564 (unless args
445 (put theme 'theme-face-set-string face-set-string )) 565 (signal 'error (list "Keyword is missing an argument" keyword)))
446 (if short-description 566 (setq args (cdr args))
447 (put theme 'theme-short-description short-description ))) 567 (cond ((eq keyword :short-description)
568 (put theme 'theme-short-description value))
569 ((eq keyword :immediate)
570 (put theme 'theme-immediate value))
571 ((eq keyword :variable-set-string)
572 (put theme 'theme-variable-set-string value))
573 ((eq keyword :variable-reset-string)
574 (put theme 'theme-variable-reset-string value))
575 ((eq keyword :face-set-string)
576 (put theme 'theme-face-set-string value))
577 ((eq keyword :face-reset-string)
578 (put theme 'theme-face-reset-string value)))))))
579
580 (defmacro deftheme (theme &optional doc &rest args)
581 "Declare custom theme THEME.
582 The optional argument DOC is a doc string describing the theme.
583 The remaining arguments should have the form
584
585 [KEYWORD VALUE]...
586
587 The following KEYWORD's are defined:
588
589 :short-description
590 VALUE is a short (one line) description of the theme. If not
591 given, DOC is used.
592 :immediate
593 If VALUE is non-nil, variables specified in this theme are set
594 immediately when loading the theme.
595 :variable-set-string
596 VALUE is a string used to indicate that a variable takes its
597 setting from this theme. It is passed to FORMAT with the name
598 of the theme as an additional argument. If not given, a
599 generic description is used.
600 :variable-reset-string
601 VALUE is a string used in the case a variable has been forced
602 to its value in this theme. It is passed to FORMAT with the
603 name of the theme as an additional argument. If not given, a
604 generic description is used.
605 :face-set-string
606 VALUE is a string used to indicate that a face takes its
607 setting from this theme. It is passed to FORMAT with the name
608 of the theme as an additional argument. If not given, a
609 generic description is used.
610 :face-reset-string
611 VALUE is a string used in the case a face has been forced to
612 its value in this theme. It is passed to FORMAT with the name
613 of the theme as an additional argument. If not given, a
614 generic description is used.
615
616 Any theme `foo' should be defined in a file called `foo-theme.el';
617 see `custom-make-theme-feature' for more information."
618 (let ((feature (custom-make-theme-feature theme)))
619 ;; It is better not to use backquote in this file,
620 ;; because that makes a bootstrapping problem
621 ;; if you need to recompile all the Lisp files using interpreted code.
622 (nconc (list 'custom-declare-theme
623 (list 'quote theme)
624 (list 'quote feature)
625 doc) args)))
448 626
449 (defun custom-make-theme-feature (theme) 627 (defun custom-make-theme-feature (theme)
628 "Given a symbol THEME, create a new symbol by appending \"-theme\".
629 Store this symbol in the `theme-feature' property of THEME.
630 Calling `provide-theme' to provide THEME actually puts `THEME-theme'
631 into `features'.
632
633 This allows for a file-name convention for autoloading themes:
634 Every theme X has a property `provide-theme' whose value is \"X-theme\".
635 \(require-theme X) then attempts to load the file `X-theme.el'."
450 (intern (concat (symbol-name theme) "-theme"))) 636 (intern (concat (symbol-name theme) "-theme")))
451
452 (defmacro deftheme (theme &rest body)
453 "(deftheme THEME &optional DOC &key KEYWORDS)
454
455 Define a theme labeled by SYMBOL THEME. The optional argument DOC is a
456 doc string describing the theme. It is optionally followed by the
457 following keyword arguments
458
459 :short-description DESC
460 DESC is a short (one line) description of the theme. If not given DOC
461 is used.
462 :immediate FLAG
463 If FLAG is non-nil variables set in this theme are bound
464 immediately when loading the theme.
465 :variable-set-string VARIABLE_-SET-STRING
466 A string used by the UI to indicate that the value takes it
467 setting from this theme. It is passed to FORMAT with the
468 name of the theme a additional argument.
469 If not given, a generic description is used.
470 :variable-reset-string VARIABLE-RESET-STRING
471 As above but used in the case the variable has been forced to
472 the value in this theme.
473 :face-set-string FACE-SET-STRING
474 :face-reset-string FACE-RESET-STRING
475 As above but for faces."
476 (let ((feature (custom-make-theme-feature theme)))
477 `(custom-define-theme (quote ,theme) (quote ,feature) ,@body)))
478 637
479 (defsubst custom-theme-p (theme) 638 (defsubst custom-theme-p (theme)
480 "Non-nil when THEME has been defined." 639 "Non-nil when THEME has been defined."
481 (memq theme custom-known-themes)) 640 (memq theme custom-known-themes))
482 641
483 (defsubst custom-check-theme (theme) 642 (defsubst custom-check-theme (theme)
484 "Check whether THEME is valid and signal an error if NOT." 643 "Check whether THEME is valid, and signal an error if it is not."
485 (unless (custom-theme-p theme) 644 (unless (custom-theme-p theme)
486 (error "Unknown theme `%s'" theme))) 645 (error "Unknown theme `%s'" theme)))
487 646
488
489 ; #### do we need to deftheme 'user and/or 'standard here to make the
490 ; code in cus-edit cleaner?.
491
492 ;;; Initializing. 647 ;;; Initializing.
493 648
494 (defun custom-push-theme (prop symbol theme mode value) 649 (defun custom-push-theme (prop symbol theme mode value)
650 "Add (THEME MODE VALUE) to the list in property PROP of SYMBOL.
651 If the first element in that list is already (THEME ...),
652 discard it first.
653
654 MODE can be either the symbol `set' or the symbol `reset'. If it is the
655 symbol `set', then VALUE is the value to use. If it is the symbol
656 `reset', then VALUE is the mode to query instead.
657
658 In the following example for the variable `goto-address-url-face', the
659 theme `subtle-hacker' uses the same value for the variable as the theme
660 `gnome2':
661
662 \((standard set bold)
663 \(gnome2 set info-xref)
664 \(jonadab set underline)
665 \(subtle-hacker reset gnome2))
666
667
668 If a value has been stored for themes A B and C, and a new value
669 is to be stored for theme C, then the old value of C is discarded.
670 If a new value is to be stored for theme B, however, the old value
671 of B is not discarded because B is not the car of the list.
672
673 For variables, list property PROP is `theme-value'.
674 For faces, list property PROP is `theme-face'.
675 This is used in `custom-do-theme-reset', for example.
676
677 The list looks the same in any case; the examples shows a possible
678 value of the `theme-face' property for the face `region':
679
680 \((gnome2 set ((t (:foreground \"cyan\" :background \"dark cyan\"))))
681 \(standard set ((((class color) (background dark))
682 \(:background \"blue\"))
683 \(t (:background \"gray\")))))
684
685 This records values for the `standard' and the `gnome2' themes.
686 The user has not customized the face; had he done that,
687 the list would contain an entry for the `user' theme, too.
688 See `custom-known-themes' for a list of known themes."
495 (let ((old (get symbol prop))) 689 (let ((old (get symbol prop)))
496 (if (eq (car-safe (car-safe old)) theme) 690 (if (eq (car-safe (car-safe old)) theme)
497 (setq old (cdr old))) 691 (setq old (cdr old)))
498 (put symbol prop (cons (list theme mode value) old)))) 692 (put symbol prop (cons (list theme mode value) old))))
499 693
506 (put 'custom-local-buffer 'permanent-local t) 700 (put 'custom-local-buffer 'permanent-local t)
507 701
508 (defun custom-set-variables (&rest args) 702 (defun custom-set-variables (&rest args)
509 "Initialize variables according to user preferences. 703 "Initialize variables according to user preferences.
510 The settings are registered as theme `user'. 704 The settings are registered as theme `user'.
511 Each argument should be a list of the form: 705 The arguments should each be a list of the form:
706
707 (SYMBOL VALUE [NOW [REQUEST [COMMENT]]])
708
709 The unevaluated VALUE is stored as the saved value for SYMBOL.
710 If NOW is present and non-nil, VALUE is also evaluated and bound as
711 the default value for the SYMBOL.
712
713 REQUEST is a list of features we must 'require for SYMBOL.
714 COMMENT is a comment string about SYMBOL."
715 (apply 'custom-theme-set-variables 'user args))
716
717 (defun custom-theme-set-variables (theme &rest args)
718 "Initialize variables according to settings specified by args.
719 Records the settings as belonging to THEME.
720
721 The arguments should be a list where each entry has the form:
512 722
513 (SYMBOL VALUE [NOW [REQUEST [COMMENT]]]) 723 (SYMBOL VALUE [NOW [REQUEST [COMMENT]]])
514 724
515 The unevaluated VALUE is stored as the saved value for SYMBOL. 725 The unevaluated VALUE is stored as the saved value for SYMBOL.
516 If NOW is present and non-nil, VALUE is also evaluated and bound as 726 If NOW is present and non-nil, VALUE is also evaluated and bound as
517 the default value for the SYMBOL. 727 the default value for the SYMBOL.
518 REQUEST is a list of features we must 'require for SYMBOL. 728 REQUEST is a list of features we must 'require for SYMBOL.
519 COMMENT is a comment string about SYMBOL." 729 COMMENT is a comment string about SYMBOL.
520 (apply 'custom-theme-set-variables 'user args)) 730
521 731 Several properties of THEME and SYMBOL are used in the process:
522 (defun custom-theme-set-variables (theme &rest args) 732
523 "Initialize variables according to settings specified by args. 733 If THEME property `theme-immediate' is non-nil, this is equivalent of
524 Records the settings as belonging to THEME. 734 providing the NOW argument to all symbols in the argument list: SYMBOL
525 735 is bound to the evaluated VALUE. The only difference is SYMBOL property
526 See `custom-set-variables' for a description of the arguments ARGS." 736 `force-value': if NOW is non-nil, SYMBOL's property `force-value' is set to
737 the symbol `rogue', else if THEME's property `theme-immediate' is non-nil,
738 FACE's property `force-face' is set to the symbol `immediate'.
739
740 VALUE itself is saved unevaluated as SYMBOL property `saved-value' and
741 in SYMBOL's list property `theme-value' \(using `custom-push-theme')."
527 (custom-check-theme theme) 742 (custom-check-theme theme)
528 (setq args
529 (sort args
530 (lambda (a1 a2)
531 (let* ((sym1 (car a1))
532 (sym2 (car a2))
533 (1-then-2 (memq sym1 (get sym2 'custom-dependencies)))
534 (2-then-1 (memq sym2 (get sym1 'custom-dependencies))))
535 (cond ((and 1-then-2 2-then-1)
536 (error "Circular custom dependency between `%s' and `%s'"
537 sym1 sym2))
538 (1-then-2 t)
539 (2-then-1 nil)
540 ;; Put symbols with :require last. The macro
541 ;; define-minor-mode generates a defcustom
542 ;; with a :require and a :set, where the
543 ;; setter function calls the mode function.
544 ;; Putting symbols with :require last ensures
545 ;; that the mode function will see other
546 ;; customized values rather than default
547 ;; values.
548 (t (nth 3 a2)))))))
549 (let ((immediate (get theme 'theme-immediate))) 743 (let ((immediate (get theme 'theme-immediate)))
744 (setq args
745 (sort args
746 (lambda (a1 a2)
747 (let* ((sym1 (car a1))
748 (sym2 (car a2))
749 (1-then-2 (memq sym1 (get sym2 'custom-dependencies)))
750 (2-then-1 (memq sym2 (get sym1 'custom-dependencies))))
751 (cond ((and 1-then-2 2-then-1)
752 (error "Circular custom dependency between `%s' and `%s'"
753 sym1 sym2))
754 (2-then-1 nil)
755 ;; Put symbols with :require last. The macro
756 ;; define-minor-mode generates a defcustom
757 ;; with a :require and a :set, where the
758 ;; setter function calls the mode function.
759 ;; Putting symbols with :require last ensures
760 ;; that the mode function will see other
761 ;; customized values rather than default
762 ;; values.
763 (t (nth 3 a2)))))))
550 (while args 764 (while args
551 (let ((entry (car args))) 765 (let ((entry (car args)))
552 (if (listp entry) 766 (if (listp entry)
553 (let* ((symbol (nth 0 entry)) 767 (let* ((symbol (nth 0 entry))
554 (value (nth 1 entry)) 768 (value (nth 1 entry))
555 (now (nth 2 entry)) 769 (now (nth 2 entry))
556 (requests (nth 3 entry)) 770 (requests (nth 3 entry))
557 (comment (nth 4 entry)) 771 (comment (nth 4 entry))
558 (set (or (get symbol 'custom-set) 'custom-set-default))) 772 set)
559 (put symbol 'saved-value (list value)) 773 (when requests
774 (put symbol 'custom-requests requests)
775 (mapc 'require requests))
776 (setq set (or (get symbol 'custom-set) 'custom-set-default))
777 (put symbol 'saved-value (list value))
778 (put symbol 'saved-variable-comment comment)
560 (custom-push-theme 'theme-value symbol theme 'set value) 779 (custom-push-theme 'theme-value symbol theme 'set value)
561 (put symbol 'saved-variable-comment comment) 780 ;; Allow for errors in the case where the setter has
562 ;; Allow for errors in the case where the setter has 781 ;; changed between versions, say, but let the user know.
563 ;; changed between versions, say, but let the user know. 782 (condition-case data
564 (condition-case data 783 (cond ((or now immediate)
565 (cond ((or now immediate) 784 ;; Rogue variable, set it now.
566 ;; Rogue variable, set it now. 785 (put symbol 'force-value (if now 'rogue 'immediate))
567 (put symbol 'force-value (if now 'rogue 'immediate)) 786 (funcall set symbol (eval value)))
568 (funcall set symbol (eval value))) 787 ((default-boundp symbol)
569 ((default-boundp symbol) 788 ;; Something already set this, overwrite it.
570 ;; Something already set this, overwrite it. 789 (funcall set symbol (eval value))))
571 (funcall set symbol (eval value)))) 790 (error
572 (error
573 (message "Error setting %s: %s" symbol data))) 791 (message "Error setting %s: %s" symbol data)))
574 (and (or now (default-boundp symbol)) 792 (setq args (cdr args))
575 (put symbol 'variable-comment comment)) 793 (and (or now (default-boundp symbol))
576 (when requests 794 (put symbol 'variable-comment comment)))
577 (put symbol 'custom-requests requests) 795 ;; Old format, a plist of SYMBOL VALUE pairs.
578 (mapc 'require requests)) 796 (message "Warning: old format `custom-set-variables'")
579 (setq args (cdr args))) 797 (ding)
580 ;; Old format, a plist of SYMBOL VALUE pairs. 798 (sit-for 2)
581 (message "Warning: old format `custom-set-variables'") 799 (let ((symbol (nth 0 args))
582 (ding) 800 (value (nth 1 args)))
583 (sit-for 2) 801 (put symbol 'saved-value (list value))
584 (let ((symbol (nth 0 args))
585 (value (nth 1 args)))
586 (put symbol 'saved-value (list value))
587 (custom-push-theme 'theme-value symbol theme 'set value)) 802 (custom-push-theme 'theme-value symbol theme 'set value))
588 (setq args (cdr (cdr args)))))))) 803 (setq args (cdr (cdr args))))))))
589
590 (defvar custom-loaded-themes nil
591 "Themes in the order they are loaded.")
592
593 (defun custom-theme-loaded-p (theme)
594 "Return non-nil when THEME has been loaded."
595 (memq theme custom-loaded-themes))
596
597 (defun provide-theme (theme)
598 "Indicate that this file provides THEME."
599 (custom-check-theme theme)
600 (provide (get theme 'theme-feature))
601 (push theme custom-loaded-themes))
602
603 (defun require-theme (theme &optional soft)
604 "Try to load a theme by requiring its feature."
605 ;; Note we do no check for validity of the theme here.
606 ;; This allows to pull in themes by a file-name convention
607 (require (get theme 'theme-feature (custom-make-theme-feature theme))))
608
609 (defun custom-do-theme-reset (theme)
610 ; #### untested! slow!
611 (let (spec-list)
612 (mapatoms (lambda (symbol)
613 (setq spec-list (get symbol 'theme-value))
614 (when spec-list
615 (setq spec-list (delete-if (lambda (elt)
616 (eq (car elt) theme))
617 spec-list))
618 (put symbol 'theme-value spec-list)
619 (custom-theme-reset-internal symbol 'user))
620 (setq spec-list (get symbol 'theme-face))
621 (when spec-list
622 (setq spec-list (delete-if (lambda (elt)
623 (eq (car elt) theme))
624 spec-list))
625 (put symbol 'theme-face spec-list)
626 (custom-theme-reset-internal-face symbol 'user))))))
627
628 (defun custom-theme-load-themes (by-theme &rest body)
629 "Load the themes specified by BODY and record them as required by
630 theme BY-THEME. BODY is a sequence of
631 - a SYMBOL
632 require the theme SYMBOL
633 - a list (reset THEME)
634 Undo all the settings made by THEME.
635 - a list (hidden THEME)
636 require the THEME but hide it from the user."
637 (custom-check-theme by-theme)
638 (dolist (theme body)
639 (cond ((and (consp theme) (eq (car theme) 'reset))
640 (custom-do-theme-reset (cadr theme)))
641 ((and (consp theme) (eq (car theme) 'hidden))
642 (require-theme (cadr theme))
643 (unless (custom-theme-loaded-p (cadr theme))
644 (put (cadr theme) 'theme-hidden t)))
645 (t
646 (require-theme theme)
647 (remprop theme 'theme-hidden)))
648 (push theme (get by-theme 'theme-loads-themes))))
649
650 (defun custom-load-themes (&rest body)
651 "Load themes for the USER theme as specified by BODY.
652
653 BODY is as with custom-theme-load-themes."
654 (apply #'custom-theme-load-themes 'user body))
655
656
657
658
659 (defsubst copy-upto-last (elt list)
660 "Copy all the elements of the list upto the last occurrence of elt."
661 ;; Is it faster to do more work in C than to do less in elisp?
662 (nreverse (cdr (member elt (reverse list)))))
663
664 (defun custom-theme-value (theme theme-spec-list)
665 "Determine the value for THEME defined by THEME-SPEC-LIST.
666 Returns (list value) if found. Nil otherwise."
667 ;; Note we do _NOT_ signal an error if the theme is unknown
668 ;; it might have gone away without the user knowing.
669 (let ((theme-or-lower (memq theme (cons 'user custom-loaded-themes)))
670 value)
671 (mapc #'(lambda (theme-spec)
672 (when (member (car theme-spec) theme-or-lower)
673 (setq value (cdr theme-spec))
674 ;; We need to continue because if theme =A and we found
675 ;; B then if the load order is B A C B
676 ;; we actually want the value in C.
677 (setq theme-or-lower (copy-upto-last (car theme-spec)
678 theme-or-lower))
679 ;; We could should circuit if this is now nil.
680 ))
681 theme-spec-list)
682 (if value
683 (if (eq (car value) 'set)
684 (list (cadr value))
685 ;; Yet another reset spec. car value = reset
686 (custom-theme-value (cadr value) theme-spec-list)))))
687
688
689 (defun custom-theme-variable-value (variable theme)
690 "Return (list value) value of VARIABLE in THEME if the THEME modifies the
691 VARIABLE. Nil otherwise."
692 (custom-theme-value theme (get variable 'theme-value)))
693
694 (defun custom-theme-reset-internal (symbol to-theme)
695 (let ((value (custom-theme-variable-value symbol to-theme))
696 was-in-theme)
697 (setq was-in-theme value)
698 (setq value (or value (get symbol 'standard-value)))
699 (when value
700 (put symbol 'saved-value was-in-theme)
701 (if (or (get 'force-value symbol) (default-boundp symbol))
702 (funcall (get symbol 'custom-set 'set-default) symbol
703 (eval (car value)))))
704 value))
705
706
707 (defun custom-theme-reset-variables (theme &rest args)
708 "Reset the value of the variables to values previously defined.
709 Associate this setting with THEME.
710
711 ARGS is a list of lists of the form
712
713 (variable to-theme)
714
715 This means reset variable to its value in to-theme."
716 (custom-check-theme theme)
717 (mapc #'(lambda (arg)
718 (apply #'custom-theme-reset-internal arg)
719 (custom-push-theme 'theme-value (car arg) theme 'reset (cadr arg)))
720 args))
721
722 (defun custom-reset-variables (&rest args)
723 "Reset the value of the variables to values previously defined.
724 Associate this setting with the `user' theme.
725
726 The ARGS are as in `custom-theme-reset-variables'."
727 (apply #'custom-theme-reset-variables 'user args))
728 804
729 (defun custom-set-default (variable value) 805 (defun custom-set-default (variable value)
730 "Default :set function for a customizable variable. 806 "Default :set function for a customizable variable.
731 Normally, this sets the default value of VARIABLE to VALUE, 807 Normally, this sets the default value of VARIABLE to VALUE,
732 but if `custom-local-buffer' is non-nil, 808 but if `custom-local-buffer' is non-nil,
734 (if custom-local-buffer 810 (if custom-local-buffer
735 (with-current-buffer custom-local-buffer 811 (with-current-buffer custom-local-buffer
736 (set variable value)) 812 (set variable value))
737 (set-default variable value))) 813 (set-default variable value)))
738 814
815 (defun custom-quote (sexp)
816 "Quote SEXP iff it is not self quoting."
817 (if (or (memq sexp '(t nil))
818 (keywordp sexp)
819 (and (listp sexp)
820 (memq (car sexp) '(lambda)))
821 (stringp sexp)
822 (numberp sexp)
823 (vectorp sexp)
824 ;;; (and (fboundp 'characterp)
825 ;;; (characterp sexp))
826 )
827 sexp
828 (list 'quote sexp)))
829
830 (defun customize-mark-to-save (symbol)
831 "Mark SYMBOL for later saving.
832
833 If the default value of SYMBOL is different from the standard value,
834 set the `saved-value' property to a list whose car evaluates to the
835 default value. Otherwise, set it to nil.
836
837 To actually save the value, call `custom-save-all'.
838
839 Return non-nil iff the `saved-value' property actually changed."
840 (let* ((get (or (get symbol 'custom-get) 'default-value))
841 (value (funcall get symbol))
842 (saved (get symbol 'saved-value))
843 (standard (get symbol 'standard-value))
844 (comment (get symbol 'customized-variable-comment)))
845 ;; Save default value iff different from standard value.
846 (if (or (null standard)
847 (not (equal value (condition-case nil
848 (eval (car standard))
849 (error nil)))))
850 (put symbol 'saved-value (list (custom-quote value)))
851 (put symbol 'saved-value nil))
852 ;; Clear customized information (set, but not saved).
853 (put symbol 'customized-value nil)
854 ;; Save any comment that might have been set.
855 (when comment
856 (put symbol 'saved-variable-comment comment))
857 (not (equal saved (get symbol 'saved-value)))))
858
859 (defun customize-mark-as-set (symbol)
860 "Mark current value of SYMBOL as being set from customize.
861
862 If the default value of SYMBOL is different from the saved value if any,
863 or else if it is different from the standard value, set the
864 `customized-value' property to a list whose car evaluates to the
865 default value. Otherwise, set it to nil.
866
867 Return non-nil iff the `customized-value' property actually changed."
868 (let* ((get (or (get symbol 'custom-get) 'default-value))
869 (value (funcall get symbol))
870 (customized (get symbol 'customized-value))
871 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
872 ;; Mark default value as set iff different from old value.
873 (if (or (null old)
874 (not (equal value (condition-case nil
875 (eval (car old))
876 (error nil)))))
877 (put symbol 'customized-value (list (custom-quote value)))
878 (put symbol 'customized-value nil))
879 ;; Changed?
880 (not (equal customized (get symbol 'customized-value)))))
881
882 ;;; Theme Manipulation
883
884 (defvar custom-loaded-themes nil
885 "Themes in the order they are loaded.")
886
887 (defun custom-theme-loaded-p (theme)
888 "Return non-nil when THEME has been loaded."
889 (memq theme custom-loaded-themes))
890
891 (defun provide-theme (theme)
892 "Indicate that this file provides THEME.
893 Add THEME to `custom-loaded-themes' and `provide' whatever
894 is stored in THEME's property `theme-feature'.
895
896 Usually the theme-feature property contains a symbol created
897 by `custom-make-theme-feature'."
898 (custom-check-theme theme)
899 (provide (get theme 'theme-feature))
900 (setq custom-loaded-themes (nconc (list theme) custom-loaded-themes)))
901
902 (defun require-theme (theme)
903 "Try to load a theme by requiring its feature.
904 THEME's feature is stored in THEME's `theme-feature' property.
905
906 Usually the `theme-feature' property contains a symbol created
907 by `custom-make-theme-feature'."
908 ;; Note we do no check for validity of the theme here.
909 ;; This allows to pull in themes by a file-name convention
910 (require (or (get theme 'theme-feature)
911 (custom-make-theme-feature theme))))
912
913 (defun custom-remove-theme (spec-alist theme)
914 "Delete all elements from SPEC-ALIST whose car is THEME."
915 (let ((elt (assoc theme spec-alist)))
916 (while elt
917 (setq spec-alist (delete elt spec-alist)
918 elt (assoc theme spec-alist))))
919 spec-alist)
920
921 (defun custom-do-theme-reset (theme)
922 "Undo all settings defined by THEME.
923
924 A variable remains unchanged if its property `theme-value' does not
925 contain a value for THEME. A face remains unchanged if its property
926 `theme-face' does not contain a value for THEME. In either case, all
927 settings for THEME are removed from the property and the variable or
928 face is set to the `user' theme.
929
930 See `custom-known-themes' for a list of known themes."
931 (let (spec-list)
932 (mapatoms (lambda (symbol)
933 ;; This works even if symbol is both a variable and a
934 ;; face.
935 (setq spec-list (get symbol 'theme-value))
936 (when spec-list
937 (put symbol 'theme-value (custom-remove-theme spec-list theme))
938 (custom-theme-reset-internal symbol 'user))
939 (setq spec-list (get symbol 'theme-face))
940 (when spec-list
941 (put symbol 'theme-face (custom-remove-theme spec-list theme))
942 (custom-theme-reset-internal-face symbol 'user))))))
943
944 (defun custom-theme-load-themes (by-theme &rest body)
945 "Load the themes specified by BODY.
946 Record them as required by theme BY-THEME. BODY is a sequence of either
947
948 THEME
949 BY-THEME requires THEME
950 \(reset THEME)
951 Undo all the settings made by THEME
952 \(hidden THEME)
953 Require THEME but hide it from the user
954
955 All the themes loaded for BY-THEME are recorded in BY-THEME's property
956 `theme-loads-themes'. Any theme loaded with the hidden predicate will
957 be given the property `theme-hidden' unless it has been loaded before.
958 Whether a theme has been loaded before is determined by the function
959 `custom-theme-loaded-p'."
960 (custom-check-theme by-theme)
961 (let ((theme)
962 (themes-loaded (get by-theme 'theme-loads-themes)))
963 (while theme
964 (setq theme (car body)
965 body (cdr body))
966 (cond ((and (consp theme) (eq (car theme) 'reset))
967 (custom-do-theme-reset (cadr theme)))
968 ((and (consp theme) (eq (car theme) 'hidden))
969 (require-theme (cadr theme))
970 (unless (custom-theme-loaded-p (cadr theme))
971 (put (cadr theme) 'theme-hidden t)))
972 (t
973 (require-theme theme)
974 (put theme 'theme-hidden nil)))
975 (setq themes-loaded (nconc (list theme) themes-loaded)))
976 (put by-theme 'theme-loads-themes themes-loaded)))
977
978 (defun custom-load-themes (&rest body)
979 "Load themes for the USER theme as specified by BODY.
980
981 See `custom-theme-load-themes' for more information on BODY."
982 (apply 'custom-theme-load-themes 'user body))
983
984 ; (defsubst copy-upto-last (elt list)
985 ; "Copy all the elements of the list upto the last occurrence of elt"
986 ; ;; Is it faster to do more work in C than to do less in elisp?
987 ; (nreverse (cdr (member elt (reverse list)))))
988
989 (defun custom-theme-value (theme theme-spec-list)
990 "Determine the value for THEME defined by THEME-SPEC-LIST.
991 Returns a list with the original value if found; nil otherwise.
992
993 THEME-SPEC-LIST is an alist with themes as its key. As new themes are
994 installed, these are added to the front of THEME-SPEC-LIST.
995 Each element has the form
996
997 \(THEME MODE VALUE)
998
999 MODE is either the symbol `set' or the symbol `reset'. See
1000 `custom-push-theme' for more information on the format of
1001 THEME-SPEC-LIST."
1002 ;; Note we do _NOT_ signal an error if the theme is unknown
1003 ;; it might have gone away without the user knowing.
1004 (let ((value (cdr (assoc theme theme-spec-list))))
1005 (if value
1006 (if (eq (car value) 'set)
1007 (cdr value)
1008 (custom-theme-value (cadr value) theme-spec-list)))))
1009
1010 (defun custom-theme-variable-value (variable theme)
1011 "Return (list value) indicating value of VARIABLE in THEME.
1012 If THEME does not define a value for VARIABLE, return nil. The value
1013 definitions per theme are stored in VARIABLE's property `theme-value'.
1014 The actual work is done by function `custom-theme-value', which see.
1015 See `custom-push-theme' for more information on how these definitions
1016 are stored."
1017 (custom-theme-value theme (get variable 'theme-value)))
1018
1019 (defun custom-theme-reset-internal (symbol to-theme)
1020 "Reset SYMBOL to the value defined by TO-THEME.
1021 If SYMBOL is not defined in TO-THEME, reset SYMBOL to the standard
1022 value. See `custom-theme-variable-value'. The standard value is
1023 stored in SYMBOL's property `standard-value'."
1024 (let ((value (custom-theme-variable-value symbol to-theme))
1025 was-in-theme)
1026 (setq was-in-theme value)
1027 (setq value (or value (get symbol 'standard-value)))
1028 (when value
1029 (put symbol 'saved-value was-in-theme)
1030 (if (or (get 'force-value symbol) (default-boundp symbol))
1031 (funcall (or (get symbol 'custom-set) 'set-default) symbol
1032 (eval (car value)))))
1033 value))
1034
1035 (defun custom-theme-reset-variables (theme &rest args)
1036 "Reset the value of the variables to values previously defined.
1037 Associate this setting with THEME.
1038
1039 ARGS is a list of lists of the form
1040
1041 (VARIABLE TO-THEME)
1042
1043 This means reset VARIABLE to its value in TO-THEME."
1044 (custom-check-theme theme)
1045 (mapcar '(lambda (arg)
1046 (apply 'custom-theme-reset-internal arg)
1047 (custom-push-theme 'theme-value (car arg) theme 'reset (cadr arg)))
1048 args))
1049
1050 (defun custom-reset-variables (&rest args)
1051 "Reset the value of the variables to values previously saved.
1052 This is the setting associated the `user' theme.
1053
1054 ARGS is a list of lists of the form
1055
1056 (VARIABLE TO-THEME)
1057
1058 This means reset VARIABLE to its value in TO-THEME."
1059 (apply 'custom-theme-reset-variables 'user args))
1060
739 ;;; The End. 1061 ;;; The End.
740
741 ;; BEGIN SYNC WITH FSF 21.2
742 1062
743 ;; Process the defcustoms for variables loaded before this file. 1063 ;; Process the defcustoms for variables loaded before this file.
744 ;; `custom-declare-variable-list' is defvar'd in subr.el. Utility programs 1064 ;; `custom-declare-variable-list' is defvar'd in subr.el. Utility programs
745 ;; run from temacs that do not load subr.el should defvar it themselves. 1065 ;; run from temacs that do not load subr.el should defvar it themselves.
746 ;; (As of 21.5.11, make-docfile.el.) 1066 ;; (As of 21.5.11, make-docfile.el.)
747 (while custom-declare-variable-list 1067 (while custom-declare-variable-list
748 (apply 'custom-declare-variable (car custom-declare-variable-list)) 1068 (apply 'custom-declare-variable (car custom-declare-variable-list))
749 (setq custom-declare-variable-list (cdr custom-declare-variable-list))) 1069 (setq custom-declare-variable-list (cdr custom-declare-variable-list)))
750 1070
751 ;; END SYNC WITH FSF 21.2
752
753 ;; custom.el ends here 1071 ;; custom.el ends here