diff options
author | Chong Yidong <cyd@stupidchicken.com> | 2006-01-02 15:11:14 +0000 |
---|---|---|
committer | Chong Yidong <cyd@stupidchicken.com> | 2006-01-02 15:11:14 +0000 |
commit | 1338ed75ec9e4ce43ed28676a30cfa720aad8571 (patch) | |
tree | d64db3f47aaf5dfac93b84abff8739c52446f7cb /lisp/custom.el | |
parent | 73d80331d1ff6b8979fb4b3e0fac0832653bf581 (diff) | |
download | emacs-1338ed75ec9e4ce43ed28676a30cfa720aad8571.tar.gz |
* custom.el: Move Custom Themes commentary to start of theme code.
(custom-known-themes): Rename `standard' theme to `changed'.
(custom-push-theme): Caller no longer specifies what theme to use
when doing `reset'---the setting is simply removed from the theme.
Delete MODE from `theme-value' and `theme-settings' properties.
(custom-declare-theme): Ignore &rest args since we don't use them.
(custom-loaded-themes): Delete variable.
(custom-theme-load-themes, custom-theme-loaded-p)
(custom-theme-value): Delete functions.
(custom-declare-theme): Signal error on invalid theme names.
(provide-theme): custom-loaded-themes was deleted.
(load-theme): Load the file unconditionally.
(enable-theme): Call `load-theme' if theme is undefined.
(custom-enabled-themes): Only update value for successful loads.
(disable-theme): Complete from enabled themes when interactive.
(custom-variable-theme-value): Calculate theme value directly.
(custom-theme-reset-variables, custom-reset-variables): Mark as
XEmacs compatibility functions. We don't actually use these.
* cus-edit.el (custom-variable-state-set): Use
custom-variable-theme-value instead of custom-theme-value.
(custom-face-state-set): Rename `standard' theme to `changed'.
(custom-save-variables, custom-save-faces): Delete unneeded
references to custom-reset-variables.
(custom-save-resets): Delete function.
(custom-save-variables, custom-save-faces): MODE argument deleted.
(custom-save-variables, custom-save-faces): Ignore theme values.
* cus-face.el (custom-theme-reset-faces): Mark as XEmacs
compatibility function.
Diffstat (limited to 'lisp/custom.el')
-rw-r--r-- | lisp/custom.el | 413 |
1 files changed, 159 insertions, 254 deletions
diff --git a/lisp/custom.el b/lisp/custom.el index 18d79a6af23..7741ce2e933 100644 --- a/lisp/custom.el +++ b/lisp/custom.el @@ -599,9 +599,56 @@ This recursively follows aliases." ((equal load "cus-edit")) (t (condition-case nil (load load) (error nil)))))))) -(defvar custom-known-themes '(user standard) +;;; Custom Themes + +;; Custom themes are collections of settings that can be enabled or +;; disabled as a unit. + +;; Each Custom theme is defined by a symbol, called the theme name. +;; The `theme-settings' property of the theme name records the +;; variable and face settings of the theme. This property is a list +;; of elements, each of the form +;; +;; (PROP SYMBOL THEME VALUE) +;; +;; - PROP is either `theme-value' or `theme-face' +;; - SYMBOL is the face or variable name +;; - THEME is the theme name (redundant, but simplifies the code) +;; - VALUE is an expression that gives the theme's setting for SYMBOL. +;; +;; The theme name also has a `theme-feature' property, whose value is +;; specified when the theme is defined (see `custom-declare-theme'). +;; Usually, this is just a symbol named THEME-theme. This lets +;; external libraries call (require 'foo-theme). + +;; In addition, each symbol (either a variable or a face) affected by +;; an *enabled* theme has a `theme-value' or `theme-face' property, +;; which is a list of elements each of the form +;; +;; (THEME VALUE) +;; +;; which have the same meanings as in `theme-settings'. +;; +;; The `theme-value' and `theme-face' lists are ordered by decreasing +;; theme precedence. Thus, the first element is always the one that +;; is in effect. + +;; Each theme is stored in a theme file, with filename THEME-theme.el. +;; Loading a theme basically involves calling (load "THEME-theme") +;; This is done by the function `load-theme'. Loading a theme +;; automatically enables it. +;; +;; When a theme is enabled, the `theme-value' and `theme-face' +;; properties for the affected symbols are set. When a theme is +;; disabled, its settings are removed from the `theme-value' and +;; `theme-face' properties, but the theme's own `theme-settings' +;; property remains unchanged. + +;;; Defining themes + +(defvar custom-known-themes '(user changed) "Themes that have been defined with `deftheme'. -The default value is the list (user standard). The theme `standard' +The default value is the list (user changed). The theme `changed' contains the settings before custom themes are applied. The theme `user' contains all the settings the user customized and saved. Additional themes declared with the `deftheme' macro will be added to @@ -616,44 +663,22 @@ the front of this list.") (unless (custom-theme-p theme) (error "Unknown theme `%s'" theme))) -;;; Initializing. - -(defun custom-push-theme (prop symbol theme mode value) - "Record a value for face or variable SYMBOL in custom theme THEME. -PROP is`theme-face' for a face, `theme-value' for a variable. -The value is specified by (THEME MODE VALUE), which is interpreted -by `custom-theme-value'. +(defun custom-push-theme (prop symbol theme mode &optional value) + "Record VALUE for face or variable SYMBOL in custom theme THEME. +PROP is `theme-face' for a face, `theme-value' for a variable. MODE can be either the symbol `set' or the symbol `reset'. If it is the symbol `set', then VALUE is the value to use. If it is the symbol -`reset', then VALUE is either another theme, which means to use the -value defined by that theme; or nil, which means to remove SYMBOL from -THEME entirely. - -In the following example, the variable `goto-address-url-face' has been -set by three different themes. Its `theme-value' property is: - - \((subtle-hacker reset gnome2) - \(jonadab set underline) - \(gnome2 set info-xref) - -The theme value defined by `subtle-hacker' is in effect, because -that theme currently has the highest precedence. The theme -`subtle-hacker' says to use the same value for the variable as -the theme `gnome2'. Therefore, the theme value of the variable -is `info-xref'. To change the precedence of the themes, use -`enable-theme'. - -The user has not customized the variable; had he done that, the -list would contain an entry for the `user' theme, too. +`reset', then SYMBOL will be removed from THEME (VALUE is ignored). See `custom-known-themes' for a list of known themes." (unless (memq prop '(theme-value theme-face)) (error "Unknown theme property")) (let* ((old (get symbol prop)) - (setting (assq theme old)) - (theme-settings (get theme 'theme-settings))) - (if (and (eq mode 'reset) (null value)) + (setting (assq theme old)) ; '(theme value) + (theme-settings ; '(prop symbol theme value) + (get theme 'theme-settings))) + (if (eq mode 'reset) ;; Remove a setting. (when setting (let (res) @@ -671,13 +696,12 @@ See `custom-known-themes' for a list of known themes." (eq (cadr theme-setting) symbol)) (setq res theme-setting))) (put theme 'theme-settings - (cons (list prop symbol theme mode value) + (cons (list prop symbol theme value) (delq res theme-settings))) - (setcar (cdr setting) mode) - (setcar (cddr setting) value)) + (setcar (cdr setting) value)) ;; Add a new setting. ;; If the user changed the value outside of Customize, we - ;; first save the current value to a fake theme, `standard'. + ;; first save the current value to a fake theme, `changed'. ;; This ensures that the user-set value comes back if the ;; theme is later disabled. (if (null old) @@ -686,13 +710,13 @@ See `custom-known-themes' for a list of known themes." (or (null (get symbol 'standard-value)) (not (equal (eval (car (get symbol 'standard-value))) (symbol-value symbol))))) - (setq old (list (list 'standard 'set (symbol-value symbol)))) + (setq old (list (list 'changed (symbol-value symbol)))) (if (facep symbol) - (setq old (list (list 'standard 'set (list + (setq old (list (list 'changed (list (append '(t) (custom-face-attributes-get symbol nil))))))))) - (put symbol prop (cons (list theme mode value) old)) + (put symbol prop (cons (list theme value) old)) (put theme 'theme-settings - (cons (list prop symbol theme mode value) + (cons (list prop symbol theme value) theme-settings)))))) (defvar custom-local-buffer nil @@ -904,43 +928,31 @@ Return non-nil iff the `customized-value' property actually changed." ;;; Defining themes. -;; deftheme is used at the beginning of the file that records a theme. +;; A theme file should be named `THEME-theme.el' (where THEME is the theme +;; name), and found in either `custom-theme-directory' or the load path. +;; It has the following format: +;; +;; (deftheme THEME +;; DOCSTRING) +;; +;; (custom-theme-set-variables +;; 'THEME +;; [THEME-VARIABLES]) +;; +;; (custom-theme-set-faces +;; 'THEME +;; [THEME-FACES]) +;; +;; (provide-theme 'THEME) -(defmacro deftheme (theme &optional doc &rest args) - "Declare custom theme THEME. -The optional argument DOC is a doc string describing the theme. -The remaining arguments should have the form - [KEYWORD VALUE]... +;; The IGNORED arguments to deftheme come from the XEmacs theme code, where +;; they were used to supply keyword-value pairs like `:immediate', +;; `:variable-reset-string', etc. We don't use any of these, so ignore them. -The following KEYWORD's are defined: - -:short-description - VALUE is a short (one line) description of the theme. If not - given, DOC is used. -:immediate - If VALUE is non-nil, variables specified in this theme are set - immediately when loading the theme. -:variable-set-string - VALUE is a string used to indicate that a variable takes its - setting from this theme. It is passed to FORMAT with the name - of the theme as an additional argument. If not given, a - generic description is used. -:variable-reset-string - VALUE is a string used in the case a variable has been forced - to its value in this theme. It is passed to FORMAT with the - name of the theme as an additional argument. If not given, a - generic description is used. -:face-set-string - VALUE is a string used to indicate that a face takes its - setting from this theme. It is passed to FORMAT with the name - of the theme as an additional argument. If not given, a - generic description is used. -:face-reset-string - VALUE is a string used in the case a face has been forced to - its value in this theme. It is passed to FORMAT with the name - of the theme as an additional argument. If not given, a - generic description is used. +(defmacro deftheme (theme &optional doc &rest ignored) + "Declare THEME to be a Custom theme. +The optional argument DOC is a doc string describing the theme. Any theme `foo' should be defined in a file called `foo-theme.el'; see `custom-make-theme-feature' for more information." @@ -948,42 +960,17 @@ see `custom-make-theme-feature' for more information." ;; It is better not to use backquote in this file, ;; because that makes a bootstrapping problem ;; if you need to recompile all the Lisp files using interpreted code. - (nconc (list 'custom-declare-theme - (list 'quote theme) - (list 'quote feature) - doc) - args))) + (list 'custom-declare-theme (list 'quote theme) (list 'quote feature) doc))) -(defun custom-declare-theme (theme feature &optional doc &rest args) +(defun custom-declare-theme (theme feature &optional doc &rest ignored) "Like `deftheme', but THEME is evaluated as a normal argument. -FEATURE is the feature this theme provides. This symbol is created -from THEME by `custom-make-theme-feature'." +FEATURE is the feature this theme provides. Normally, this is a symbol +created from THEME by `custom-make-theme-feature'." + (if (memq theme '(user changed)) + (error "Custom theme cannot be named %S" theme)) (add-to-list 'custom-known-themes theme) (put theme 'theme-feature feature) - (when doc - (put theme 'theme-documentation doc)) - (while args - (let ((arg (car args))) - (setq args (cdr args)) - (unless (symbolp arg) - (error "Junk in args %S" args)) - (let ((keyword arg) - (value (car args))) - (unless args - (error "Keyword %s is missing an argument" keyword)) - (setq args (cdr args)) - (cond ((eq keyword :short-description) - (put theme 'theme-short-description value)) - ((eq keyword :immediate) - (put theme 'theme-immediate value)) - ((eq keyword :variable-set-string) - (put theme 'theme-variable-set-string value)) - ((eq keyword :variable-reset-string) - (put theme 'theme-variable-reset-string value)) - ((eq keyword :face-set-string) - (put theme 'theme-face-set-string value)) - ((eq keyword :face-reset-string) - (put theme 'theme-face-reset-string value))))))) + (when doc (put theme 'theme-documentation doc))) (defun custom-make-theme-feature (theme) "Given a symbol THEME, create a new symbol by appending \"-theme\". @@ -998,38 +985,6 @@ Every theme X has a property `provide-theme' whose value is \"X-theme\". ;;; Loading themes. -;; The variable and face settings of a theme are recorded in -;; the `theme-settings' property of the theme name. -;; This property's value is a list of elements, each of the form -;; (PROP SYMBOL THEME MODE VALUE), where PROP is `theme-value' or `theme-face' -;; and SYMBOL is the face or variable name. -;; THEME is the theme name itself; that's redundant, but simplifies things. -;; MODE is `set' or `reset'. -;; If MODE is `set', then VALUE is an expression that specifies the -;; theme's setting for SYMBOL. -;; If MODE is `reset', then VALUE is another theme, -;; and it means to use the value from that theme. - -;; Each variable has a `theme-value' property that describes all the -;; settings of enabled themes that apply to it. -;; Each face name has a `theme-face' property that describes all the -;; settings of enabled themes that apply to it. -;; The property value is a list of settings, each with the form -;; (THEME MODE VALUE). THEME, MODE and VALUE are as above. -;; Each of these lists is ordered by decreasing theme precedence. -;; Thus, the first element is always the one that is in effect. - -;; Disabling a theme removes its settings from the `theme-value' and -;; `theme-face' properties, but the theme's own `theme-settings' -;; property remains unchanged. - -;; Loading a theme implicitly enables it. Enabling a theme adds its -;; settings to the symbols' `theme-value' and `theme-face' properties, -;; or moves them to the front of those lists if they're already present. - -(defvar custom-loaded-themes nil - "Custom themes that have been loaded.") - (defcustom custom-theme-directory (if (eq system-type 'ms-dos) ;; MS-DOS cannot have initial dot. @@ -1043,76 +998,33 @@ into this directory." :group 'customize :version "22.1") -(defun custom-theme-loaded-p (theme) - "Return non-nil if THEME has been loaded." - (memq theme custom-loaded-themes)) - (defun provide-theme (theme) - "Indicate that this file provides THEME, and mark it as enabled. -Add THEME to `custom-loaded-themes' and `custom-enabled-themes', -and `provide' the feature name stored in THEME's property `theme-feature'. - -Usually the `theme-feature' property contains a symbol created -by `custom-make-theme-feature'." - (if (eq theme 'user) - (error "Custom theme cannot be named `user'")) + "Indicate that this file provides THEME. +This calls `provide' to provide the feature name stored in THEME's +property `theme-feature' (which is usually a symbol created by +`custom-make-theme-feature')." + (if (memq theme '(user changed)) + (error "Custom theme cannot be named %S" theme)) (custom-check-theme theme) (provide (get theme 'theme-feature)) - (push theme custom-loaded-themes) - ;; Loading a theme also installs its settings, - ;; so mark it as "enabled". + ;; Loading a theme also enables it. (push theme custom-enabled-themes) ;; `user' must always be the highest-precedence enabled theme. ;; Make that remain true. (This has the effect of making user settings ;; override the ones just loaded, too.) - (enable-theme 'user)) + (let ((custom-enabling-themes t)) + (enable-theme 'user))) (defun load-theme (theme) "Try to load a theme's settings from its file. This also enables the theme; use `disable-theme' to disable it." - - ;; THEME's feature is stored in THEME's `theme-feature' property. - ;; Usually the `theme-feature' property contains a symbol created - ;; by `custom-make-theme-feature'. - ;; Note we do no check for validity of the theme here. ;; This allows to pull in themes by a file-name convention (interactive "SCustom theme name: ") (let ((load-path (if (file-directory-p custom-theme-directory) (cons custom-theme-directory load-path) load-path))) - (require (or (get theme 'theme-feature) - (custom-make-theme-feature theme))))) - -;;; How to load and enable various themes as part of `user'. - -(defun custom-theme-load-themes (by-theme &rest body) - "Load the themes specified by BODY. -Record them as required by theme BY-THEME. - -BODY is a sequence of either - -THEME - Load THEME and enable it. -\(reset THEME) - Undo all the settings made by THEME -\(hidden THEME) - Load THEME but do not enable it. - -All the themes loaded for BY-THEME are recorded in BY-THEME's property -`theme-loads-themes'." - (custom-check-theme by-theme) - (let ((themes-loaded (get by-theme 'theme-loads-themes))) - (dolist (theme body) - (cond ((and (consp theme) (eq (car theme) 'reset)) - (disable-theme (cadr theme))) - ((and (consp theme) (eq (car theme) 'hidden)) - (load-theme (cadr theme)) - (disable-theme (cadr theme))) - (t - (load-theme theme))) - (push theme themes-loaded)) - (put by-theme 'theme-loads-themes themes-loaded))) + (load (symbol-name (custom-make-theme-feature theme))))) ;;; Enabling and disabling loaded themes. @@ -1123,25 +1035,26 @@ All the themes loaded for BY-THEME are recorded in BY-THEME's property The newly enabled theme gets the highest precedence (after `user'). If it is already enabled, just give it highest precedence (after `user'). -This signals an error if THEME does not specify any theme -settings. Theme settings are set using `load-theme'." +If THEME does not specify any theme settings, this tries to load +the theme from its theme file, by calling `load-theme'." (interactive "SEnable Custom theme: ") - (unless (or (eq theme 'user) (memq theme custom-loaded-themes)) - (error "Theme %s not defined" (symbol-name theme))) - (let ((settings (get theme 'theme-settings))) - (dolist (s settings) - (let* ((prop (car s)) - (symbol (cadr s)) - (spec-list (get symbol prop))) - (put symbol prop (cons (cddr s) (assq-delete-all theme spec-list))) - (if (eq prop 'theme-value) - (custom-theme-recalc-variable symbol) - (custom-theme-recalc-face symbol))))) - (unless (eq theme 'user) - (setq custom-enabled-themes - (cons theme (delq theme custom-enabled-themes))) - (unless custom-enabling-themes - (enable-theme 'user)))) + (if (not (custom-theme-p theme)) + (load-theme theme) + ;; This could use a bit of optimization -- cyd + (let ((settings (get theme 'theme-settings))) + (dolist (s settings) + (let* ((prop (car s)) + (symbol (cadr s)) + (spec-list (get symbol prop))) + (put symbol prop (cons (cddr s) (assq-delete-all theme spec-list))) + (if (eq prop 'theme-value) + (custom-theme-recalc-variable symbol) + (custom-theme-recalc-face symbol))))) + (unless (eq theme 'user) + (setq custom-enabled-themes + (cons theme (delq theme custom-enabled-themes))) + (unless custom-enabling-themes + (enable-theme 'user))))) (defcustom custom-enabled-themes nil "List of enabled Custom Themes, highest precedence first. @@ -1155,28 +1068,36 @@ and always takes precedence over other Custom Themes." ;; defined in a theme (e.g. `user'). Enabling the theme sets ;; custom-enabled-themes, which enables the theme... (unless custom-enabling-themes - (let ((custom-enabling-themes t)) + (let ((custom-enabling-themes t) failures) (setq themes (delq 'user (delete-dups themes))) (if (boundp symbol) (dolist (theme (symbol-value symbol)) (if (not (memq theme themes)) (disable-theme theme)))) (dolist (theme (reverse themes)) - (if (or (custom-theme-loaded-p theme) (eq theme 'user)) + (condition-case nil (enable-theme theme) - (load-theme theme))) + (error (progn (push theme failures) + (setq themes (delq theme themes)))))) (enable-theme 'user) - (custom-set-default symbol themes))))) + (custom-set-default symbol themes) + (if failures + (message "Failed to enable themes: %s" + (mapconcat 'symbol-name failures " "))))))) -(defun custom-theme-enabled-p (theme) +(defsubst custom-theme-enabled-p (theme) "Return non-nil if THEME is enabled." (memq theme custom-enabled-themes)) (defun disable-theme (theme) "Disable all variable and face settings defined by THEME. See `custom-enabled-themes' for a list of enabled themes." - (interactive "SDisable Custom theme: ") - (when (memq theme custom-enabled-themes) + (interactive (list (intern + (completing-read + "Disable Custom theme: " + (mapcar 'symbol-name custom-enabled-themes) + nil t)))) + (when (custom-theme-enabled-p theme) (let ((settings (get theme 'theme-settings))) (dolist (s settings) (let* ((prop (car s)) @@ -1189,28 +1110,6 @@ See `custom-enabled-themes' for a list of enabled themes." (setq custom-enabled-themes (delq theme custom-enabled-themes)))) -(defun custom-theme-value (theme setting-list) - "Determine the value specified for THEME according to SETTING-LIST. -Returns a list whose car is the specified value, if we -find one; nil otherwise. - -SETTING-LIST is an alist with themes as its key. -Each element has the form: - - \(THEME MODE VALUE) - -MODE is either the symbol `set' or the symbol `reset'. See -`custom-push-theme' for more information on the format of -SETTING-LIST." - ;; Note we do _NOT_ signal an error if the theme is unknown - ;; it might have gone away without the user knowing. - (let ((elt (cdr (assoc theme setting-list)))) - (if elt - (if (eq (car elt) 'set) - (cdr elt) - ;; `reset' means refer to another theme's value in the same alist. - (custom-theme-value (cadr elt) setting-list))))) - (defun custom-variable-theme-value (variable) "Return (list VALUE) indicating the custom theme value of VARIABLE. That is to say, it specifies what the value should be according to @@ -1219,47 +1118,53 @@ currently enabled custom themes. This function returns nil if no custom theme specifies a value for VARIABLE." (let* ((theme-value (get variable 'theme-value))) (if theme-value - (custom-theme-value (car (car theme-value)) theme-value)))) + (cdr (car theme-value))))) (defun custom-theme-recalc-variable (variable) "Set VARIABLE according to currently enabled custom themes." (let ((valspec (custom-variable-theme-value variable))) - (when valspec - (put variable 'saved-value valspec)) - (unless valspec + (if valspec + (put variable 'saved-value valspec) (setq valspec (get variable 'standard-value))) - (when valspec - (if (or (get 'force-value variable) (default-boundp variable)) - (funcall (or (get variable 'custom-set) 'set-default) variable - (eval (car valspec))))))) + (if (and valspec + (or (get variable 'force-value) + (default-boundp variable))) + (funcall (or (get variable 'custom-set) 'set-default) variable + (eval (car valspec)))))) (defun custom-theme-recalc-face (face) "Set FACE according to currently enabled custom themes." (if (facep face) (let ((theme-faces (reverse (get face 'theme-face)))) (dolist (spec theme-faces) - (face-spec-set face (car (cddr spec))))))) + (face-spec-set face (cadr spec)))))) +;;; XEmacs compability functions + +;; In XEmacs, when you reset a Custom Theme, you have to specify the +;; theme to reset it to. We just apply the next available theme, so +;; just ignore the IGNORED arguments. + (defun custom-theme-reset-variables (theme &rest args) - "Reset the specs in THEME of some variables to their values in other themes. + "Reset some variable settings in THEME to their values in other themes. Each of the arguments ARGS has this form: - (VARIABLE FROM-THEME) + (VARIABLE IGNORED) -This means reset VARIABLE to its value in FROM-THEME." +This means reset VARIABLE. (The argument IGNORED is ignored." (custom-check-theme theme) (dolist (arg args) - (custom-push-theme 'theme-value (car arg) theme 'reset (cadr arg)))) + (custom-push-theme 'theme-value (car arg) theme 'reset))) (defun custom-reset-variables (&rest args) - "Reset the specs of some variables to their values in certain themes. + "Reset the specs of some variables to their values in other themes. This creates settings in the `user' theme. Each of the arguments ARGS has this form: - (VARIABLE FROM-THEME) + (VARIABLE IGNORED) -This means reset VARIABLE to its value in FROM-THEME." +This means reset VARIABLE. (The argument IGNORED is ignored." (apply 'custom-theme-reset-variables 'user args)) ;;; The End. |