X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/85340a068c2685d6bcfc568adc607cf0a37c9f9a..31f84d032894a5277d1d0f4a302baa3f6b4b3db4:/lisp/custom.el diff --git a/lisp/custom.el b/lisp/custom.el index afa5b20ca2..a724d497f5 100644 --- a/lisp/custom.el +++ b/lisp/custom.el @@ -1,11 +1,10 @@ ;;; custom.el -- Tools for declaring and initializing options. ;; -;; Copyright (C) 1996, 1997 Free Software Foundation, Inc. +;; Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc. ;; ;; Author: Per Abrahamsen +;; Maintainer: FSF ;; Keywords: help, faces -;; Version: 1.84 -;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ ;; This file is part of GNU Emacs. @@ -26,11 +25,9 @@ ;;; Commentary: ;; -;; If you want to use this code, please visit the URL above. -;; ;; This file only contain the code needed to declare and initialize ;; user options. The code to customize options is autoloaded from -;; `cus-edit.el'. +;; `cus-edit.el' and is documented in the Emacs Lisp Reference manual. ;; The code implementing face declarations is in `cus-face.el' @@ -38,53 +35,120 @@ (require 'widget) -(define-widget-keywords :prefix :tag :load :link :options :type :group) - (defvar custom-define-hook nil ;; Customize information for this option is in `cus-edit.el'. "Hook called after defining each customize option.") ;;; The `defcustom' Macro. -(defun custom-declare-variable (symbol value doc &rest args) - "Like `defcustom', but SYMBOL and VALUE are evaluated as normal arguments." - ;; Bind this variable unless it already is bound. +(defun custom-initialize-default (symbol value) + "Initialize SYMBOL with VALUE. +This will do nothing if symbol already has a default binding. +Otherwise, if symbol has a `saved-value' property, it will evaluate +the car of that and used as the default binding for symbol. +Otherwise, VALUE will be evaluated and used as the default binding for +symbol." (unless (default-boundp symbol) - ;; Use the saved value if it exists, otherwise the factory setting. + ;; Use the saved value if it exists, otherwise the standard setting. (set-default symbol (if (get symbol 'saved-value) (eval (car (get symbol 'saved-value))) - (eval value)))) - ;; Remember the factory setting. - (put symbol 'factory-value (list value)) + (eval value))))) + +(defun custom-initialize-set (symbol value) + "Initialize SYMBOL based on VALUE. +If the symbol doesn't have a default binding already, +then set it using its `:set' function (or `set-default' if it has none). +The value is either the value in the symbol's `saved-value' property, +if any, or VALUE." + (unless (default-boundp symbol) + (funcall (or (get symbol 'custom-set) 'set-default) + symbol + (if (get symbol 'saved-value) + (eval (car (get symbol 'saved-value))) + (eval value))))) + +(defun custom-initialize-reset (symbol value) + "Initialize SYMBOL based on VALUE. +Set the symbol, using its `:set' function (or `set-default' if it has none). +The value is either the symbol's current value + \(as obtained using the `:get' function), if any, +or the value in the symbol's `saved-value' property if any, +or (last of all) VALUE." + (funcall (or (get symbol 'custom-set) 'set-default) + symbol + (cond ((default-boundp symbol) + (funcall (or (get symbol 'custom-get) 'default-value) + symbol)) + ((get symbol 'saved-value) + (eval (car (get symbol 'saved-value)))) + (t + (eval value))))) + +(defun custom-initialize-changed (symbol value) + "Initialize SYMBOL with VALUE. +Like `custom-initialize-reset', but only use the `:set' function if the +not using the standard setting. +For the standard setting, use the `set-default'." + (cond ((default-boundp symbol) + (funcall (or (get symbol 'custom-set) 'set-default) + symbol + (funcall (or (get symbol 'custom-get) 'default-value) + symbol))) + ((get symbol 'saved-value) + (funcall (or (get symbol 'custom-set) 'set-default) + symbol + (eval (car (get symbol 'saved-value))))) + (t + (set-default symbol (eval value))))) + +(defun custom-declare-variable (symbol default doc &rest args) + "Like `defcustom', but SYMBOL and DEFAULT are evaluated as normal arguments. +DEFAULT should be an expression to evaluate to compute the default value, +not the default value itself." + ;; Remember the standard setting. + (put symbol 'standard-value (list default)) ;; Maybe this option was rogue in an earlier version. It no longer is. (when (get symbol 'force-value) - ;; It no longer is. (put symbol 'force-value nil)) (when doc (put symbol 'variable-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)) + (let ((initialize 'custom-initialize-reset) + (requests nil)) + (while args + (let ((arg (car args))) (setq args (cdr args)) - (cond ((eq keyword :type) - (put symbol 'custom-type value)) - ((eq keyword :options) - (if (get symbol 'custom-options) - ;; Slow safe code to avoid duplicates. - (mapcar (lambda (option) - (custom-add-option symbol option)) - value) - ;; Fast code for the common case. - (put symbol 'custom-options (copy-sequence value)))) - (t - (custom-handle-keyword symbol keyword value - 'custom-variable)))))) + (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 :initialize) + (setq initialize value)) + ((eq keyword :set) + (put symbol 'custom-set value)) + ((eq keyword :get) + (put symbol 'custom-get value)) + ((eq keyword :require) + (setq requests (cons value requests))) + ((eq keyword :type) + (put symbol 'custom-type (purecopy value))) + ((eq keyword :options) + (if (get symbol 'custom-options) + ;; Slow safe code to avoid duplicates. + (mapcar (lambda (option) + (custom-add-option symbol option)) + value) + ;; Fast code for the common case. + (put symbol 'custom-options (copy-sequence value)))) + (t + (custom-handle-keyword symbol keyword value + 'custom-variable)))))) + (put symbol 'custom-requests requests) + ;; Do the actual initialization. + (funcall initialize symbol default)) + (setq current-load-list (cons symbol current-load-list)) (run-hooks 'custom-define-hook) symbol) @@ -96,19 +160,46 @@ Neither SYMBOL nor VALUE needs to be quoted. If SYMBOL is not already bound, initialize it to VALUE. The remaining arguments should have the form - [KEYWORD VALUE]... + [KEYWORD VALUE]... -The following KEYWORD's are defined: +The following keywords are meaningful: -:type VALUE should be a widget type. +:type VALUE should be a widget type for editing the symbols value. + The default is `sexp'. :options VALUE should be a list of valid members of the widget type. -:group VALUE should be a customization group. +:group VALUE should be a customization group. Add SYMBOL to that group. +:initialize + VALUE should be a function used to initialize the + variable. It takes two arguments, the symbol and value + given in the `defcustom' call. The default is + `custom-initialize-default' +:set VALUE should be a function to set the value of the symbol. + It takes two arguments, the symbol to set and the value to + give it. The default choice of function is `custom-set-default'. +:get VALUE should be a function to extract the value of symbol. + The function takes one argument, a symbol, and should return + the current value for that symbol. The default choice of function + is `custom-default-value'. +:require + VALUE should be a feature symbol. If you save a value + for this option, then when your `.emacs' file loads the value, + it does (require VALUE) first. +:version + VALUE should be a string specifying that the variable was + first introduced, or its default value was changed, in Emacs + version VERSION. Read the section about customization in the Emacs Lisp manual for more information." - `(eval-and-compile - (custom-declare-variable (quote ,symbol) (quote ,value) ,doc ,@args))) + ;; 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-variable + (list 'quote symbol) + (list 'quote value) + doc) + args)) ;;; The `defface' Macro. @@ -126,28 +217,33 @@ The remaining arguments should have the form [KEYWORD VALUE]... -The following KEYWORD's are defined: +The following KEYWORDs are defined: :group VALUE should be a customization group. Add FACE to that group. SPEC should be an alist of the form ((DISPLAY ATTS)...). -ATTS is a list of face attributes and their values. The possible -attributes are defined in the variable `custom-face-attributes'. -Alternatively, ATTS can be a face in which case the attributes of that -face is used. +The first element of SPEC where the DISPLAY matches the frame +is the one that takes effect in that frame. The ATTRs in this +element take effect; the other elements are ignored, on that frame. + +ATTS is a list of face attributes followed by their values: + (ATTR VALUE ATTR VALUE...) -The ATTS of the first entry in SPEC where the DISPLAY matches the -frame should take effect in that frame. DISPLAY can either be the -symbol t, which will match all frames, or an alist of the form -\((REQ ITEM...)...) +The possible attributes are `:family', `:width', `:height', `:weight', +`:slant', `:underline', `:overline', `:strike-through', `:box', +`:foreground', `:background', `:stipple', and `:inverse-video'. -For the DISPLAY to match a FRAME, the REQ property of the frame must -match one of the ITEM. The following REQ are defined: +DISPLAY can either be the symbol t, which will match all frames, or an +alist of the form \((REQ ITEM...)...). For the DISPLAY to match a +FRAME, the REQ property of the frame must match one of the ITEM. The +following REQ are defined: `type' (the value of `window-system') - Should be one of `x' or `tty'. + Under X, in addition to the values `window-system' can take, + `motif', `lucid' and `x-toolkit' are allowed, and match when + the Motif toolkit, Lucid toolkit, or any X toolkit is in use. `class' (the frame's color support) Should be one of `color', `grayscale', or `mono'. @@ -157,16 +253,23 @@ match one of the ITEM. The following REQ are defined: Read the section about customization in the Emacs Lisp manual for more information." - `(custom-declare-face (quote ,face) ,spec ,doc ,@args)) + ;; 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-face (list 'quote face) spec doc) args)) ;;; The `defgroup' Macro. (defun custom-declare-group (symbol members doc &rest args) "Like `defgroup', but SYMBOL is evaluated as a normal argument." + (while members + (apply 'custom-add-to-group symbol (car members)) + (setq members (cdr members))) (put symbol 'custom-group (nconc members (get symbol 'custom-group))) (when doc - (put symbol 'group-documentation doc)) - (while args + ;; This text doesn't get into DOC. + (put symbol 'group-documentation (purecopy doc))) + (while args (let ((arg (car args))) (setq args (cdr args)) (unless (symbolp arg) @@ -191,22 +294,28 @@ SYMBOL does not need to be quoted. Third arg DOC is the group documentation. MEMBERS should be an alist of the form ((NAME WIDGET)...) where -NAME is a symbol and WIDGET is a widget is a widget for editing that -symbol. Useful widgets are `custom-variable' for editing variables, +NAME is a symbol and WIDGET is a widget for editing that symbol. +Useful widgets are `custom-variable' for editing variables, `custom-face' for edit faces, and `custom-group' for editing groups. The remaining arguments should have the form - [KEYWORD VALUE]... + [KEYWORD VALUE]... -The following KEYWORD's are defined: +The following KEYWORDs are defined: -:group VALUE should be a customization group. - Add SYMBOL to that group. +:group VALUE should be a customization group. + Add SYMBOL to that group. + +:version VALUE should be a string specifying that the group was introduced + in Emacs version VERSION. Read the section about customization in the Emacs Lisp manual for more information." - `(custom-declare-group (quote ,symbol) ,members ,doc ,@args)) + ;; 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-group (list 'quote symbol) members doc) args)) (defun custom-add-to-group (group option widget) "To existing GROUP add a new OPTION of type WIDGET. @@ -222,7 +331,7 @@ If there already is an entry for that option, overwrite it." (defun custom-handle-all-keywords (symbol args type) "For customization option SYMBOL, handle keyword arguments ARGS. Third argument TYPE is the custom option type." - (while args + (while args (let ((arg (car args))) (setq args (cdr args)) (unless (symbolp arg) @@ -232,22 +341,47 @@ Third argument TYPE is the custom option type." (unless args (error "Keyword %s is missing an argument" keyword)) (setq args (cdr args)) - (custom-handle-keyword symbol keyword value type))))) + (custom-handle-keyword symbol keyword value type))))) (defun custom-handle-keyword (symbol keyword value type) "For customization option SYMBOL, handle KEYWORD with VALUE. Fourth argument TYPE is the custom option type." + (if purify-flag + (setq value (purecopy value))) (cond ((eq keyword :group) (custom-add-to-group value symbol type)) + ((eq keyword :version) + (custom-add-version symbol value)) ((eq keyword :link) (custom-add-link symbol value)) ((eq keyword :load) (custom-add-load symbol value)) ((eq keyword :tag) (put symbol 'custom-tag value)) + ((eq keyword :set-after) + (custom-add-dependencies symbol value)) (t - (error "Unknown keyword %s" symbol)))) - + (error "Unknown keyword %s" keyword)))) + +(defun custom-add-dependencies (symbol value) + "To the custom option SYMBOL, add dependencies specified by VALUE. +VALUE should be a list of symbols. For each symbol in that list, +this specifies that SYMBOL should be set after the specified symbol, if +both appear in constructs like `custom-set-variables'." + (unless (listp value) + (error "Invalid custom dependency `%s'" value)) + (let* ((deps (get symbol 'custom-dependencies)) + (new-deps deps)) + (while value + (let ((dep (car value))) + (unless (symbolp dep) + (error "Invalid custom dependency `%s'" dep)) + (unless (memq dep new-deps) + (setq new-deps (cons dep new-deps))) + (setq value (cdr value)))) + (unless (eq deps new-deps) + (put symbol 'custom-dependencies new-deps)))) + (defun custom-add-option (symbol option) "To the variable SYMBOL add OPTION. @@ -261,42 +395,82 @@ For other types variables, the effect is undefined." "To the custom option SYMBOL add the link WIDGET." (let ((links (get symbol 'custom-links))) (unless (member widget links) - (put symbol 'custom-links (cons widget links))))) + (put symbol 'custom-links (cons (purecopy widget) links))))) + +(defun custom-add-version (symbol version) + "To the custom option SYMBOL add the version VERSION." + (put symbol 'custom-version (purecopy version))) (defun custom-add-load (symbol load) "To the custom option SYMBOL add the dependency LOAD. LOAD should be either a library file name, or a feature name." (let ((loads (get symbol 'custom-loads))) (unless (member load loads) - (put symbol 'custom-loads (cons load loads))))) + (put symbol 'custom-loads (cons (purecopy load) loads))))) ;;; Initializing. +(defvar custom-local-buffer nil + "Non-nil, in a Customization buffer, means customize a specific buffer. +If this variable is non-nil, it should be a buffer, +and it means customize the local bindings of that buffer. +This variable is a permanent local, and it normally has a local binding +in every Customization buffer.") +(put 'custom-local-buffer 'permanent-local t) + (defun custom-set-variables (&rest args) - "Initialize variables according to user preferences. + "Initialize variables according to user preferences. The arguments should be a list where each entry has the form: - (SYMBOL VALUE [NOW]) + (SYMBOL VALUE [NOW [REQUEST [COMMENT]]]) The unevaluated VALUE is stored as the saved value for SYMBOL. If NOW is present and non-nil, VALUE is also evaluated and bound as -the default value for the SYMBOL." - (while args +the default value for the SYMBOL. +REQUEST is a list of features we must require for SYMBOL. +COMMENT is a comment string about SYMBOL." + (setq args + (sort args + (lambda (a1 a2) + (let* ((sym1 (car a1)) + (sym2 (car a2)) + (1-then-2 (memq sym1 (get sym2 'custom-dependencies))) + (2-then-1 (memq sym2 (get sym1 'custom-dependencies)))) + (cond ((and 1-then-2 2-then-1) + (error "Circular custom dependency between `%s' and `%s'" + sym1 sym2)) + (2-then-1 nil) + (t t)))))) + (while args (let ((entry (car args))) (if (listp entry) - (let ((symbol (nth 0 entry)) - (value (nth 1 entry)) - (now (nth 2 entry))) + (let* ((symbol (nth 0 entry)) + (value (nth 1 entry)) + (now (nth 2 entry)) + (requests (nth 3 entry)) + (comment (nth 4 entry)) + set) + (when requests + (put symbol 'custom-requests requests) + (mapcar 'require requests)) + (setq set (or (get symbol 'custom-set) 'custom-set-default)) (put symbol 'saved-value (list value)) - (cond (now - ;; Rogue variable, set it now. - (put symbol 'force-value t) - (set-default symbol (eval value))) - ((default-boundp symbol) - ;; Something already set this, overwrite it. - (set-default symbol (eval value)))) - (setq args (cdr args))) + (put symbol 'saved-variable-comment comment) + ;; Allow for errors in the case where the setter has + ;; changed between versions, say. + (condition-case nil + (cond (now + ;; Rogue variable, set it now. + (put symbol 'force-value t) + (funcall set symbol (eval value))) + ((default-boundp symbol) + ;; Something already set this, overwrite it. + (funcall set symbol (eval value)))) + (error nil)) + (setq args (cdr args)) + (and (or now (default-boundp symbol)) + (put symbol 'variable-comment comment))) ;; Old format, a plist of SYMBOL VALUE pairs. (message "Warning: old format `custom-set-variables'") (ding) @@ -306,8 +480,23 @@ the default value for the SYMBOL." (put symbol 'saved-value (list value))) (setq args (cdr (cdr args))))))) +(defun custom-set-default (variable value) + "Default :set function for a customizable variable. +Normally, this sets the default value of VARIABLE to VALUE, +but if `custom-local-buffer' is non-nil, +this sets the local binding in that buffer instead." + (if custom-local-buffer + (with-current-buffer custom-local-buffer + (set variable value)) + (set-default variable value))) + ;;; The End. +;; Process the defcustoms for variables loaded before this file. +(while custom-declare-variable-list + (apply 'custom-declare-variable (car custom-declare-variable-list)) + (setq custom-declare-variable-list (cdr custom-declare-variable-list))) + (provide 'custom) -;; custom.el ends here +;;; custom.el ends here