(replace_buffer_in_all_windows):
[bpt/emacs.git] / lisp / cus-edit.el
index 6f91c25..0af6900 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.9929
+;; Version: 1.9954
 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
 
 ;; This file is part of GNU Emacs.
 ;; 
 ;; See `custom.el'.
 
+;; No commands should have names starting with `custom-' because
+;; that interferes with completion.  Use `customize-' for commands
+;; that the user will run with M-x, and `Custom-' for interactive commands.
+
 ;;; Code:
 
 (require 'cus-face)
   :group 'customize
   :group 'faces)
 
+(defgroup custom-browse nil
+  "Control customize browser."
+  :prefix "custom-"
+  :group 'customize)
+
 (defgroup custom-buffer nil
-  "Control the customize buffers."
+  "Control customize buffers."
   :prefix "custom-"
   :group 'customize)
 
 (defgroup custom-menu nil
-  "Control how the customize menus."
+  "Control customize menus."
   :prefix "custom-"
   :group 'customize)
 
@@ -431,6 +440,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)
@@ -449,15 +463,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 
@@ -545,62 +560,86 @@ if that fails, the doc string with `custom-guess-doc-alist'."
 
 ;;; Sorting.
 
+(defcustom custom-browse-sort-alphabetically nil
+  "If non-nil, sort members of each customization group alphabetically."
+  :type 'boolean
+  :group 'custom-browse)
+
+(defcustom custom-browse-order-groups nil
+  "If non-nil, order group members within each customization group.
+If `first', order groups before non-groups.
+If `last', order groups after non-groups."
+  :type '(choice (const first)
+                (const last)
+                (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 the members of each customization group alphabetically."
+  "If non-nil, sort members of each customization group alphabetically."
   :type 'boolean
   :group 'custom-buffer)
 
-(defcustom custom-buffer-groups-last nil
-  "If non-nil, put subgroups after all ordinary options within a group."
-  :type 'boolean
+(defcustom custom-buffer-order-groups 'last
+  "If non-nil, order group members within each customization group.
+If `first', order groups before non-groups.
+If `last', order groups after non-groups."
+  :type '(choice (const first)
+                (const last)
+                (const :tag "none" nil))
   :group 'custom-buffer)
 
 (defcustom custom-menu-sort-alphabetically nil
-  "If non-nil, sort the members of each customization group alphabetically."
+  "If non-nil, sort members of each customization group alphabetically."
   :type 'boolean
   :group 'custom-menu)
 
-(defcustom custom-menu-groups-first t
-  "If non-nil, put subgroups before all ordinary options within a group."
-  :type 'boolean
+(defcustom custom-menu-order-groups 'first
+  "If non-nil, order group members within each customization group.
+If `first', order groups before non-groups.
+If `last', order groups after non-groups."
+  :type '(choice (const first)
+                (const last)
+                (const :tag "none" nil))
   :group 'custom-menu)
 
-(defun custom-buffer-sort-predicate (a b)
-  "Return t iff A should come before B in a customization buffer.
-A and B should be members of a `custom-group' property."
-  (cond ((and (not custom-buffer-groups-last)
-             (not custom-buffer-sort-alphabetically))
-        nil)
-       ((or (eq (eq (nth 1 a) 'custom-group) (eq (nth 1 b) 'custom-group))
-            (not custom-buffer-groups-last))
-        (if custom-buffer-sort-alphabetically
-            (string-lessp (symbol-name (nth 0 a)) (symbol-name (nth 0 b)))
-          nil))
-       (t
-        (not (eq (nth 1 a) 'custom-group) ))))
-
-(defalias 'custom-browse-sort-predicate 'ignore)
-
-(defun custom-menu-sort-predicate (a b)
-  "Return t iff A should come before B in a customization menu.
-A and B should be members of a `custom-group' property."
-  (cond ((and (not custom-menu-groups-first)
-             (not custom-menu-sort-alphabetically))
-        nil)
-       ((or (eq (eq (nth 1 a) 'custom-group) (eq (nth 1 b) 'custom-group))
-            (not custom-menu-groups-first))
-        (if custom-menu-sort-alphabetically
-            (string-lessp (symbol-name (nth 0 a)) (symbol-name (nth 0 b)))
-          nil))
-       (t
-        (eq (nth 1 a) 'custom-group) )))
+(defun custom-sort-items (items sort-alphabetically order-groups)
+  "Return a sorted copy of ITEMS.
+ITEMS should be a `custom-group' property.
+If SORT-ALPHABETICALLY non-nil, sort alphabetically.
+If ORDER-GROUPS is `first' order groups before non-groups, if `last' order
+groups after non-groups, if nil do not order groups at all."
+  (sort (copy-sequence items)
+   (lambda (a b)
+     (let ((typea (nth 1 a)) (typeb (nth 1 b))
+          (namea (symbol-name (nth 0 a))) (nameb (symbol-name (nth 0 b))))
+       (cond ((not order-groups)
+             ;; Since we don't care about A and B order, maybe sort.
+             (when sort-alphabetically
+               (string-lessp namea nameb)))
+            ((eq typea 'custom-group)
+             ;; If B is also a group, maybe sort.  Otherwise, order A and B.
+             (if (eq typeb 'custom-group)
+                 (when sort-alphabetically
+                   (string-lessp namea nameb))
+               (eq order-groups 'first)))
+            ((eq typeb 'custom-group)
+             ;; Since A cannot be a group, order A and B.
+             (eq order-groups 'last))
+            (sort-alphabetically
+             ;; Since A and B cannot be groups, sort.
+             (string-lessp namea nameb)))))))
 
 ;;; Custom Mode Commands.
 
 (defvar custom-options nil
   "Customization widgets in the current buffer.")
 
-(defun custom-set ()
+(defun Custom-set ()
   "Set changes in all modified options."
   (interactive)
   (let ((children custom-options))
@@ -609,7 +648,7 @@ A and B should be members of a `custom-group' property."
                (widget-apply child :custom-set)))
            children)))
 
-(defun custom-save ()
+(defun Custom-save ()
   "Set all modified group members and save them."
   (interactive)
   (let ((children custom-options))
@@ -620,9 +659,9 @@ A and B should be members of a `custom-group' property."
   (custom-save-all))
 
 (defvar custom-reset-menu 
-  '(("Current" . custom-reset-current)
-    ("Saved" . custom-reset-saved)
-    ("Standard Settings" . custom-reset-standard))
+  '(("Current" . Custom-reset-current)
+    ("Saved" . Custom-reset-saved)
+    ("Standard Settings" . Custom-reset-standard))
   "Alist of actions for the `Reset' button.
 The key is a string containing the name of the action, the value is a
 lisp function taking the widget as an element which will be called
@@ -637,7 +676,7 @@ when the action is chosen.")
     (if answer
        (funcall answer))))
 
-(defun custom-reset-current (&rest ignore)
+(defun Custom-reset-current (&rest ignore)
   "Reset all modified group members to their current value."
   (interactive)
   (let ((children custom-options))
@@ -646,7 +685,7 @@ when the action is chosen.")
                (widget-apply child :custom-reset-current)))
            children)))
 
-(defun custom-reset-saved (&rest ignore)
+(defun Custom-reset-saved (&rest ignore)
   "Reset all modified or set group members to their saved value."
   (interactive)
   (let ((children custom-options))
@@ -655,7 +694,7 @@ when the action is chosen.")
                (widget-apply child :custom-reset-saved)))
            children)))
 
-(defun custom-reset-standard (&rest ignore)
+(defun Custom-reset-standard (&rest ignore)
   "Reset all modified, set, or saved group members to their standard settings."
   (interactive)
   (let ((children custom-options))
@@ -701,7 +740,7 @@ If the variable has a `custom-type' property, it must be a widget and the
                   (eval-minibuffer prompt)))))))
 
 ;;;###autoload
-(defun custom-set-value (var val)
+(defun customize-set-value (var val)
   "Set VARIABLE to VALUE.  VALUE is a Lisp object.
 
 If VARIABLE has a `variable-interactive' property, that is used as if
@@ -715,7 +754,7 @@ If VARIABLE has a `custom-type' property, it must be a widget and the
   (set var val))
 
 ;;;###autoload
-(defun custom-set-variable (var val)
+(defun customize-set-variable (var val)
   "Set the default for VARIABLE to VALUE.  VALUE is a Lisp object.
 
 If VARIABLE has a `custom-set' property, that is used for setting
@@ -734,6 +773,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.
@@ -750,19 +809,23 @@ 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)
@@ -811,17 +874,14 @@ If SYMBOL is nil, customize all faces."
   (interactive (list (completing-read "Customize face: (default all) " 
                                      obarray 'custom-facep)))
   (if (or (null symbol) (and (stringp symbol) (zerop (length symbol))))
-      (let ((found nil))
-       (message "Looking for faces...")
-       (mapcar (lambda (symbol)
-                 (push (list symbol 'custom-face) found))
-               (nreverse (mapcar 'intern
-                                 (sort (mapcar 'symbol-name (face-list))
-                                       'string-lessp))))
-                       
-       (custom-buffer-create found "*Customize Faces*"))
-    (if (stringp symbol)
-       (setq symbol (intern symbol)))
+      (custom-buffer-create (custom-sort-items
+                            (mapcar (lambda (symbol)
+                                      (list symbol 'custom-face))
+                                    (face-list))
+                            t nil)
+                           "*Customize Faces*")
+    (when (stringp symbol)
+      (setq symbol (intern symbol)))
     (unless (symbolp symbol)
       (error "Should be a symbol %S" symbol))
     (custom-buffer-create (list (list symbol 'custom-face))
@@ -855,9 +915,10 @@ If SYMBOL is nil, customize all faces."
                (and (get symbol 'customized-value)
                     (boundp symbol)
                     (push (list symbol 'custom-variable) found))))
-    (if found 
-       (custom-buffer-create found "*Customize Customized*")
-      (error "No customized user options"))))
+    (if (not found)
+       (error "No customized user options")
+      (custom-buffer-create (custom-sort-items found t nil)
+                           "*Customize Customized*"))))
 
 ;;;###autoload
 (defun customize-saved ()
@@ -871,9 +932,10 @@ If SYMBOL is nil, customize all faces."
                (and (get symbol 'saved-value)
                     (boundp symbol)
                     (push (list symbol 'custom-variable) found))))
-    (if found 
-       (custom-buffer-create found "*Customize Saved*")
-      (error "No saved user options"))))
+    (if (not found )
+       (error "No saved user options")
+      (custom-buffer-create (custom-sort-items found t nil)
+                           "*Customize Saved*"))))
 
 ;;;###autoload
 (defun customize-apropos (regexp &optional all)
@@ -903,9 +965,9 @@ user-settable, as well as faces and groups."
                    (push (list symbol 'custom-variable) found)))))
     (if (not found)
        (error "No matches")
-      (let ((custom-buffer-sort-alphabetically t))
-       (custom-buffer-create (sort found 'custom-buffer-sort-predicate)
-                             "*Customize Apropos*")))))
+      (custom-buffer-create (custom-sort-items found t
+                                              custom-buffer-order-groups)
+                           "*Customize Apropos*"))))
 
 ;;;###autoload
 (defun customize-apropos-options (regexp &optional arg)
@@ -944,7 +1006,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
@@ -953,10 +1015,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
@@ -966,7 +1028,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
@@ -975,57 +1037,68 @@ 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.
-Push RET or click mouse-2 on the word ")
+  (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"
+                :tag "Help"
                 :help-echo "Read the online help."
                 "(emacs)Easy Customization")
   (widget-insert " for more information.\n\n")
   (message "Creating customization buttons...")
+  (widget-insert "Operate on everything in this buffer:\n ")
   (widget-create 'push-button
-                :tag "Set"
-                :help-echo "Set all modifications for this session."
+                :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)))
+                          (Custom-set)))
   (widget-insert " ")
   (widget-create 'push-button
-                :tag "Save"
+                :tag "Save for Future Sessions"
                 :help-echo "\
-Make the modifications default for future sessions."
+Make your editing in this buffer take effect for future Emacs sessions."
                 :action (lambda (widget &optional event)
-                          (custom-save)))
-  (widget-insert " ")
+                          (Custom-save)))
   (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 "\
-Reset all visible items in this buffer to their current settings."
-                  :action 'custom-reset-current)
+Reset all edited text in this buffer to reflect current values."
+                  :action 'Custom-reset-current)
     (widget-insert " ")
     (widget-create 'push-button
                   :tag "Reset to Saved"
                   :help-echo "\
-Reset all visible items in this buffer to their saved settings."
-                  :action 'custom-reset-saved)
+Reset all values in this buffer to their saved settings."
+                  :action 'Custom-reset-saved)
     (widget-insert " ")
     (widget-create 'push-button
                   :tag "Reset to Standard"
                   :help-echo "\
-Reset all visible items in this buffer to their standard settings."
-                  :action 'custom-reset-standard))
-  (widget-insert " ")
+Reset all values in this buffer to their standard settings."
+                  :action 'Custom-reset-standard))
+  (widget-insert "   ")
   (widget-create 'push-button
-                :tag "Done"
+                :tag "Bury Buffer"
                 :help-echo "Bury the buffer."
                 :action (lambda (widget &optional event)
                           (bury-buffer)))
@@ -1058,6 +1131,7 @@ Reset all visible items 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...")
@@ -1068,63 +1142,107 @@ Reset all visible items in this buffer to their standard settings."
 ;;; The Tree Browser.
 
 ;;;###autoload
-(defun customize-browse ()
+(defun customize-browse (&optional group)
   "Create a tree browser for the customize hierarchy."
   (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
                   :custom-state 'unknown
-                  :tag (custom-unlispify-tag-name 'emacs)
-                  :value 'emacs))
+                  :tag (custom-unlispify-tag-name group)
+                  :value group))
   (goto-char (point-min)))
 
-(define-widget 'custom-tree-visibility 'item
+(define-widget 'custom-browse-visibility 'item
   "Control visibility of of items in the customize tree browser."
-  :button-prefix "["
-  :button-suffix "]"
-  :format "%[%t%]"
-  :action 'custom-tree-visibility-action)
+  :format "%[[%t]%]"
+  :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"
-  :action 'custom-tree-group-tag-action)
+  :tag "Group"
+  :tag-glyph "folder"
+  :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"
-  :action 'custom-tree-variable-tag-action)
+  :tag "Option"
+  :tag-glyph "option"
+  :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"
-  :action 'custom-tree-face-tag-action)
+  :tag "Face"
+  :tag-glyph "face"
+  :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-browse-alist '(("   " "space")
+                             (" | " "vertical")
+                             ("-\\ " "top")
+                             (" |-" "middle")
+                             (" `-" "bottom")))
+
+(defun custom-browse-insert-prefix (prefix)
+  "Insert PREFIX.  On XEmacs convert it to line graphics."
+  (if nil ; (string-match "XEmacs" emacs-version)
+      (progn 
+       (insert "*")
+       (while (not (string-equal prefix ""))
+         (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-browse-alist))))
+             (overlay-put overlay 'end-glyph (widget-glyph-find name entry))
+             (overlay-put overlay 'start-open t)
+             (overlay-put overlay 'end-open t)))))
+    (insert prefix)))
+
 ;;; Modification of Basic Widgets.
 ;;
 ;; We add extra properties to the basic widgets needed here.  This is
@@ -1207,11 +1325,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.")
@@ -1266,22 +1384,22 @@ The list should be sorted most significant first.")
 
 (defcustom custom-magic-show 'long
   "If non-nil, show textual description of the state.
-If non-nil and not the symbol `long', only show first word."
+If `long', show a full-line description, not just one word."
   :type '(choice (const :tag "no" nil)
                 (const short)
                 (const long))
   :group 'custom-buffer)
 
 (defcustom custom-magic-show-hidden '(option face)
-  "Control whether the state button is shown for hidden items.
-The value should be a list with the custom categories where the state
+  "Control whether the State button is shown for hidden items.
+The value should be a list with the custom categories where the State
 button should be visible.  Possible categories are `group', `option',
 and `face'."
   :type '(set (const group) (const option) (const face))
   :group 'custom-buffer)
 
 (defcustom custom-magic-show-button nil
-  "Show a magic button indicating the state of each customization option."
+  "Show a \"magic\" button indicating the state of each customization option."
   :type 'boolean
   :group 'custom-buffer)
 
@@ -1312,7 +1430,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) 
@@ -1337,11 +1455,15 @@ and `face'."
             :tag "State")
            children)
       (insert ": ")
-      (if (eq custom-magic-show 'long)
-         (insert text)
-       (insert (symbol-name state)))
-      (when lisp 
-       (insert " (lisp)"))
+      (let ((start (point)))
+       (if (eq custom-magic-show 'long)
+           (insert text)
+         (insert (symbol-name state)))
+       (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)
               (not (and (eq custom-buffer-style 'links)
@@ -1361,7 +1483,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)
@@ -1375,6 +1497,24 @@ and `face'."
 
 ;;; The `custom' Widget.
 
+(defface custom-button-face nil
+  "Face used for buttons in customization buffers."
+  :group 'custom-faces)
+
+(defface custom-documentation-face nil
+  "Face used for documentation strings in customization buffers."
+  :group 'custom-faces)
+
+(defface custom-state-face '((((class color)
+                              (background dark))
+                             (:foreground "lime green"))
+                            (((class color)
+                              (background light))
+                             (:foreground "dark green"))
+                            (t nil))
+  "Face used for State descriptions in the customize buffer."
+  :group 'custom-faces)
+
 (define-widget 'custom 'default
   "Customize a user option."
   :format "%v"
@@ -1467,6 +1607,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
@@ -1482,8 +1624,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"))
@@ -1496,7 +1661,7 @@ and `face'."
     (widget-setup)))
 
 (defun custom-toggle-parent (widget &rest ignore)
-  "Toggle visibility of parent to WIDGET."
+  "Toggle visibility of parent of WIDGET."
   (custom-toggle-hide (widget-get widget :parent)))
 
 (defun custom-add-see-also (widget &optional prefix)
@@ -1527,32 +1692,41 @@ Insert PREFIX first if non-nil."
               (insert ", "))))
       (widget-put widget :buttons buttons))))
 
-(defun custom-add-parent-links (widget)
-  "Add `Parent groups: ...' to WIDGET."
+(defun custom-add-parent-links (widget &optional initial-string)
+  "Add \"Parent groups: ...\" to WIDGET if the group has parents.
+The value if non-nil if any parents were found.
+If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
   (let ((name (widget-value widget))
        (type (widget-type widget))
        (buttons (widget-get widget :buttons))
+       (start (point))
        found)
-    (insert "Parent groups:")
+    (insert (or initial-string "Parent groups:"))
     (mapatoms (lambda (symbol)
-               (let ((group (get symbol 'custom-group)))
-                 (when (assq name group)
-                   (when (eq type (nth 1 (assq name group)))
-                     (insert " ")
-                     (push (widget-create-child-and-convert 
-                            widget 'custom-group-link 
-                            :tag (custom-unlispify-tag-name symbol)
-                            symbol)
-                           buttons)
-                     (setq found t))))))
+               (let ((entry (assq name (get symbol 'custom-group))))
+                 (when (eq (nth 1 entry) type)
+                   (insert " ")
+                   (push (widget-create-child-and-convert 
+                          widget 'custom-group-link 
+                          :tag (custom-unlispify-tag-name symbol)
+                          symbol)
+                         buttons)
+                   (setq found t)))))
     (widget-put widget :buttons buttons)
-    (unless found
-      (insert " (none)"))
-    (insert "\n")))
+    (if found
+       (insert "\n")
+      (delete-region start (point)))
+    found))
 
 ;;; The `custom-variable' Widget.
 
-(defface custom-variable-sample-face '((t (:underline t)))
+(defface custom-variable-tag-face '((((class color)
+                                     (background dark))
+                                    (:foreground "light blue" :underline t))
+                                   (((class color)
+                                     (background light))
+                                    (:foreground "blue" :underline t))
+                                   (t (:underline t)))
   "Face used for unpushable variable tags."
   :group 'custom-faces)
 
@@ -1620,12 +1794,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 " +--- " " |--- "))
+          (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))
@@ -1634,7 +1808,7 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
           (push (widget-create-child-and-convert 
                  widget 'item
                  :format "%{%t%}: "
-                 :sample-face 'custom-variable-sample-face
+                 :sample-face 'custom-variable-tag-face
                  :tag tag
                  :parent widget)
                 buttons)
@@ -1644,7 +1818,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)))
@@ -1675,7 +1849,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
@@ -1685,7 +1859,7 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
                    :help-echo "Change value of this option."
                    :mouse-down-action 'custom-tag-mouse-down-action
                    :button-face 'custom-variable-button-face
-                   :sample-face 'custom-variable-sample-face
+                   :sample-face 'custom-variable-tag-face
                    tag)
                   buttons)
             (insert " ")
@@ -1764,10 +1938,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
@@ -1787,10 +1961,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
@@ -1837,11 +2011,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
@@ -1851,7 +2025,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)))
@@ -1859,11 +2033,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
@@ -1944,10 +2118,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.")
@@ -2057,9 +2231,9 @@ Match frames with dark backgrounds.")
     (unless tag
       (setq tag (prin1-to-string symbol)))
     (cond ((eq custom-buffer-style 'tree)
-          (insert prefix (if is-last " +--- " " |--- "))
+          (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))
@@ -2117,7 +2291,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 
@@ -2131,14 +2310,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)))
@@ -2217,8 +2396,13 @@ 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)))
@@ -2312,6 +2496,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-editable-list-match widget value)))
   :convert-widget 'custom-hook-convert-widget
   :tag "Hook")
 
@@ -2335,7 +2526,7 @@ Optional EVENT is the location for the menu."
 
 (define-widget 'custom-group-link 'link
   "Show parent in other window when activated."
-  :help-echo "Create customize buffer for this group group."
+  :help-echo "Create customization buffer for this group."
   :action 'custom-group-link-action)
 
 (defun custom-group-link-action (widget &rest ignore)
@@ -2343,7 +2534,7 @@ Optional EVENT is the location for the menu."
 
 ;;; The `custom-group' Widget.
 
-(defcustom custom-group-tag-faces '(custom-group-tag-face-1)
+(defcustom custom-group-tag-faces nil
   ;; In XEmacs, this ought to play games with font size.
   "Face used for group tags.
 The first member is used for level 1 groups, the second for level 2,
@@ -2392,61 +2583,98 @@ and so forth.  The remaining group tags are shown with
   (or (nth (1- (widget-get widget :custom-level)) custom-group-tag-faces)
       'custom-group-tag-face))
 
+(define-widget 'custom-group-visibility 'visibility
+  "An indicator and manipulator for hidden group contents."
+  :create 'custom-group-visibility-create)
+
+(defun custom-group-visibility-create (widget)
+  (let ((visible (widget-value widget)))
+    (if visible
+       (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))
-          (insert 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 :tag "+")
+                 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))))
-          (insert 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)
-          (insert prefix)
+          (custom-browse-insert-prefix prefix)
           (custom-load-widget widget)
-          (if (zerop (length (get symbol 'custom-group)))
+          (if (zerop (length members))
               (progn 
-                (insert 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 :tag "-")
+                   widget 'custom-browse-visibility 
+                   ;; :tag-glyph "minus"
+                   :tag "-")
                   buttons)
-            (insert "-+ ")
+            (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 (sort (copy-sequence (get symbol 'custom-group))
-                                  'custom-browse-sort-predicate))
+            (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)
                                      "   "
                                    " | "))
@@ -2458,8 +2686,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)
@@ -2483,11 +2710,11 @@ and so forth.  The remaining group tags are shown with
           (if (eq custom-buffer-style 'links)
               (push (widget-create-child-and-convert
                      widget 'custom-group-link 
-                     :tag "Show"
+                     :tag "Go to Group"
                      symbol)
                     buttons)
             (push (widget-create-child-and-convert 
-                   widget 'visibility
+                   widget 'group-visibility
                    :help-echo "Show members of this group."
                    :action 'custom-toggle-parent
                    (not (eq state 'hidden)))
@@ -2506,6 +2733,13 @@ and so forth.  The remaining group tags are shown with
           (widget-default-format-handler widget ?h))
          ;; Nested style.
          (t                            ;Visible.
+          ;; Add parent groups references above the group.
+          (if t    ;;; This should test that the buffer
+                   ;;; was made to display a group.
+              (when (eq level 1)
+                (if (custom-add-parent-links widget
+                                             "Go to parent group:")
+                    (insert "\n"))))
           ;; Create level indicator.
           (insert-char ?\  (* custom-buffer-indent (1- level)))
           (insert "/- ")
@@ -2541,18 +2775,21 @@ and so forth.  The remaining group tags are shown with
           (widget-put widget :buttons buttons)
           ;; Insert documentation.
           (widget-default-format-handler widget ?h)
-          ;; Parents and See also.
-          (when (eq level 1)
-            (insert-char ?\  custom-buffer-indent)
-            (custom-add-parent-links widget))
+          ;; Parent groups.
+          (if nil  ;;; This should test that the buffer
+                   ;;; was not made to display a group.
+              (when (eq level 1)
+                (insert-char ?\  custom-buffer-indent)
+                (custom-add-parent-links widget)))
           (custom-add-see-also widget 
                                (make-string (* custom-buffer-indent level)
                                             ?\ ))
           ;; Members.
           (message "Creating group...")
           (custom-load-widget widget)
-          (let* ((members (sort (copy-sequence (get symbol 'custom-group))
-                                'custom-buffer-sort-predicate))
+          (let* ((members (custom-sort-items members
+                                             custom-buffer-sort-alphabetically
+                                             custom-buffer-order-groups))
                  (prefixes (widget-get widget :custom-prefixes))
                  (custom-prefix-list (custom-prefix-add symbol prefixes))
                  (length (length members))
@@ -2589,10 +2826,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
@@ -2688,19 +2925,18 @@ 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-save-delete (symbol)
   "Delete the call to SYMBOL form `custom-file'.
 Leave point at the location of the call, or after the last expression."
-  (set-buffer (find-file-noselect custom-file))
+  (set-buffer (find-file-noselect (or custom-file user-init-file)))
   (goto-char (point-min))
   (catch 'found
     (while t
@@ -2785,7 +3021,7 @@ Leave point at the location of the call, or after the last expression."
        (princ "\n")))))
 
 ;;;###autoload
-(defun custom-save-customized ()
+(defun customize-save-customized ()
   "Save all user options which have been set in this session."
   (interactive)
   (mapatoms (lambda (symbol)
@@ -2803,53 +3039,17 @@ 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
+      (set-buffer (find-file-noselect (or custom-file user-init-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]
-      ["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
@@ -2906,8 +3106,9 @@ The menu is in a format applicable to `easy-menu-define'."
             (< (length (get symbol 'custom-group)) widget-menu-max-size))
        (let ((custom-prefix-list (custom-prefix-add symbol
                                                     custom-prefix-list))
-             (members (sort (copy-sequence (get symbol 'custom-group))
-                            'custom-menu-sort-predicate)))
+             (members (custom-sort-items (get symbol 'custom-group)
+                                         custom-menu-sort-alphabetically
+                                         custom-menu-order-groups)))
          (custom-load-symbol symbol)
          `(,(custom-unlispify-menu-entry symbol t)
            ,item
@@ -2940,30 +3141,61 @@ The format is suitable for use with `easy-menu-define'."
 
 (defvar custom-mode-map nil
   "Keymap for `custom-mode'.")
-  
+
 (unless custom-mode-map
   (setq custom-mode-map (make-sparse-keymap))
   (set-keymap-parent custom-mode-map widget-keymap)
   (suppress-keymap custom-mode-map)
-  (define-key custom-mode-map "q" 'bury-buffer))
-
-(easy-menu-define custom-mode-menu 
+  (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 "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
   "Menu used in customization buffers."
   `("Custom"
     ,(customize-menu-create 'customize)
-    ["Set" custom-set t]
-    ["Save" custom-save t]
-    ["Reset to Current" custom-reset-current t]
-    ["Reset to Saved" custom-reset-saved t]
-    ["Reset to Standard Settings" custom-reset-standard t]
+    ["Set" Custom-set t]
+    ["Save" Custom-save t]
+    ["Reset to Current" Custom-reset-current t]
+    ["Reset to Saved" Custom-reset-saved t]
+    ["Reset to Standard Settings" Custom-reset-standard t]
     ["Info" (Info-goto-node "(custom)The Customization Buffer") t]))
 
+(defun Custom-goto-parent ()
+  "Go to the parent group listed at the top of this buffer.
+If several parents are listed, go to the first of them."
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (if (search-forward "\nGo to parent group: " nil t)
+       (let* ((button (get-char-property (point) 'button))
+              (parent (downcase (widget-get  button :tag))))
+         (customize-group parent)))))
+
 (defcustom custom-mode-hook nil
   "Hook called when entering custom-mode."
   :type 'hook
   :group 'custom-buffer )
 
+(defun custom-state-buffer-message (widget)
+  (if (eq (widget-get (widget-get widget :parent) :custom-state) 'modified)
+      (message "To install your edits, invoke [State] and choose the Set operation")))
+
 (defun custom-mode ()
   "Major mode for editing customization buffers.
 
@@ -2971,13 +3203,16 @@ 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]
-Reset all modified options.               \\[custom-reset-current]
-Reset all modified or set options.        \\[custom-reset-saved]
-Reset all options.                        \\[custom-reset-standard]
+Set all modifications.                    \\[Custom-set]
+Make all modifications default.                   \\[Custom-save]
+Reset all modified options.               \\[Custom-reset-current]
+Reset all modified or set options.        \\[Custom-reset-saved]
+Reset all options.                        \\[Custom-reset-standard]
 
 Entry to this mode calls the value of `custom-mode-hook'
 if that value is non-nil."
@@ -2985,8 +3220,14 @@ if that value is non-nil."
   (setq major-mode 'custom-mode
        mode-name "Custom")
   (use-local-map custom-mode-map)
-  (easy-menu-add custom-mode-menu)
+  (easy-menu-add Custom-mode-menu)
   (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))
 
 ;;; The End.