(tex-command-end): New variable.
[bpt/emacs.git] / lisp / cus-edit.el
index 3433b03..1854512 100644 (file)
@@ -1,10 +1,10 @@
-;;; cus-edit.el --- Tools for customization Emacs.
+;;; cus-edit.el --- Tools for customizating Emacs and Lisp packages.
 ;;
 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Keywords: help, faces
-;; Version: 1.9936
+;; Version: 1.9954
 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
 
 ;; This file is part of GNU Emacs.
   :group 'external
   :group 'development)
 
+(defgroup convenience nil
+  "Convenience features for faster editing."
+  :group 'emacs)
+
 (defgroup programming nil
   "Support for programming in other languages."
   :group 'emacs)
@@ -408,7 +412,7 @@ Return a list suitable for use in `interactive'."
                obarray (lambda (symbol)
                          (and (boundp symbol)
                               (or (get symbol 'custom-type)
-                                  (user-variable-p symbol))))))
+                                  (user-variable-p symbol)))) t))
      (list (if (equal val "")
               (if (symbolp v) v nil)
             (intern val)))))
@@ -440,6 +444,11 @@ WIDGET is the widget to apply the filter entries of MENU on."
   :group 'custom-menu
   :type 'boolean)
 
+(defcustom custom-unlispify-remove-prefixes nil
+  "Non-nil means remove group prefixes from option names in buffer."
+  :group 'custom-menu
+  :type 'boolean)
+
 (defun custom-unlispify-menu-entry (symbol &optional no-suffix)
   "Convert symbol into a menu entry."
   (cond ((not custom-unlispify-menu-entries)
@@ -458,15 +467,16 @@ WIDGET is the widget to apply the filter entries of MENU on."
                      (re-search-forward "-p\\'" nil t))
             (replace-match "" t t)
             (goto-char (point-min)))
-          (let ((prefixes custom-prefix-list)
-                prefix)
-            (while prefixes
-              (setq prefix (car prefixes))
-              (if (search-forward prefix (+ (point) (length prefix)) t)
-                  (progn 
-                    (setq prefixes nil)
-                    (delete-region (point-min) (point)))
-                (setq prefixes (cdr prefixes)))))
+          (if custom-unlispify-remove-prefixes
+              (let ((prefixes custom-prefix-list)
+                    prefix)
+                (while prefixes
+                  (setq prefix (car prefixes))
+                  (if (search-forward prefix (+ (point) (length prefix)) t)
+                      (progn 
+                        (setq prefixes nil)
+                        (delete-region (point-min) (point)))
+                    (setq prefixes (cdr prefixes))))))
           (subst-char-in-region (point-min) (point-max) ?- ?\  t)
           (capitalize-region (point-min) (point-max))
           (unless no-suffix 
@@ -568,6 +578,11 @@ If `last', order groups after non-groups."
                 (const :tag "none" nil))
   :group 'custom-browse)
 
+(defcustom custom-browse-only-groups nil
+  "If non-nil, show group members only within each customization group."
+  :type 'boolean
+  :group 'custom-browse)
+
 (defcustom custom-buffer-sort-alphabetically nil
   "If non-nil, sort members of each customization group alphabetically."
   :type 'boolean
@@ -762,6 +777,26 @@ If VARIABLE has a `custom-type' property, it must be a widget and the
   (funcall (or (get var 'custom-set) 'set-default) var val)
   (put var 'customized-value (list (custom-quote val))))
 
+;;;###autoload
+(defun customize-save-variable (var val)
+  "Set the default for VARIABLE to VALUE, and save it for future sessions.
+If VARIABLE has a `custom-set' property, that is used for setting
+VARIABLE, otherwise `set-default' is used.
+
+The `customized-value' property of the VARIABLE will be set to a list
+with a quoted VALUE as its sole list member.
+
+If VARIABLE has a `variable-interactive' property, that is used as if
+it were the arg to `interactive' (which see) to interactively read the value.
+
+If 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. " 
+  (interactive (custom-prompt-variable "Set and ave variable: "
+                                      "Set and save value for %s as: "))
+  (funcall (or (get var 'custom-set) 'set-default) var val)
+  (put var 'saved-value (list (custom-quote val)))
+  (custom-save-all))
+
 ;;;###autoload
 (defun customize ()
   "Select a customization buffer which you can use to set user options.
@@ -778,36 +813,51 @@ are shown; the contents of those subgroups are initially hidden."
                       (completing-read "Customize group: (default emacs) "
                                        obarray 
                                        (lambda (symbol)
-                                         (get symbol 'custom-group))
+                                         (or (get symbol 'custom-loads)
+                                             (get symbol 'custom-group)))
                                        t))))
-
   (when (stringp group)
     (if (string-equal "" group)
        (setq group 'emacs)
       (setq group (intern group))))
+  (or (get group 'custom-group)
+      (custom-load-symbol group))
   (let ((name (format "*Customize Group: %s*"
                      (custom-unlispify-tag-name group))))
     (if (get-buffer name)
        (switch-to-buffer name)
       (custom-buffer-create (list (list group 'custom-group))
-                           name))))
+                           name
+                           (concat " for group "
+                                   (custom-unlispify-tag-name group))))))
 
 ;;;###autoload
-(defun customize-group-other-window (symbol)
-  "Customize SYMBOL, which must be a customization group."
-  (interactive (list (completing-read "Customize group: (default emacs) "
-                                     obarray 
-                                     (lambda (symbol)
-                                       (get symbol 'custom-group))
-                                     t)))
-
-  (when (stringp symbol)
-    (if (string-equal "" symbol)
-       (setq symbol 'emacs)
-      (setq symbol (intern symbol))))
-  (custom-buffer-create-other-window
-   (list (list symbol 'custom-group))
-   (format "*Customize Group: %s*" (custom-unlispify-tag-name symbol))))
+(defun customize-group-other-window (group)
+  "Customize GROUP, which must be a customization group."
+  (interactive (list (let ((completion-ignore-case t))
+                      (completing-read "Customize group: (default emacs) "
+                                       obarray 
+                                       (lambda (symbol)
+                                         (or (get symbol 'custom-loads)
+                                             (get symbol 'custom-group)))
+                                       t))))
+  (when (stringp group)
+    (if (string-equal "" group)
+       (setq group 'emacs)
+      (setq group (intern group))))
+  (or (get group 'custom-group)
+      (custom-load-symbol group))
+  (let ((name (format "*Customize Group: %s*"
+                     (custom-unlispify-tag-name group))))
+    (if (get-buffer name)
+       (let ((window (selected-window)))
+         (switch-to-buffer-other-window name)
+         (select-window window))
+      (custom-buffer-create-other-window
+       (list (list group 'custom-group))
+       name
+       (concat " for group "
+              (custom-unlispify-tag-name group))))))
 
 ;;;###autoload
 (defalias 'customize-variable 'customize-option)
@@ -820,6 +870,49 @@ are shown; the contents of those subgroups are initially hidden."
                        (format "*Customize Option: %s*"
                                (custom-unlispify-tag-name symbol))))
 
+;;;###autoload
+(defun customize-changed-options (since-version)
+  "Customize all user option variables whose default values changed recently.
+This means, in other words, variables and groups defined with a `:version' 
+option."
+  (interactive "sCustomize options changed, since version (default all versions): ")
+  (if (equal since-version "")
+      (setq since-version nil))
+  (let ((found nil))
+    (mapatoms (lambda (symbol)
+               (and (or (boundp symbol)
+                        ;; For groups the previous test fails, this one
+                        ;; could be used to determine if symbol is a
+                        ;; group. Is there a better way for this?
+                        (get symbol 'group-documentation))
+                    (let ((version (get symbol 'custom-version)))
+                      (and version
+                           (or (null since-version)
+                               (customize-version-lessp since-version version))))
+                    (setq found
+                          ;; We have to set the right thing here,
+                          ;; depending if we have a group or a
+                          ;; variable. 
+                          (if (get  symbol 'group-documentation)
+                              (cons (list symbol 'custom-group) found)
+                            (cons (list symbol 'custom-variable) found))))))
+    (if (not found)
+       (error "No user options have changed defaults in recent Emacs versions")
+      (custom-buffer-create (custom-sort-items found t nil)
+                           "*Customize Changed Options*"))))
+
+(defun customize-version-lessp (version1 version2)
+  (let (major1 major2 minor1 minor2)
+    (string-match "\\([0-9]+\\)[.]\\([0-9]+\\)" version1)
+    (setq major1 (read (match-string 1 version1)))
+    (setq minor1 (read (match-string 2 version1)))
+    (string-match "\\([0-9]+\\)[.]\\([0-9]+\\)" version2)
+    (setq major2 (read (match-string 1 version2)))
+    (setq minor2 (read (match-string 2 version2)))
+    (or (< major1 major2)
+       (and (= major1 major2)
+            (< minor1 minor2)))))
+  
 ;;;###autoload
 (defalias 'customize-variable-other-window 'customize-option-other-window)
 
@@ -971,7 +1064,7 @@ links: groups have links to subgroups."
   :group 'custom-buffer)
 
 ;;;###autoload
-(defun custom-buffer-create (options &optional name)
+(defun custom-buffer-create (options &optional name description)
   "Create a buffer containing OPTIONS.
 Optional NAME is the name of the buffer.
 OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where
@@ -980,10 +1073,10 @@ that option."
   (unless name (setq name "*Customization*"))
   (kill-buffer (get-buffer-create name))
   (switch-to-buffer (get-buffer-create name))
-  (custom-buffer-create-internal options))
+  (custom-buffer-create-internal options description))
 
 ;;;###autoload
-(defun custom-buffer-create-other-window (options &optional name)
+(defun custom-buffer-create-other-window (options &optional name description)
   "Create a buffer containing OPTIONS.
 Optional NAME is the name of the buffer.
 OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where
@@ -993,7 +1086,7 @@ that option."
   (kill-buffer (get-buffer-create name))
   (let ((window (selected-window)))
     (switch-to-buffer-other-window (get-buffer-create name))
-    (custom-buffer-create-internal options)
+    (custom-buffer-create-internal options description)
     (select-window window)))
 
 (defcustom custom-reset-button-menu nil
@@ -1002,12 +1095,18 @@ This button will have a menu with all three reset operations."
   :type 'boolean
   :group 'custom-buffer)
 
-(defun custom-buffer-create-internal (options)
+(defun custom-buffer-create-internal (options &optional description)
   (message "Creating customization buffer...")
   (custom-mode)
-  (widget-insert "This is a customization buffer.
-Square brackets show active fields; type RET or click mouse-2
-on an active field to invoke its action.  Invoke ")
+  (widget-insert "This is a customization buffer")
+  (if description
+      (widget-insert description))
+  (widget-insert ".
+Square brackets show active fields; type RET or click mouse-1
+on an active field to invoke its action.  Editing an option value
+changes the text in the buffer; invoke the State button and
+choose the Set operation to set the option value.
+Invoke ")
   (widget-create 'info-link 
                 :tag "Help"
                 :help-echo "Read the online help."
@@ -1016,26 +1115,28 @@ on an active field to invoke its action.  Invoke ")
   (message "Creating customization buttons...")
   (widget-insert "Operate on everything in this buffer:\n ")
   (widget-create 'push-button
-                :tag "Set"
+                :tag "Set for Current Session"
                 :help-echo "\
 Make your editing in this buffer take effect for this session."
                 :action (lambda (widget &optional event)
                           (Custom-set)))
   (widget-insert " ")
   (widget-create 'push-button
-                :tag "Save"
+                :tag "Save for Future Sessions"
                 :help-echo "\
 Make your editing in this buffer take effect for future Emacs sessions."
                 :action (lambda (widget &optional event)
                           (Custom-save)))
-  (widget-insert " ")
   (if custom-reset-button-menu
-      (widget-create 'push-button
-                    :tag "Reset"
-                    :help-echo "Show a menu with reset operations."
-                    :mouse-down-action (lambda (&rest junk) t)
-                    :action (lambda (widget &optional event)
-                              (custom-reset event)))
+      (progn
+       (widget-insert " ")
+       (widget-create 'push-button
+                      :tag "Reset"
+                      :help-echo "Show a menu with reset operations."
+                      :mouse-down-action (lambda (&rest junk) t)
+                      :action (lambda (widget &optional event)
+                                (custom-reset event))))
+    (widget-insert "\n ")
     (widget-create 'push-button
                   :tag "Reset"
                   :help-echo "\
@@ -1088,6 +1189,7 @@ Reset all values in this buffer to their standard settings."
                      options))))
   (unless (eq (preceding-char) ?\n)
     (widget-insert "\n"))
+  (message "Creating customization items %2d%%...done" 100)
   (unless (eq custom-buffer-style 'tree)
     (mapcar 'custom-magic-reset custom-options))
   (message "Creating customization setup...")
@@ -1098,27 +1200,39 @@ Reset all values in this buffer to their standard settings."
 ;;; The Tree Browser.
 
 ;;;###autoload
-(defun customize-browse (group)
+(defun customize-browse (&optional group)
   "Create a tree browser for the customize hierarchy."
-  (interactive (list (let ((completion-ignore-case t))
-                      (completing-read "Customize group: (default emacs) "
-                                       obarray 
-                                       (lambda (symbol)
-                                         (get symbol 'custom-group))
-                                       t))))
-
-  (when (stringp group)
-    (if (string-equal "" group)
-       (setq group 'emacs)
-      (setq group (intern group))))
+  (interactive)
+  (unless group
+    (setq group 'emacs))
   (let ((name "*Customize Browser*"))
     (kill-buffer (get-buffer-create name))
     (switch-to-buffer (get-buffer-create name)))
   (custom-mode)
   (widget-insert "\
-Invoke [+] below to expand items, and [-] to collapse items.
-Invoke the [Group], [Face], and [Option] buttons below to edit that
-item in another window.\n\n")
+Square brackets show active fields; type RET or click mouse-1
+on an active field to invoke its action.
+Invoke [+] below to expand a group, and [-] to collapse an expanded group.\n")
+  (if custom-browse-only-groups
+      (widget-insert "\
+Invoke the [Group] button below to edit that item in another window.\n\n")
+    (widget-insert "Invoke the ") 
+    (widget-create 'item 
+                  :format "%t"
+                  :tag "[Group]"
+                  :tag-glyph "folder")
+    (widget-insert ", ")
+    (widget-create 'item 
+                  :format "%t"
+                  :tag "[Face]"
+                  :tag-glyph "face")
+    (widget-insert ", and ")
+    (widget-create 'item 
+                  :format "%t"
+                  :tag "[Option]"
+                  :tag-glyph "option")
+    (widget-insert " buttons below to edit that
+item in another window.\n\n"))
   (let ((custom-buffer-style 'tree))
     (widget-create 'custom-group 
                   :custom-last t
@@ -1127,52 +1241,52 @@ item in another window.\n\n")
                   :value group))
   (goto-char (point-min)))
 
-(define-widget 'custom-tree-visibility 'item
-  "Control visibility of of items in the customize tree browser."
+(define-widget 'custom-browse-visibility 'item
+  "Control visibility of items in the customize tree browser."
   :format "%[[%t]%]"
-  :action 'custom-tree-visibility-action)
+  :action 'custom-browse-visibility-action)
 
-(defun custom-tree-visibility-action (widget &rest ignore)
+(defun custom-browse-visibility-action (widget &rest ignore)
   (let ((custom-buffer-style 'tree))
     (custom-toggle-parent widget)))
 
-(define-widget 'custom-tree-group-tag 'push-button
+(define-widget 'custom-browse-group-tag 'push-button
   "Show parent in other window when activated."
   :tag "Group"
   :tag-glyph "folder"
-  :action 'custom-tree-group-tag-action)
+  :action 'custom-browse-group-tag-action)
 
-(defun custom-tree-group-tag-action (widget &rest ignore)
+(defun custom-browse-group-tag-action (widget &rest ignore)
   (let ((parent (widget-get widget :parent)))
     (customize-group-other-window (widget-value parent))))
 
-(define-widget 'custom-tree-variable-tag 'push-button
+(define-widget 'custom-browse-variable-tag 'push-button
   "Show parent in other window when activated."
   :tag "Option"
   :tag-glyph "option"
-  :action 'custom-tree-variable-tag-action)
+  :action 'custom-browse-variable-tag-action)
 
-(defun custom-tree-variable-tag-action (widget &rest ignore)
+(defun custom-browse-variable-tag-action (widget &rest ignore)
   (let ((parent (widget-get widget :parent)))
     (customize-variable-other-window (widget-value parent))))
 
-(define-widget 'custom-tree-face-tag 'push-button
+(define-widget 'custom-browse-face-tag 'push-button
   "Show parent in other window when activated."
   :tag "Face"
   :tag-glyph "face"
-  :action 'custom-tree-face-tag-action)
+  :action 'custom-browse-face-tag-action)
 
-(defun custom-tree-face-tag-action (widget &rest ignore)
+(defun custom-browse-face-tag-action (widget &rest ignore)
   (let ((parent (widget-get widget :parent)))
     (customize-face-other-window (widget-value parent))))
 
-(defconst custom-tree-alist '(("   " "space")
+(defconst custom-browse-alist '(("   " "space")
                              (" | " "vertical")
                              ("-\\ " "top")
                              (" |-" "middle")
                              (" `-" "bottom")))
 
-(defun custom-tree-insert-prefix (prefix)
+(defun custom-browse-insert-prefix (prefix)
   "Insert PREFIX.  On XEmacs convert it to line graphics."
   (if nil ; (string-match "XEmacs" emacs-version)
       (progn 
@@ -1181,7 +1295,7 @@ item in another window.\n\n")
          (let ((entry (substring prefix 0 3)))
            (setq prefix (substring prefix 3))
            (let ((overlay (make-overlay (1- (point)) (point) nil t nil))
-                 (name (nth 1 (assoc entry custom-tree-alist))))
+                 (name (nth 1 (assoc entry custom-browse-alist))))
              (overlay-put overlay 'end-glyph (widget-glyph-find name entry))
              (overlay-put overlay 'start-open t)
              (overlay-put overlay 'end-open t)))))
@@ -1269,11 +1383,11 @@ group now hidden, invoke \"Show\", above, to show contents.")
                               (invalid "x" custom-invalid-face "\
 the value displayed for this %c is invalid and cannot be set.")
                               (modified "*" custom-modified-face "\
-you have edited the value, and can now set the %c." "\
-you have edited something in this group, and can now set it.")
+you have edited the value as text, but you have not set the %c." "\
+you have edited something in this group, but not set it.")
                               (set "+" custom-set-face "\
-you have set this %c, but not saved it." "\
-something in this group has been set, but not yet saved.")
+you have set this %c, but not saved it for future sessions." "\
+something in this group has been set, but not saved.")
                               (changed ":" custom-changed-face "\
 this %c has been changed outside the customize buffer." "\
 something in this group has been changed outside customize.")
@@ -1374,7 +1488,7 @@ and `face'."
         (text (or (and (eq category 'group)
                        (nth 4 entry))
                   (nth 3 entry)))
-        (lisp (eq (widget-get parent :custom-form) 'lisp))
+        (form (widget-get parent :custom-form))
         children)
     (while (string-match "\\`\\(.*\\)%c\\(.*\\)\\'" text)
       (setq text (concat (match-string 1 text) 
@@ -1403,8 +1517,10 @@ and `face'."
        (if (eq custom-magic-show 'long)
            (insert text)
          (insert (symbol-name state)))
-       (when lisp 
-         (insert " (lisp)"))
+       (cond ((eq form 'lisp)
+              (insert " (lisp)"))
+             ((eq form 'mismatch)
+              (insert " (mismatch)")))
        (put-text-property start (point) 'face 'custom-state-face))
       (insert "\n"))
     (when (and (eq category 'group)
@@ -1425,7 +1541,7 @@ and `face'."
             :button-suffix ""
             :help-echo "Change the state."
             :format (if hidden "%t" "%[%t%]")
-            :tag (if lisp 
+            :tag (if (memq form '(lisp mismatch))
                      (concat "(" magic ")")
                    (concat "[" magic "]")))
            children)
@@ -1470,7 +1586,6 @@ and `face'."
   :value-delete 'widget-children-value-delete
   :value-get 'widget-value-value-get
   :validate 'widget-children-validate
-  :button-face 'custom-button-face
   :match (lambda (widget value) (symbolp value)))
 
 (defun custom-convert-widget (widget)
@@ -1550,6 +1665,8 @@ and `face'."
                   (require load)
                 (error nil)))
              ;; Don't reload a file already loaded.
+             ((and (boundp 'preloaded-file-list)
+                   (member load preloaded-file-list)))
              ((assoc load load-history))
              ((assoc (locate-library load) load-history))
              (t
@@ -1565,8 +1682,31 @@ and `face'."
   "Load all dependencies for WIDGET."
   (custom-load-symbol (widget-value widget)))
 
+(defun custom-unloaded-symbol-p (symbol)
+  "Return non-nil if the dependencies of SYMBOL has not yet been loaded."
+  (let ((found nil)
+       (loads (get symbol 'custom-loads))
+       load)
+    (while loads
+      (setq load (car loads)
+           loads (cdr loads))
+      (cond ((symbolp load)
+            (unless (featurep load)
+              (setq found t)))
+           ((assoc load load-history))
+           ((assoc (locate-library load) load-history)
+            (message nil))
+           (t
+            (setq found t))))
+    found))
+
+(defun custom-unloaded-widget-p (widget)
+  "Return non-nil if the dependencies of WIDGET has not yet been loaded."
+  (custom-unloaded-symbol-p (widget-value widget)))
+
 (defun custom-toggle-hide (widget)
   "Toggle visibility of WIDGET."
+  (custom-load-widget widget)
   (let ((state (widget-get widget :custom-state)))
     (cond ((memq state '(invalid modified))
           (error "There are unset changes"))
@@ -1652,6 +1792,13 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
   "Face used for pushable variable tags."
   :group 'custom-faces)
 
+(defcustom custom-variable-default-form 'edit
+  "Default form of displaying variable values."
+  :type '(choice (const edit)
+                (const lisp))
+  :group 'custom-buffer
+  :version "20.3")
+
 (define-widget 'custom-variable 'custom
   "Customize variable."
   :format "%v"
@@ -1660,7 +1807,7 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
   :custom-category 'option
   :custom-state nil
   :custom-menu 'custom-variable-menu-create
-  :custom-form 'edit
+  :custom-form nil ; defaults to value of `custom-variable-default-form'
   :value-create 'custom-variable-value-create
   :action 'custom-variable-action
   :custom-set 'custom-variable-set
@@ -1688,6 +1835,8 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
 (defun custom-variable-value-create (widget)
   "Here is where you edit the variables value."
   (custom-load-widget widget)
+  (unless (widget-get widget :custom-form)
+    (widget-put widget :custom-form custom-variable-default-form))
   (let* ((buttons (widget-get widget :buttons))
         (children (widget-get widget :children))
         (form (widget-get widget :custom-form))
@@ -1712,12 +1861,12 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
     (when (eq state 'unknown)
       (unless (widget-apply conv :match value)
        ;; (widget-apply (widget-convert type) :match value)
-       (setq form 'lisp)))
+       (setq form 'mismatch)))
     ;; Now we can create the child widget.
     (cond ((eq custom-buffer-style 'tree)
           (insert prefix (if last " `--- " " |--- "))
           (push (widget-create-child-and-convert
-                 widget 'custom-tree-variable-tag)
+                 widget 'custom-browse-variable-tag)
                 buttons)
           (insert " " tag "\n")
           (widget-put widget :buttons buttons))
@@ -1736,7 +1885,7 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
                  :action 'custom-toggle-parent
                  nil)
                 buttons))
-         ((eq form 'lisp)
+         ((memq form '(lisp mismatch))
           ;; In lisp mode edit the saved value when possible.
           (let* ((value (cond ((get symbol 'saved-value)
                                (car (get symbol 'saved-value)))
@@ -1767,7 +1916,7 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
           (let* ((format (widget-get type :format))
                  tag-format value-format)
             (unless (string-match ":" format)
-              (error "Bad format."))
+              (error "Bad format"))
             (setq tag-format (substring format 0 (match-end 0)))
             (setq value-format (substring format (match-end 0)))
             (push (widget-create-child-and-convert
@@ -1856,10 +2005,10 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
     (widget-put widget :custom-state state)))
 
 (defvar custom-variable-menu 
-  '(("Set" custom-variable-set
+  '(("Set for Current Session" custom-variable-set
      (lambda (widget)
        (eq (widget-get widget :custom-state) 'modified)))
-    ("Save" custom-variable-save
+    ("Save for Future Sessions" custom-variable-save
      (lambda (widget)
        (memq (widget-get widget :custom-state) '(modified set changed rogue))))
     ("Reset to Current" custom-redraw
@@ -1879,10 +2028,10 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
     ("---" ignore ignore)
     ("Don't show as Lisp expression" custom-variable-edit 
      (lambda (widget)
-       (not (eq (widget-get widget :custom-form) 'edit))))
-    ("Show as Lisp expression" custom-variable-edit-lisp
+       (eq (widget-get widget :custom-form) 'lisp)))
+    ("Show initial Lisp expression" custom-variable-edit-lisp
      (lambda (widget)
-       (not (eq (widget-get widget :custom-form) 'lisp)))))
+       (eq (widget-get widget :custom-form) 'edit))))
   "Alist of actions for the `custom-variable' widget.
 Each entry has the form (NAME ACTION FILTER) where NAME is the name of
 the menu entry, ACTION is the function to call on the widget when the
@@ -1929,11 +2078,11 @@ Optional EVENT is the location for the menu."
         (set (or (get symbol 'custom-set) 'set-default))
          val)
     (cond ((eq state 'hidden)
-          (error "Cannot set hidden variable."))
+          (error "Cannot set hidden variable"))
          ((setq val (widget-apply child :validate))
           (goto-char (widget-get val :from))
           (error "%s" (widget-get val :error)))
-         ((eq form 'lisp)
+         ((memq form '(lisp mismatch))
           (funcall set symbol (eval (setq val (widget-value child))))
           (put symbol 'customized-value (list val)))
          (t
@@ -1943,7 +2092,7 @@ Optional EVENT is the location for the menu."
     (custom-redraw-magic widget)))
 
 (defun custom-variable-save (widget)
-  "Set the default value for the variable being edited by WIDGET."
+  "Set and save the value for the variable being edited by WIDGET."
   (let* ((form (widget-get widget :custom-form))
         (state (widget-get widget :custom-state))
         (child (car (widget-get widget :children)))
@@ -1951,11 +2100,11 @@ Optional EVENT is the location for the menu."
         (set (or (get symbol 'custom-set) 'set-default))
         val)
     (cond ((eq state 'hidden)
-          (error "Cannot set hidden variable."))
+          (error "Cannot set hidden variable"))
          ((setq val (widget-apply child :validate))
           (goto-char (widget-get val :from))
           (error "%s" (widget-get val :error)))
-         ((eq form 'lisp)
+         ((memq form '(lisp mismatch))
           (put symbol 'saved-value (list (widget-value child)))
           (funcall set symbol (eval (widget-value child))))
          (t
@@ -2036,10 +2185,10 @@ The X11 Window System.")
                                           :sibling-args (:help-echo "\
 OS/2 Presentation Manager.")
                                           pm)
-                                   (const :format "Win32 "
+                                   (const :format "W32 "
                                           :sibling-args (:help-echo "\
-Windows NT/95/97.")
-                                          win32)
+Windows NT/9X.")
+                                          w32)
                                    (const :format "DOS "
                                           :sibling-args (:help-echo "\
 Plain MS-DOS.")
@@ -2088,6 +2237,14 @@ Match frames with dark backgrounds.")
   "Face used for face tags."
   :group 'custom-faces)
 
+(defcustom custom-face-default-form 'selected
+  "Default form of displaying face definition."
+  :type '(choice (const all)
+                (const selected)
+                (const lisp))
+  :group 'custom-buffer
+  :version "20.3")
+
 (define-widget 'custom-face 'custom
   "Customize face."
   :sample-face 'custom-face-tag-face
@@ -2097,7 +2254,7 @@ Match frames with dark backgrounds.")
   :value-create 'custom-face-value-create
   :action 'custom-face-action
   :custom-category 'face
-  :custom-form 'selected
+  :custom-form nil ; defaults to value of `custom-face-default-form'
   :custom-set 'custom-face-set
   :custom-save 'custom-face-save
   :custom-reset-current 'custom-redraw
@@ -2151,7 +2308,7 @@ Match frames with dark backgrounds.")
     (cond ((eq custom-buffer-style 'tree)
           (insert prefix (if is-last " `--- " " |--- "))
           (push (widget-create-child-and-convert
-                 widget 'custom-tree-face-tag)
+                 widget 'custom-browse-face-tag)
                 buttons)
           (insert " " tag "\n")
           (widget-put widget :buttons buttons))
@@ -2201,6 +2358,8 @@ Match frames with dark backgrounds.")
           (unless (eq state 'hidden)
             (message "Creating face editor...")
             (custom-load-widget widget)
+            (unless (widget-get widget :custom-form)
+                (widget-put widget :custom-form custom-face-default-form))
             (let* ((symbol (widget-value widget))
                    (spec (or (get symbol 'saved-face)
                              (get symbol 'face-defface-spec)
@@ -2209,7 +2368,12 @@ Match frames with dark backgrounds.")
                                             symbol (selected-frame))))))
                    (form (widget-get widget :custom-form))
                    (indent (widget-get widget :indent))
-                   (edit (widget-create-child-and-convert
+                   edit)
+              ;; If the user has changed this face in some other way,
+              ;; edit it as the user has specified it.
+              (if (not (face-spec-match-p symbol spec (selected-frame)))
+                  (setq spec (list (list t (face-attr-construct symbol (selected-frame))))))
+              (setq edit (widget-create-child-and-convert
                           widget
                           (cond ((and (eq form 'selected)
                                       (widget-apply custom-face-selected 
@@ -2223,14 +2387,14 @@ Match frames with dark backgrounds.")
                                 (t 
                                  (when indent (insert-char ?\  indent))
                                  'sexp))
-                          :value spec)))
+                          :value spec))
               (custom-face-state-set widget)
               (widget-put widget :children (list edit)))
             (message "Creating face editor...done"))))))
 
 (defvar custom-face-menu 
-  '(("Set" custom-face-set)
-    ("Save" custom-face-save)
+  '(("Set for Current Session" custom-face-set)
+    ("Save for Future Sessions" custom-face-save-command)
     ("Reset to Saved" custom-face-reset-saved
      (lambda (widget)
        (get (widget-value widget) 'saved-face)))
@@ -2309,14 +2473,20 @@ Optional EVENT is the location for the menu."
     (custom-face-state-set widget)
     (custom-redraw-magic widget)))
 
+(defun custom-face-save-command (widget)
+  "Save in `.emacs' the face attributes in WIDGET."
+  (custom-face-save widget)
+  (custom-save-all))
+
 (defun custom-face-save (widget)
-  "Make the face attributes in WIDGET default."
+  "Prepare for saving WIDGET's face attributes, but don't write `.emacs'."
   (let* ((symbol (widget-value widget))
         (child (car (widget-get widget :children)))
         (value (widget-value child)))
     (face-spec-set symbol value)
     (put symbol 'saved-face value)
     (put symbol 'customized-face nil)
+    (custom-save-all)
     (custom-face-state-set widget)
     (custom-redraw-magic widget)))
 
@@ -2404,6 +2574,13 @@ Optional EVENT is the location for the menu."
 
 (define-widget 'hook 'list
   "A emacs lisp hook"
+  :value-to-internal (lambda (widget value)
+                      (if (and value (symbolp value))
+                          (list value)
+                        value))
+  :match (lambda (widget value)
+          (or (symbolp value)
+              (widget-group-match widget value)))
   :convert-widget 'custom-hook-convert-widget
   :tag "Hook")
 
@@ -2494,74 +2671,88 @@ and so forth.  The remaining group tags are shown with
        (insert "--------")))
   (widget-default-create widget))
 
+(defun custom-group-members (symbol groups-only)
+  "Return SYMBOL's custom group members.
+If GROUPS-ONLY non-nil, return only those members that are groups."
+  (if (not groups-only)
+      (get symbol 'custom-group)
+    (let (members)
+      (dolist (entry (get symbol 'custom-group))
+       (when (eq (nth 1 entry) 'custom-group)
+         (push entry members)))
+      (nreverse members))))
+
 (defun custom-group-value-create (widget)
   "Insert a customize group for WIDGET in the current buffer."
-  (let ((state (widget-get widget :custom-state))
-       (level (widget-get widget :custom-level))
-       (indent (widget-get widget :indent))
-       (prefix (widget-get widget :custom-prefix))
-       (buttons (widget-get widget :buttons))
-       (tag (widget-get widget :tag))
-       (symbol (widget-value widget)))
+  (let* ((state (widget-get widget :custom-state))
+        (level (widget-get widget :custom-level))
+        ;; (indent (widget-get widget :indent))
+        (prefix (widget-get widget :custom-prefix))
+        (buttons (widget-get widget :buttons))
+        (tag (widget-get widget :tag))
+        (symbol (widget-value widget))
+        (members (custom-group-members symbol
+                                       (and (eq custom-buffer-style 'tree)
+                                            custom-browse-only-groups))))
     (cond ((and (eq custom-buffer-style 'tree)
-               (eq state 'hidden))
-          (custom-tree-insert-prefix prefix)
+               (eq state 'hidden)
+               (or members (custom-unloaded-widget-p widget)))
+          (custom-browse-insert-prefix prefix)
           (push (widget-create-child-and-convert
-                 widget 'custom-tree-visibility 
+                 widget 'custom-browse-visibility 
                  ;; :tag-glyph "plus"
                  :tag "+")
                 buttons)
           (insert "-- ")
           ;; (widget-glyph-insert nil "-- " "horizontal")
           (push (widget-create-child-and-convert
-                 widget 'custom-tree-group-tag)
+                 widget 'custom-browse-group-tag)
                 buttons)
           (insert " " tag "\n")
           (widget-put widget :buttons buttons))
          ((and (eq custom-buffer-style 'tree)
-               (zerop (length (get symbol 'custom-group))))
-          (custom-tree-insert-prefix prefix)
+               (zerop (length members)))
+          (custom-browse-insert-prefix prefix)
           (insert "[ ]-- ")
           ;; (widget-glyph-insert nil "[ ]" "empty")
           ;; (widget-glyph-insert nil "-- " "horizontal")
           (push (widget-create-child-and-convert 
-                 widget 'custom-tree-group-tag)
+                 widget 'custom-browse-group-tag)
                 buttons)
           (insert " " tag "\n")
           (widget-put widget :buttons buttons))
          ((eq custom-buffer-style 'tree)
-          (custom-tree-insert-prefix prefix)
+          (custom-browse-insert-prefix prefix)
           (custom-load-widget widget)
-          (if (zerop (length (get symbol 'custom-group)))
+          (if (zerop (length members))
               (progn 
-                (custom-tree-insert-prefix prefix)
+                (custom-browse-insert-prefix prefix)
                 (insert "[ ]-- ")
                 ;; (widget-glyph-insert nil "[ ]" "empty")
                 ;; (widget-glyph-insert nil "-- " "horizontal")
                 (push (widget-create-child-and-convert 
-                       widget 'custom-tree-group-tag)
+                       widget 'custom-browse-group-tag)
                       buttons)
                 (insert " " tag "\n")
                 (widget-put widget :buttons buttons))
             (push (widget-create-child-and-convert 
-                   widget 'custom-tree-visibility 
+                   widget 'custom-browse-visibility 
                    ;; :tag-glyph "minus"
                    :tag "-")
                   buttons)
             (insert "-\\ ")
             ;; (widget-glyph-insert nil "-\\ " "top")
             (push (widget-create-child-and-convert 
-                   widget 'custom-tree-group-tag)
+                   widget 'custom-browse-group-tag)
                   buttons)
             (insert " " tag "\n")
             (widget-put widget :buttons buttons)
             (message "Creating group...")
-            (let* ((members (custom-sort-items (get symbol 'custom-group)
+            (let* ((members (custom-sort-items members
                              custom-browse-sort-alphabetically
                              custom-browse-order-groups))
                    (prefixes (widget-get widget :custom-prefixes))
                    (custom-prefix-list (custom-prefix-add symbol prefixes))
-                   (length (length members))
                    (extra-prefix (if (widget-get widget :custom-last)
                                      "   "
                                    " | "))
@@ -2573,8 +2764,7 @@ and so forth.  The remaining group tags are shown with
                 (push (widget-create-child-and-convert
                        widget (nth 1 entry)
                        :group widget
-                       :tag (custom-unlispify-tag-name
-                             (nth 0 entry))
+                       :tag (custom-unlispify-tag-name (nth 0 entry))
                        :custom-prefixes custom-prefix-list
                        :custom-level (1+ level)
                        :custom-last (null members)
@@ -2602,7 +2792,7 @@ and so forth.  The remaining group tags are shown with
                      symbol)
                     buttons)
             (push (widget-create-child-and-convert 
-                   widget 'group-visibility
+                   widget 'custom-group-visibility
                    :help-echo "Show members of this group."
                    :action 'custom-toggle-parent
                    (not (eq state 'hidden)))
@@ -2675,7 +2865,7 @@ and so forth.  The remaining group tags are shown with
           ;; Members.
           (message "Creating group...")
           (custom-load-widget widget)
-          (let* ((members (custom-sort-items (get symbol 'custom-group)
+          (let* ((members (custom-sort-items members
                                              custom-buffer-sort-alphabetically
                                              custom-buffer-order-groups))
                  (prefixes (widget-get widget :custom-prefixes))
@@ -2714,10 +2904,10 @@ Creating group members... %2d%%"
           (insert "/\n")))))
 
 (defvar custom-group-menu 
-  '(("Set" custom-group-set
+  '(("Set for Current Session" custom-group-set
      (lambda (widget)
        (eq (widget-get widget :custom-state) 'modified)))
-    ("Save" custom-group-save
+    ("Save for Future Sessions" custom-group-save
      (lambda (widget)
        (memq (widget-get widget :custom-state) '(modified set))))
     ("Reset to Current" custom-group-reset-current
@@ -2813,19 +3003,27 @@ Optional EVENT is the location for the menu."
 
 ;;; The `custom-save-all' Function.
 ;;;###autoload
-(defcustom custom-file (if (featurep 'xemacs)
-                          "~/.xemacs-custom"
-                        "~/.emacs")
+(defcustom custom-file nil
   "File used for storing customization information.
-If you change this from the default \"~/.emacs\" you need to
-explicitly load that file for the settings to take effect."
-  :type 'file
+The default is nil, which means to use your init file
+as specified by `user-init-file'.  If you specify some other file,
+you need to explicitly load that file for the settings to take effect."
+  :type '(choice (const :tag "Your Emacs init file" nil) file)
   :group 'customize)
 
+(defun custom-file ()
+  "Return the file name for saving customizations."
+  (setq custom-file
+       (or custom-file
+           user-init-file
+           (read-file-name "File for customizations: "
+                           "~/" nil nil ".emacs"))))
+
 (defun custom-save-delete (symbol)
-  "Delete the call to SYMBOL form `custom-file'.
+  "Delete the call to SYMBOL from `custom-file'.
 Leave point at the location of the call, or after the last expression."
-  (set-buffer (find-file-noselect custom-file))
+  (let ((default-major-mode))
+    (set-buffer (find-file-noselect (custom-file))))
   (goto-char (point-min))
   (catch 'found
     (while t
@@ -2928,54 +3126,18 @@ Leave point at the location of the call, or after the last expression."
 ;;;###autoload
 (defun custom-save-all ()
   "Save all customizations in `custom-file'."
-  (custom-save-variables)
-  (custom-save-faces)
-  (save-excursion
-    (set-buffer (find-file-noselect custom-file))
-    (save-buffer)))
+  (let ((inhibit-read-only t))
+    (custom-save-variables)
+    (custom-save-faces)
+    (save-excursion
+      (let ((default-major-mode nil))
+       (set-buffer (find-file-noselect (custom-file))))
+      (save-buffer))))
 
 ;;; The Customize Menu.
 
 ;;; Menu support
 
-(unless (string-match "XEmacs" emacs-version)
-  (defconst custom-help-menu
-    '("Customize"
-      ["Update menu..." Custom-menu-update t]
-      ["Browse..." (customize-browse 'emacs) t]
-      ["Group..." customize-group t]
-      ["Variable..." customize-variable t]
-      ["Face..." customize-face t]
-      ["Saved..." customize-saved t]
-      ["Set..." customize-customized t]
-      ["--" custom-menu-sep t]
-      ["Apropos..." customize-apropos t]
-      ["Group apropos..." customize-apropos-groups t]
-      ["Variable apropos..." customize-apropos-options t]
-      ["Face apropos..." customize-apropos-faces t])
-    ;; This menu should be identical to the one defined in `menu-bar.el'. 
-    "Customize menu")
-
-  (defun custom-menu-reset ()
-    "Reset customize menu."
-    (remove-hook 'custom-define-hook 'custom-menu-reset)
-    (define-key global-map [menu-bar help-menu customize-menu]
-      (cons (car custom-help-menu)
-           (easy-menu-create-keymaps (car custom-help-menu)
-                                     (cdr custom-help-menu)))))
-
-  (defun Custom-menu-update (event)
-    "Update customize menu."
-    (interactive "e")
-    (add-hook 'custom-define-hook 'custom-menu-reset)
-    (let* ((emacs (widget-apply '(custom-group) :custom-menu 'emacs))
-          (menu `(,(car custom-help-menu)
-                  ,emacs
-                  ,@(cdr (cdr custom-help-menu)))))
-      (let ((map (easy-menu-create-keymaps (car menu) (cdr menu))))
-       (define-key global-map [menu-bar help-menu customize-menu]
-         (cons (car menu) map))))))
-
 (defcustom custom-menu-nesting 2
   "Maximum nesting in custom menus."
   :type 'integer
@@ -3075,7 +3237,20 @@ The format is suitable for use with `easy-menu-define'."
   (define-key custom-mode-map " " 'scroll-up)
   (define-key custom-mode-map "\177" 'scroll-down)
   (define-key custom-mode-map "q" 'bury-buffer)
-  (define-key custom-mode-map "u" 'Custom-goto-parent))
+  (define-key custom-mode-map "u" 'Custom-goto-parent)
+  (define-key custom-mode-map "n" 'widget-forward)
+  (define-key custom-mode-map "p" 'widget-backward)
+  (define-key custom-mode-map [mouse-1] 'Custom-move-and-invoke))
+
+(defun Custom-move-and-invoke (event)
+  "Move to where you click, and if it is an active field, invoke it."
+  (interactive "e")
+  (mouse-set-point event)
+  (if (widget-event-point event)
+      (let* ((pos (widget-event-point event))
+            (button (get-char-property pos 'button)))
+       (if button
+           (widget-button-click event)))))
 
 (easy-menu-define Custom-mode-menu 
     custom-mode-map
@@ -3116,7 +3291,10 @@ The following commands are available:
 
 Move to next button or editable field.     \\[widget-forward]
 Move to previous button or editable field. \\[widget-backward]
-Invoke button under the mouse pointer.     \\[widget-button-click]
+\\<widget-field-keymap>\
+Complete content of editable text field.   \\[widget-complete]
+\\<custom-mode-map>\
+Invoke button under the mouse pointer.     \\[Custom-move-and-invoke]
 Invoke button under point.                \\[widget-button-press]
 Set all modifications.                    \\[Custom-set]
 Make all modifications default.                   \\[Custom-save]
@@ -3134,6 +3312,8 @@ if that value is non-nil."
   (make-local-variable 'custom-options)
   (make-local-variable 'widget-documentation-face)
   (setq widget-documentation-face 'custom-documentation-face)
+  (make-local-variable 'widget-button-face)
+  (setq widget-button-face 'custom-button-face)
   (make-local-hook 'widget-edit-functions)
   (add-hook 'widget-edit-functions 'custom-state-buffer-message nil t)
   (run-hooks 'custom-mode-hook))