]> code.delx.au - gnu-emacs/blobdiff - lisp/cus-edit.el
(command-line-1): Kill emacs if the last frame is deleted while
[gnu-emacs] / lisp / cus-edit.el
index 763b4b8c57f432b0647ef6fe93501fa44ba6633f..c70284f4455563dd333f3b6ad3e4f2d520eb2412 100644 (file)
   :link '(custom-manual "(emacs)Undo")
   :group 'editing)
 
-(defgroup modeline nil
+(defgroup mode-line nil
   "Content of the modeline."
   :group 'environment)
 
 
 ;;; Utilities.
 
-(defun custom-quote (sexp)
-  "Quote SEXP iff it is not self quoting."
-  (if (or (memq sexp '(t nil))
-         (keywordp sexp)
-         (and (listp sexp)
-              (memq (car sexp) '(lambda)))
-         (stringp sexp)
-         (numberp sexp)
-         (vectorp sexp)
-;;;      (and (fboundp 'characterp)
-;;;           (characterp sexp))
-         )
-      sexp
-    (list 'quote sexp)))
-
 (defun custom-split-regexp-maybe (regexp)
   "If REGEXP is a string, split it to a list at `\\|'.
 You can get the original back with from the result with:
@@ -536,7 +521,7 @@ WIDGET is the widget to apply the filter entries of MENU on."
   "List of prefixes that should be ignored by `custom-unlispify'.")
 
 (defcustom custom-unlispify-menu-entries t
-  "Display menu entries as words instead of symbols if non nil."
+  "Display menu entries as words instead of symbols if non-nil."
   :group 'custom-menu
   :type 'boolean)
 
@@ -583,7 +568,7 @@ WIDGET is the widget to apply the filter entries of MENU on."
           (buffer-string)))))
 
 (defcustom custom-unlispify-tag-names t
-  "Display tag names as words instead of symbols if non nil."
+  "Display tag names as words instead of symbols if non-nil."
   :group 'custom-buffer
   :type 'boolean)
 
@@ -602,6 +587,7 @@ WIDGET is the widget to apply the filter entries of MENU on."
 
 (defcustom custom-guess-name-alist
   '(("-p\\'" boolean)
+    ("-flag\\'" boolean)
     ("-hook\\'" hook)
     ("-face\\'" face)
     ("-file\\'" file)
@@ -801,7 +787,7 @@ when the action is chosen.")
     (if (or (and (= 1 (length children))
                 (memq (widget-type (car children))
                       '(custom-variable custom-face)))
-           (y-or-n-p "Reset all settings' buffer text to show current values?  "))
+           (y-or-n-p "Reset all settings' buffer text to show current values? "))
        (mapc (lambda (widget)
                (if (memq (widget-get widget :custom-state)
                          '(modified changed))
@@ -860,7 +846,7 @@ it were the arg to `interactive' (which see) to interactively read the value.
 If the variable has a `custom-type' property, it must be a widget and the
 `:prompt-value' property of that widget will be used for reading the value.
 
-If optional COMMENT argument is non nil, also prompt for a comment and return
+If optional COMMENT argument is non-nil, also prompt for a comment and return
 it as the third element in the list."
   (let* ((var (read-variable prompt-var))
         (minibuffer-help-form '(describe-variable var))
@@ -932,6 +918,7 @@ If given a prefix (or a COMMENT argument), also prompt for a comment."
                                       "Set customized value for %s to: "
                                       current-prefix-arg))
   (custom-load-symbol variable)
+  (custom-push-theme 'theme-value variable 'user 'set (custom-quote value))
   (funcall (or (get variable 'custom-set) 'set-default) variable value)
   (put variable 'customized-value (list (custom-quote value)))
   (cond ((string= comment "")
@@ -1068,6 +1055,8 @@ then prompt for the MODE to customize."
 (defun customize-option (symbol)
   "Customize SYMBOL, which must be a user option variable."
   (interactive (custom-variable-prompt))
+  (unless symbol
+    (error "No variable specified"))
   (let ((basevar (indirect-variable symbol)))
     (custom-buffer-create (list (list basevar 'custom-variable))
                          (format "*Customize Option: %s*"
@@ -1083,6 +1072,8 @@ then prompt for the MODE to customize."
   "Customize SYMBOL, which must be a user option variable.
 Show the buffer in another window, but don't select it."
   (interactive (custom-variable-prompt))
+  (unless symbol
+    (error "No variable specified"))
   (let ((basevar (indirect-variable symbol)))
     (custom-buffer-create-other-window
      (list (list basevar 'custom-variable))
@@ -1093,6 +1084,39 @@ Show the buffer in another window, but don't select it."
 (defvar customize-changed-options-previous-release "21.1"
   "Version for `customize-changed-options' to refer back to by default.")
 
+;; Packages will update this variable, so make it available.
+;;;###autoload
+(defvar customize-package-emacs-version-alist nil
+  "Alist mapping versions of a package to Emacs versions.
+We use this for packages that have their own names, but are released
+as part of Emacs itself.
+
+Each elements looks like this:
+
+     (PACKAGE (PVERSION . EVERSION)...)
+
+Here PACKAGE is the name of a package, as a symbol.  After
+PACKAGE come one or more elements, each associating a
+package version PVERSION with the first Emacs version
+EVERSION in which it (or a subsequent version of PACKAGE)
+was first released.  Both PVERSION and EVERSION are strings.
+PVERSION should be a string that this package used in
+the :package-version keyword for `defcustom', `defgroup',
+and `defface'.
+
+For example, the MH-E package updates this alist as follows:
+
+     (add-to-list 'customize-package-emacs-version-alist
+                  '(MH-E (\"6.0\" . \"22.1\") (\"6.1\" . \"22.1\")
+                         (\"7.0\" . \"22.1\") (\"7.1\" . \"22.1\")
+                         (\"7.2\" . \"22.1\") (\"7.3\" . \"22.1\")
+                         (\"7.4\" . \"22.1\") (\"8.0\" . \"22.1\")))
+
+The value of PACKAGE needs to be unique and it needs to match the
+PACKAGE value appearing in the :package-version keyword.  Since
+the user might see the value in a error message, a good choice is
+the official name of the package, such as MH-E or Gnus.")
+
 ;;;###autoload
 (defalias 'customize-changed 'customize-changed-options)
 
@@ -1106,7 +1130,11 @@ or default values have changed since the previous major Emacs release.
 With argument SINCE-VERSION (a string), customize all settings
 that were added or redefined since that version."
 
-  (interactive "sCustomize options changed, since version (default all versions): ")
+  (interactive
+   (list
+    (read-from-minibuffer
+     (format "Customize options changed, since version (default %s): "
+            customize-changed-options-previous-release))))
   (if (equal since-version "")
       (setq since-version nil)
     (unless (condition-case nil
@@ -1129,7 +1157,12 @@ that were added or redefined since that version."
   (let (found)
     (mapatoms
      (lambda (symbol)
-       (let ((version (get symbol 'custom-version)))
+        (let* ((package-version (get symbol 'custom-package-version))
+               (version
+                (or (and package-version
+                         (customize-package-emacs-version symbol
+                                                          package-version))
+                    (get symbol 'custom-version))))
         (if version
             (when (customize-version-lessp since-version version)
               (if (or (get symbol 'custom-group)
@@ -1145,6 +1178,31 @@ that were added or redefined since that version."
       (error "No user option defaults have been changed since Emacs %s"
             since-version))))
 
+(defun customize-package-emacs-version (symbol package-version)
+  "Return the Emacs version in which SYMBOL's meaning last changed.
+PACKAGE-VERSION has the form (PACKAGE . VERSION).  We use
+`customize-package-emacs-version-alist' to find the version of
+Emacs that is associated with version VERSION of PACKAGE."
+  (let (package-versions emacs-version)
+    ;; Use message instead of error since we want user to be able to
+    ;; see the rest of the symbols even if a package author has
+    ;; botched things up.
+    (cond ((not (listp package-version))
+           (message "Invalid package-version value for %s" symbol))
+          ((setq package-versions (assq (car package-version)
+                                        customize-package-emacs-version-alist))
+           (setq emacs-version
+                 (cdr (assoc (cdr package-version) package-versions)))
+           (unless emacs-version
+             (message "%s version %s not found in %s" symbol
+                      (cdr package-version)
+                      "customize-package-emacs-version-alist")))
+          (t
+           (message "Package %s version %s lists no corresponding Emacs version"
+                    (car package-version)
+                    (cdr package-version))))
+    emacs-version))
+
 (defun customize-version-lessp (version1 version2)
   ;; Why are the versions strings, and given that they are, why aren't
   ;; they converted to numbers and compared as such here?  -- fx
@@ -1313,10 +1371,10 @@ that are not customizable options, as well as faces and groups
                                      (get symbol 'variable-documentation))))
                    (push (list symbol 'custom-variable) found)))))
     (if (not found)
-       (error "No matches")
-      (custom-buffer-create (custom-sort-items found t
-                                              custom-buffer-order-groups)
-                           "*Customize Apropos*"))))
+       (error "No customizable items matching %s" regexp)
+      (custom-buffer-create
+       (custom-sort-items found t custom-buffer-order-groups)
+       "*Customize Apropos*"))))
 
 ;;;###autoload
 (defun customize-apropos-options (regexp &optional arg)
@@ -1463,13 +1521,18 @@ Otherwise use brackets."
            (widget-insert description))
        (widget-insert (format ".
 %s buttons; type RET or click mouse-1 to actuate one.
-Editing a setting changes only the text in the buffer.
-Use the setting's State button to set it or save changes in it.
-Saving a change normally works by editing your Emacs init file.
-See "
+Editing a setting changes only the text in the buffer."
                               (if custom-raised-buttons
                                   "`Raised' text indicates"
                                 "Square brackets indicate")))
+       (if init-file-user
+           (widget-insert "
+Use the setting's State button to set it or save changes in it.
+Saving a change normally works by editing your Emacs init file.")
+           (widget-insert "
+\nSince you started Emacs with `-q', which inhibits use of the
+Emacs init file, you cannot save settings into the Emacs init file."))
+       (widget-insert "\nSee ")
        (widget-create 'custom-manual
                       :tag "Custom file"
                       "(emacs)Saving Customizations")
@@ -1720,6 +1783,7 @@ item in another window.\n\n"))
   :help-echo "Read the manual entry for this option."
   :button-face 'custom-link
   :mouse-face 'highlight
+  :pressed-face 'highlight
   :tag "Manual")
 
 ;;; The `custom-magic' Widget.
@@ -2040,7 +2104,7 @@ and `face'."
       'custom-button-pressed
     'custom-button-pressed-unraised))
 
-(defface custom-documentation nil
+(defface custom-documentation '((t nil))
   "Face used for documentation strings in customization buffers."
   :group 'custom-faces)
 ;; backward-compatibility alias
@@ -2201,7 +2265,8 @@ Insert PREFIX first if non-nil."
        (push (widget-create-child-and-convert
               widget (car links)
               :button-face 'custom-link
-              :mouse-face 'highlight)
+              :mouse-face 'highlight
+              :pressed-face 'highlight)
              buttons)
        (setq links (cdr links))
        (cond ((null links)
@@ -2247,7 +2312,8 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
                (push (widget-create-child-and-convert
                      widget (car links)
                      :button-face 'custom-link
-                     :mouse-face 'highlight)
+                     :mouse-face 'highlight
+                     :pressed-face 'highlight)
                      buttons)
                (setq links (cdr links))
                (cond ((null links)
@@ -2612,7 +2678,18 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
                             (error nil))
                           (cond
                            ((eq (caar tmp) 'user) 'saved)
-                           ((eq (caar tmp) 'changed) 'changed)
+                           ((eq (caar tmp) 'changed)
+                             (if (condition-case nil
+                                     (and (null comment)
+                                          (equal value
+                                                 (eval
+                                                  (car (get symbol 'standard-value)))))
+                                   (error nil))
+                                 ;; The value was originally set outside
+                                 ;; custom, but it was set to the standard
+                                 ;; value (probably an autoloaded defcustom).
+                                 'standard
+                               'changed))
                            (t 'themed))
                         'changed))
                      ((setq tmp (get symbol 'standard-value))
@@ -3419,12 +3496,12 @@ Optional EVENT is the location for the menu."
       ;; Make the comment invisible by hand if it's empty
       (custom-comment-hide comment-widget))
     (put symbol 'customized-face value)
+    (custom-push-theme 'theme-face symbol 'user 'set value)
     (if (face-spec-choose value)
        (face-spec-set symbol value)
       ;; face-set-spec ignores empty attribute lists, so just give it
       ;; something harmless instead.
       (face-spec-set symbol '((t :foreground unspecified))))
-    (custom-push-theme 'theme-face symbol 'user 'set value)
     (put symbol 'customized-face-comment comment)
     (put symbol 'face-comment comment)
     (custom-face-state-set widget)
@@ -3497,13 +3574,17 @@ restoring it to the state of a face that has never been customized."
     (put symbol 'customized-face nil)
     (put symbol 'customized-face-comment nil)
     (custom-push-theme 'theme-face symbol 'user 'reset)
+    (face-spec-set symbol value)
     (custom-theme-recalc-face symbol)
     (when (or (get symbol 'saved-face) (get symbol 'saved-face-comment))
       (put symbol 'saved-face nil)
       (put symbol 'saved-face-comment nil)
       (custom-save-all))
     (put symbol 'face-comment nil)
-    (widget-value-set child value)
+    (widget-value-set child
+                     (custom-pre-filter-face-spec
+                      (list (list t (custom-face-attributes-get
+                                     symbol nil)))))
     ;; This call manages the comment visibility
     (widget-value-set comment-widget "")
     (custom-face-state-set widget)
@@ -3590,6 +3671,7 @@ restoring it to the state of a face that has never been customized."
   "Show parent in other window when activated."
   :button-face 'custom-link
   :mouse-face 'highlight
+  :pressed-face 'highlight
   :help-echo "Create customization buffer for this group."
   :action 'custom-group-link-action)
 
@@ -4067,6 +4149,8 @@ if only the first line of the docstring is shown."))
 ;;;###autoload
 (defun custom-save-all ()
   "Save all customizations in `custom-file'."
+  (when (and (null custom-file) init-file-had-error)
+    (error "Cannot save customizations; init file was not fully loaded"))
   (let* ((filename (custom-file))
         (recentf-exclude (if recentf-mode
                              (cons (concat "\\`"
@@ -4075,6 +4159,8 @@ if only the first line of the docstring is shown."))
                                    recentf-exclude)))
         (old-buffer (find-buffer-visiting filename)))
     (with-current-buffer (or old-buffer (find-file-noselect filename))
+      (unless (eq major-mode 'emacs-lisp-mode)
+       (emacs-lisp-mode))
       (let ((inhibit-read-only t))
        (custom-save-variables)
        (custom-save-faces))
@@ -4162,7 +4248,9 @@ This function does not save the buffer."
       (mapatoms
        (lambda (symbol)
         (if (and (get symbol 'saved-value)
-                 (eq 'user (car (car-safe (get symbol 'theme-value)))))
+                 ;; ignore theme values
+                 (or (null (get symbol 'theme-value))
+                     (eq 'user (caar (get symbol 'theme-value)))))
             (nconc saved-list (list symbol)))))
       (setq saved-list (sort (cdr saved-list) 'string<))
       (unless (bolp)
@@ -4176,19 +4264,31 @@ This function does not save the buffer."
        (let ((spec (car-safe (get symbol 'theme-value)))
              (value (get symbol 'saved-value))
              (requests (get symbol 'custom-requests))
-             (now (not (or (custom-variable-p symbol)
-                           (and (not (boundp symbol))
-                                (not (eq (get symbol 'force-value)
-                                         'rogue))))))
+             (now (and (not (custom-variable-p symbol))
+                       (or (boundp symbol)
+                           (eq (get symbol 'force-value)
+                               'rogue))))
              (comment (get symbol 'saved-variable-comment)))
-         ;; Check `requests'.
+         ;; Check REQUESTS for validity. 
          (dolist (request requests)
            (when (and (symbolp request) (not (featurep request)))
              (message "Unknown requested feature: %s" request)
              (setq requests (delq request requests))))
+         ;; Is there anything customized about this variable?
          (when (or (and spec (eq (car spec) 'user))
                    comment
                    (and (null spec) (get symbol 'saved-value)))
+           ;; Output an element for this variable.
+           ;; It has the form (SYMBOL VALUE-FORM NOW REQUESTS COMMENT).
+           ;; SYMBOL is the variable name.
+           ;; VALUE-FORM is an expression to return the customized value.
+           ;; NOW if non-nil means always set the variable immediately
+           ;; when the customizations are reloaded.  This is used
+           ;; for rogue variables
+           ;; REQUESTS is a list of packages to load before setting the
+           ;; variable.  Each element of it will be passed to `require'.
+           ;; COMMENT is whatever comment the user has specified
+           ;; with the customize facility.
            (unless (bolp)
              (princ "\n"))
            (princ " '(")
@@ -4304,14 +4404,15 @@ This function does not save the buffer."
   "Ignoring WIDGET, create a menu entry for customization group SYMBOL."
   `( ,(custom-unlispify-menu-entry symbol t)
      :filter (lambda (&rest junk)
-              (let ((menu (custom-menu-create ',symbol)))
+              (let* ((menu (custom-menu-create ',symbol)))
                 (if (consp menu) (cdr menu) menu)))))
 
 ;;;###autoload
 (defun custom-menu-create (symbol)
   "Create menu for customization group SYMBOL.
 The menu is in a format applicable to `easy-menu-define'."
-  (let* ((item (vector (custom-unlispify-menu-entry symbol)
+  (let* ((deactivate-mark nil)
+        (item (vector (custom-unlispify-menu-entry symbol)
                       `(customize-group ',symbol)
                       t)))
     (if (and (or (not (boundp 'custom-menu-nesting))
@@ -4356,7 +4457,8 @@ The format is suitable for use with `easy-menu-define'."
   ;; Actually, this misfeature of dense keymaps was fixed on 2001-11-26.
   (let ((map (make-keymap)))
     (set-keymap-parent map widget-keymap)
-    (suppress-keymap map)
+    (define-key map [remap self-insert-command] 'Custom-no-edit)
+    (define-key map "\^m" 'Custom-newline)
     (define-key map " " 'scroll-up)
     (define-key map "\177" 'scroll-down)
     (define-key map "\C-c\C-c" 'Custom-set)
@@ -4365,10 +4467,22 @@ The format is suitable for use with `easy-menu-define'."
     (define-key map "u" 'Custom-goto-parent)
     (define-key map "n" 'widget-forward)
     (define-key map "p" 'widget-backward)
-    (define-key map [mouse-1] 'widget-move-and-invoke)
     map)
   "Keymap for `custom-mode'.")
 
+(defun Custom-no-edit (pos &optional event)
+  "Invoke button at POS, or refuse to allow editing of Custom buffer."
+  (interactive "@d")
+  (error "You can't edit this part of the Custom buffer"))
+
+(defun Custom-newline (pos &optional event)
+  "Invoke button at POS, or refuse to allow editing of Custom buffer."
+  (interactive "@d")
+  (let ((button (get-char-property pos 'button)))
+    (if button
+       (widget-apply-action button event)
+      (error "You can't edit this part of the Custom buffer"))))
+
 (easy-menu-define Custom-mode-menu
     custom-mode-map
   "Menu used in customization buffers."
@@ -4421,7 +4535,7 @@ Move to previous button, link or editable field. \\[advertised-widget-backward]
 \\<custom-field-keymap>\
 Complete content of editable text field.   \\[widget-complete]
 \\<custom-mode-map>\
-Invoke button under the mouse pointer.     \\[widget-move-and-invoke]
+Invoke button under the mouse pointer.     \\[widget-button-click]
 Invoke button under point.                 \\[widget-button-press]
 Set all options from current text.         \\[Custom-set]
 Make values in current text permanent.     \\[Custom-save]
@@ -4443,6 +4557,13 @@ if that value is non-nil."
   (setq widget-documentation-face 'custom-documentation)
   (make-local-variable 'widget-button-face)
   (setq widget-button-face custom-button)
+
+  ;; We need this because of the "More" button on docstrings.
+  ;; Otherwise clicking on "More" can push point offscreen, which
+  ;; causes the window to recenter on point, which pushes the
+  ;; newly-revealed docstring offscreen; which is annoying.  -- cyd.
+  (set (make-local-variable 'widget-button-click-moves-point) t)
+
   (set (make-local-variable 'widget-button-pressed-face) custom-button-pressed)
   (set (make-local-variable 'widget-mouse-face) custom-button-mouse)
 
@@ -4458,9 +4579,18 @@ if that value is non-nil."
 
 (put 'custom-mode 'mode-class 'special)
 
-(add-to-list
- 'debug-ignored-errors
- "^No user options have changed defaults in recent Emacs versions$")
+(dolist (regexp
+        '("^No user option defaults have been changed since Emacs "
+          "^Invalid face:? "
+          "^No \\(?:customized\\|rogue\\|saved\\) user options"
+          "^No customizable items matching "
+          "^There are unset changes"
+          "^Cannot set hidden variable"
+          "^No \\(?:saved\\|backup\\) value for "
+          "^No standard setting known for "
+          "^No standard setting for this face"
+          "^Saving settings from \"emacs -q\" would overwrite existing customizations"))
+  (add-to-list 'debug-ignored-errors regexp))
 
 ;;; The End.