diff lisp/custom/cus-edit.el @ 163:0132846995bd r20-3b8

Import from CVS: tag r20-3b8
author cvs
date Mon, 13 Aug 2007 09:43:35 +0200
parents 28f395d8dc7a
children 5a88923fcbfe
line wrap: on
line diff
--- a/lisp/custom/cus-edit.el	Mon Aug 13 09:42:28 2007 +0200
+++ b/lisp/custom/cus-edit.el	Mon Aug 13 09:43:35 2007 +0200
@@ -4,7 +4,7 @@
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Keywords: help, faces
-;; Version: 1.9916
+;; Version: 1.9931
 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
 
 ;; This file is part of GNU Emacs.
@@ -45,7 +45,8 @@
     (require 'cus-start)
   (error nil))
 
-(define-widget-keywords :custom-category :custom-prefixes :custom-menu
+(define-widget-keywords :custom-last :custom-prefix :custom-category
+  :custom-prefixes :custom-menu  
   :custom-show  
   :custom-magic :custom-state :custom-level :custom-form
   :custom-set :custom-save :custom-reset-current :custom-reset-saved 
@@ -209,6 +210,10 @@
   "Support editing files of data."
   :group 'emacs)
 
+(defgroup files nil
+  "Support editing files."
+  :group 'emacs)
+
 (defgroup wp nil
   "Word processing."
   :group 'emacs)
@@ -323,7 +328,7 @@
 
 (defgroup auto-save nil
   "Preventing accidential loss of data."
-  :group 'data)
+  :group 'files)
 
 (defgroup processes-basics nil
   "Basic stuff dealing with processes."
@@ -339,6 +344,18 @@
 
 ;;; Utilities.
 
+(defun custom-last (x &optional n)
+  ;; Stolen from `cl.el'.
+  "Returns the last link in the list LIST.
+With optional argument N, returns Nth-to-last link (default 1)."
+  (if n
+      (let ((m 0) (p x))
+	(while (consp p) (incf m) (pop p))
+	(if (<= n 0) p
+	  (if (< n m) (nthcdr (- m n) x) x)))
+    (while (consp (cdr x)) (pop x))
+    x))
+
 (defun custom-quote (sexp)
   "Quote SEXP iff it is not self quoting."
   (if (or (memq sexp '(t nil))
@@ -528,59 +545,55 @@
 
 ;;; Sorting.
 
-(defcustom custom-buffer-sort-predicate 'ignore
-  "Function used for sorting group members in buffers.
-The value should be useful as a predicate for `sort'.  
-The list to be sorted is the value of the groups `custom-group' property."
-  :type '(radio (const :tag "Unsorted" ignore)
-		(const :tag "Alphabetic" custom-sort-items-alphabetically)
-		(function :tag "Other"))
+(defcustom custom-buffer-sort-alphabetically nil
+  "If non-nil, sort the members of each customization group alphabetically."
+  :type 'boolean
   :group 'custom-buffer)
 
-(defcustom custom-buffer-order-predicate 'custom-sort-groups-last
-  "Function used for sorting group members in buffers.
-The value should be useful as a predicate for `sort'.  
-The list to be sorted is the value of the groups `custom-group' property."
-  :type '(radio (const :tag "Groups first" custom-sort-groups-first)
-		(const :tag "Groups last" custom-sort-groups-last)
-		(function :tag "Other"))
+(defcustom custom-buffer-groups-last nil
+  "If non-nil, put subgroups after all ordinary options within a group."
+  :type 'boolean
   :group 'custom-buffer)
 
-(defcustom custom-menu-sort-predicate 'ignore
-  "Function used for sorting group members in menus.
-The value should be useful as a predicate for `sort'.  
-The list to be sorted is the value of the groups `custom-group' property."
-  :type '(radio (const :tag "Unsorted" ignore)
-		(const :tag "Alphabetic" custom-sort-items-alphabetically)
-		(function :tag "Other"))
+(defcustom custom-menu-sort-alphabetically nil
+  "If non-nil, sort the 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
   :group 'custom-menu)
 
-(defcustom custom-menu-order-predicate 'custom-sort-groups-first
-  "Function used for sorting group members in menus.
-The value should be useful as a predicate for `sort'.  
-The list to be sorted is the value of the groups `custom-group' property."
-  :type '(radio (const :tag "Groups first" custom-sort-groups-first)
-		(const :tag "Groups last" custom-sort-groups-last)
-		(function :tag "Other"))
-  :group 'custom-menu)
-
-(defun custom-sort-items-alphabetically (a b)
-  "Return t iff A is alphabetically before B and the same custom type.
+(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."
-  (and (eq (nth 1 a) (nth 1 b))
-       (string-lessp (symbol-name (nth 0 a)) (symbol-name (nth 0 b)))))
+  (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) ))))
 
-(defun custom-sort-groups-first (a b)
-  "Return t iff A a custom group and B is a not.
+(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."
-  (and (eq (nth 1 a) 'custom-group)
-       (not (eq (nth 1 b) 'custom-group))))
-
-(defun custom-sort-groups-last (a b)
-  "Return t iff B a custom group and A is a not.
-A and B should be members of a `custom-group' property."
-  (and (eq (nth 1 b) 'custom-group)
-       (not (eq (nth 1 a) 'custom-group))))
+  (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) )))
 
 ;;; Custom Mode Commands.
 
@@ -639,7 +652,7 @@
   (let ((children custom-options))
     (mapcar (lambda (child)
 	      (when (eq (widget-get child :custom-state) 'modified)
-		(widget-apply child :custom-reset-current)))
+		(widget-apply child :custom-reset-saved)))
 	    children)))
 
 (defun custom-reset-standard (&rest ignore)
@@ -648,7 +661,7 @@
   (let ((children custom-options))
     (mapcar (lambda (child)
 	      (when (eq (widget-get child :custom-state) 'modified)
-		(widget-apply child :custom-reset-current)))
+		(widget-apply child :custom-reset-standard)))
 	    children)))
 
 ;;; The Customize Commands
@@ -733,19 +746,23 @@
 ;;;###autoload
 (defun customize-group (group)
   "Customize GROUP, which must be a customization group."
-  (interactive (list (completing-read "Customize group: (default emacs) "
-				      obarray 
-				      (lambda (symbol)
-					(get symbol 'custom-group))
-				      t)))
+  (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))))
-  (custom-buffer-create (list (list group 'custom-group))
-			(format "*Customize Group: %s*"
-				(custom-unlispify-tag-name 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))))
 
 ;;;###autoload
 (defun customize-group-other-window (symbol)
@@ -797,10 +814,10 @@
       (let ((found nil))
 	(message "Looking for faces...")
 	(mapcar (lambda (symbol)
-		  (setq found (cons (list symbol 'custom-face) found)))
-		(nreverse (mapcar 'intern 
+		  (push (list symbol 'custom-face) found))
+		(nreverse (mapcar 'intern
 				  (sort (mapcar 'symbol-name (face-list))
-					'string<))))
+					'string-lessp))))
 			
 	(custom-buffer-create found "*Customize Faces*"))
     (if (stringp symbol)
@@ -834,11 +851,10 @@
     (mapatoms (lambda (symbol)
 		(and (get symbol 'customized-face)
 		     (custom-facep symbol)
-		     (setq found (cons (list symbol 'custom-face) found)))
+		     (push (list symbol 'custom-face) found))
 		(and (get symbol 'customized-value)
 		     (boundp symbol)
-		     (setq found
-			   (cons (list symbol 'custom-variable) found)))))
+		     (push (list symbol 'custom-variable) found))))
     (if found 
 	(custom-buffer-create found "*Customize Customized*")
       (error "No customized user options"))))
@@ -851,11 +867,10 @@
     (mapatoms (lambda (symbol)
 		(and (get symbol 'saved-face)
 		     (custom-facep symbol)
-		     (setq found (cons (list symbol 'custom-face) found)))
+		     (push (list symbol 'custom-face) found))
 		(and (get symbol 'saved-value)
 		     (boundp symbol)
-		     (setq found
-			   (cons (list symbol 'custom-variable) found)))))
+		     (push (list symbol 'custom-variable) found))))
     (if found 
 	(custom-buffer-create found "*Customize Saved*")
       (error "No saved user options"))))
@@ -863,30 +878,71 @@
 ;;;###autoload
 (defun customize-apropos (regexp &optional all)
   "Customize all user options matching REGEXP.
-If ALL (e.g., started with a prefix key), include options which are not
-user-settable."
+If ALL is `options', include only options.
+If ALL is `faces', include only faces.
+If ALL is `groups', include only groups.
+If ALL is t (interactively, with prefix arg), include options which are not
+user-settable, as well as faces and groups."
   (interactive "sCustomize regexp: \nP")
   (let ((found nil))
     (mapatoms (lambda (symbol)
 		(when (string-match regexp (symbol-name symbol))
-		  (when (get symbol 'custom-group)
-		    (setq found (cons (list symbol 'custom-group) found)))
-		  (when (custom-facep symbol)
-		    (setq found (cons (list symbol 'custom-face) found)))
-		  (when (and (boundp symbol)
+		  (when (and (not (memq all '(faces options)))
+			     (get symbol 'custom-group))
+		    (push (list symbol 'custom-group) found))
+		  (when (and (not (memq all '(options groups)))
+			     (custom-facep symbol))
+		    (push (list symbol 'custom-face) found))
+		  (when (and (not (memq all '(groups faces)))
+			     (boundp symbol)
 			     (or (get symbol 'saved-value)
 				 (get symbol 'standard-value)
-				 (if all
-				     (get symbol 'variable-documentation)
-				   (user-variable-p symbol))))
-		    (setq found
-			  (cons (list symbol 'custom-variable) found))))))
-    (if found 
-	(custom-buffer-create found "*Customize Apropos*")
-      (error "No matches"))))
+				 (if (memq all '(nil options))
+				     (user-variable-p symbol)
+				   (get symbol 'variable-documentation))))
+		    (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*")))))
+
+;;;###autoload
+(defun customize-apropos-options (regexp &optional arg)
+  "Customize all user options matching REGEXP.
+With prefix arg, include options which are not user-settable."
+  (interactive "sCustomize regexp: \nP")
+  (customize-apropos regexp (or arg 'options)))
+
+;;;###autoload
+(defun customize-apropos-faces (regexp)
+  "Customize all user faces matching REGEXP."
+  (interactive "sCustomize regexp: \n")
+  (customize-apropos regexp 'faces))
+
+;;;###autoload
+(defun customize-apropos-groups (regexp)
+  "Customize all user groups matching REGEXP."
+  (interactive "sCustomize regexp: \n")
+  (customize-apropos regexp 'groups))
 
 ;;; Buffer.
 
+(defcustom custom-buffer-style 'links
+  "Control the presentation style for customization buffers.
+The value should be a symbol, one of:
+
+brackets: groups nest within each other with big horizontal brackets.
+links: groups have links to subgroups."
+  :type '(radio (const brackets)
+		(const links))
+  :group 'custom-buffer)
+
+(defcustom custom-buffer-indent 3
+  "Number of spaces to indent nested groups."
+  :type 'integer
+  :group 'custom-buffer)
+
 ;;;###autoload
 (defun custom-buffer-create (options &optional name)
   "Create a buffer containing OPTIONS.
@@ -1002,13 +1058,90 @@
 		      options))))
   (unless (eq (preceding-char) ?\n)
     (widget-insert "\n"))
-  (message "Creating customization magic...")
-  (mapcar 'custom-magic-reset custom-options)
+  (unless (eq custom-buffer-style 'tree)
+    (mapcar 'custom-magic-reset custom-options))
   (message "Creating customization setup...")
   (widget-setup)
   (goto-char (point-min))
   (message "Creating customization buffer...done"))
 
+;;; The Tree Browser.
+
+;;;###autoload
+(defun customize-browse ()
+  "Create a tree browser for the customize hierarchy."
+  (interactive)
+  (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")
+  (let ((custom-buffer-style 'tree))
+    (widget-create 'custom-group 
+		   :custom-last t
+		   :custom-state 'unknown
+		   :tag (custom-unlispify-tag-name 'emacs)
+		   :value 'emacs))
+  (goto-char (point-min)))
+
+(define-widget 'custom-tree-visibility 'item
+  "Control visibility of of items in the customize tree browser."
+  :format "%[[%t]%]"
+  :action 'custom-tree-visibility-action)
+
+(defun custom-tree-visibility-action (widget &rest ignore)
+  (let ((custom-buffer-style 'tree))
+    (custom-toggle-parent widget)))
+
+(define-widget 'custom-tree-group-tag 'push-button
+  "Show parent in other window when activated."
+  :tag "group"
+  :tag-glyph "folder"
+  :action 'custom-tree-group-tag-action)
+
+(defun custom-tree-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
+  "Show parent in other window when activated."
+  :tag "option"
+  :tag-glyph "option"
+  :action 'custom-tree-variable-tag-action)
+
+(defun custom-tree-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
+  "Show parent in other window when activated."
+  :tag "face"
+  :tag-glyph "face"
+  :action 'custom-tree-face-tag-action)
+
+(defun custom-tree-face-tag-action (widget &rest ignore)
+  (let ((parent (widget-get widget :parent)))
+    (customize-face-other-window (widget-value parent))))
+
+(defconst custom-tree-alist '(("   " "space")
+			      (" | " "vertical")
+			      (" |-" "middle")
+			      (" `-" "bottom")))
+
+(defun custom-tree-insert (prefix)
+  "Insert PREFIX.  On XEmacs convert it to line graphics."
+  (if nil ;(string-match "XEmacs" emacs-version)
+      (while (not (string-equal prefix ""))
+	(let ((entry (substring prefix 0 3)))
+	  (setq prefix (substring prefix 3))
+	  (widget-specify-insert
+	   (widget-glyph-insert nil entry
+				(nth 1 (assoc entry custom-tree-alist))))))
+    (insert prefix)))
+
 ;;; Modification of Basic Widgets.
 ;;
 ;; We add extra properties to the basic widgets needed here.  This is
@@ -1086,8 +1219,8 @@
 			       (unknown "?" italic "\
 unknown, you should not see this.")
 			       (hidden "-" default "\
-hidden, invoke the dots above to show." "\
-group now hidden, invoke the dots above to show contents.")
+hidden, invoke \"Show\" in the previous line to show." "\
+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 "\
@@ -1206,6 +1339,9 @@
 	       (or (not hidden)
 		   (memq category custom-magic-show-hidden)))
       (insert "   ")
+      (when (eq category 'group)
+	(insert-char ?\  (* custom-buffer-indent
+			    (widget-get parent :custom-level))))
       (push (widget-create-child-and-convert 
 	     widget 'choice-item 
 	     :help-echo "Change the state of this item."
@@ -1222,6 +1358,9 @@
       (when lisp 
 	(insert " (lisp)"))
       (insert "\n"))
+    (when (eq category 'group)
+      (insert-char ?\  (* custom-buffer-indent
+			  (widget-get parent :custom-level))))
     (when custom-magic-show-button
       (when custom-magic-show
 	(let ((indent (widget-get parent :indent)))
@@ -1251,9 +1390,10 @@
 
 (define-widget 'custom 'default
   "Customize a user option."
+  :format "%v"
   :convert-widget 'custom-convert-widget
-  :format-handler 'custom-format-handler
   :notify 'custom-notify
+  :custom-prefix ""
   :custom-level 1
   :custom-state 'hidden
   :documentation-property 'widget-subclass-responsibility
@@ -1273,72 +1413,6 @@
       (widget-put widget :args nil)))
   widget)
 
-(defun custom-format-handler (widget escape)
-  ;; We recognize extra escape sequences.
-  (let* ((buttons (widget-get widget :buttons))
-	 (state (widget-get widget :custom-state))
-	 (level (widget-get widget :custom-level)))
-    (cond ((eq escape ?l)
-	   (when level 
-	     (insert-char ?\  (1- level))
-	     (if (eq state 'hidden)
-		 (insert-char ?- (1+ level))
-	       (insert "/")
-	       (insert-char ?- level))))
-	  ((eq escape ?e)
-	   (when (and level (not (eq state 'hidden)))
-	     (insert "\n")
-	     (insert-char ?\  (1- level))
-	     (insert "\\")
-	     (insert-char ?-  level)
-	     (insert " " (widget-get widget :tag) " group end ")
-	     (insert-char ?- (- 75 (current-column) level))
-	     (insert "/\n")))
-	  ((eq escape ?-)
-	   (when (and level (not (eq state 'hidden)))
-	     (insert-char ?- (- 76 (current-column) level))
-	     (insert "\\")))
-	  ((eq escape ?L)
-	   (push (widget-create-child-and-convert
-		  widget 'visibility
-		  :action 'custom-toggle-parent
-		  (not (eq state 'hidden)))
-		 buttons))
-	  ((eq escape ?m)
-	   (and (eq (preceding-char) ?\n)
-		(widget-get widget :indent)
-		(insert-char ?  (widget-get widget :indent)))
-	   (let ((magic (widget-create-child-and-convert
-			 widget 'custom-magic nil)))
-	     (widget-put widget :custom-magic magic)
-	     (push magic buttons)
-	     (widget-put widget :buttons buttons)))
-	  ((eq escape ?a)
-	   (unless (eq state 'hidden)
-	     (let* ((symbol (widget-get widget :value))
-		    (links (get symbol 'custom-links))
-		    (many (> (length links) 2)))
-	       (when links
-		 (and (eq (preceding-char) ?\n)
-		      (widget-get widget :indent)
-		      (insert-char ?  (widget-get widget :indent)))
-		 (insert "See also ")
-		 (while links
-		   (push (widget-create-child-and-convert widget (car links))
-			 buttons)
-		   (setq links (cdr links))
-		   (cond ((null links)
-			  (insert ".\n"))
-			 ((null (cdr links))
-			  (if many
-			      (insert ", and ")
-			    (insert " and ")))
-			 (t 
-			  (insert ", "))))
-		 (widget-put widget :buttons buttons)))))
-	  (t 
-	   (widget-default-format-handler widget escape)))))
-
 (defun custom-notify (widget &rest args)
   "Keep track of changes."
   (let ((state (widget-get widget :custom-state)))
@@ -1371,11 +1445,12 @@
   "Redraw WIDGET state with current settings."
   (while widget 
     (let ((magic (widget-get widget :custom-magic)))
-      (unless magic 
-	(debug))
-      (widget-value-set magic (widget-value magic))
-      (when (setq widget (widget-get widget :group))
-	(custom-group-state-update widget))))
+      (cond (magic 
+	     (widget-value-set magic (widget-value magic))
+	     (when (setq widget (widget-get widget :group))
+	       (custom-group-state-update widget)))
+	    (t
+	     (setq widget nil)))))
   (widget-setup))
 
 (defun custom-show (widget value)
@@ -1430,12 +1505,64 @@
 	  (t 
 	   (widget-put widget :documentation-shown nil)
 	   (widget-put widget :custom-state 'hidden)))
-    (custom-redraw widget)))
+    (custom-redraw widget)
+    (widget-setup)))
 
 (defun custom-toggle-parent (widget &rest ignore)
   "Toggle visibility of parent to WIDGET."
   (custom-toggle-hide (widget-get widget :parent)))
 
+(defun custom-add-see-also (widget &optional prefix)
+  "Add `See also ...' to WIDGET if there are any links.
+Insert PREFIX first if non-nil."
+  (let* ((symbol (widget-get widget :value))
+	 (links (get symbol 'custom-links))
+	 (many (> (length links) 2))
+	 (buttons (widget-get widget :buttons))
+	 (indent (widget-get widget :indent)))
+    (when links
+      (when indent
+	(insert-char ?\  indent))
+      (when prefix
+	(insert prefix))
+      (insert "See also ")
+      (while links
+	(push (widget-create-child-and-convert widget (car links))
+	      buttons)
+	(setq links (cdr links))
+	(cond ((null links)
+	       (insert ".\n"))
+	      ((null (cdr links))
+	       (if many
+		   (insert ", and ")
+		 (insert " and ")))
+	      (t 
+	       (insert ", "))))
+      (widget-put widget :buttons buttons))))
+
+(defun custom-add-parent-links (widget)
+  "Add `Parent groups: ...' to WIDGET."
+  (let ((name (widget-value widget))
+	(type (widget-type widget))
+	(buttons (widget-get widget :buttons))
+	found)
+    (insert "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))))))
+    (widget-put widget :buttons buttons)
+    (unless found
+      (insert " (none)"))
+    (insert "\n")))
+
 ;;; The `custom-variable' Widget.
 
 (defface custom-variable-sample-face '((t (:underline t)))
@@ -1448,7 +1575,7 @@
 
 (define-widget 'custom-variable 'custom
   "Customize variable."
-  :format "%v%m%h%a"
+  :format "%v"
   :help-echo "Set or reset this variable."
   :documentation-property 'variable-documentation
   :custom-category 'option
@@ -1491,6 +1618,8 @@
 	 (type (custom-variable-type symbol))
 	 (conv (widget-convert type))
 	 (get (or (get symbol 'custom-get) 'default-value))
+	 (prefix (widget-get widget :custom-prefix))
+	 (last (widget-get widget :custom-last))
 	 (value (if (default-boundp symbol)
 		    (funcall get symbol)
 		  (widget-get conv :value))))
@@ -1506,7 +1635,14 @@
 	;; (widget-apply (widget-convert type) :match value)
 	(setq form 'lisp)))
     ;; Now we can create the child widget.
-    (cond ((eq state 'hidden)
+    (cond ((eq custom-buffer-style 'tree)
+	   (insert prefix (if last " `--- " " |--- "))
+	   (push (widget-create-child-and-convert
+		  widget 'custom-tree-variable-tag)
+		 buttons)
+	   (insert " " tag "\n")
+	   (widget-put widget :buttons buttons))
+	  ((eq state 'hidden)
 	   ;; Indicate hidden value.
 	   (push (widget-create-child-and-convert 
 		  widget 'item
@@ -1517,6 +1653,7 @@
 		 buttons)
 	   (push (widget-create-child-and-convert 
 		  widget 'visibility
+		  :help-echo "Show the value of this option."
 		  :action 'custom-toggle-parent
 		  nil)
 		 buttons))
@@ -1532,10 +1669,11 @@
 				(custom-quote (widget-get conv :value))))))
 	     (insert (symbol-name symbol) ": ")
 	     (push (widget-create-child-and-convert 
-		  widget 'visibility
-		  :action 'custom-toggle-parent
-		  t)
-		 buttons)
+		    widget 'visibility
+		    :help-echo "Hide the value of this option."
+		    :action 'custom-toggle-parent
+		    t)
+		   buttons)
 	     (insert " ")
 	     (push (widget-create-child-and-convert 
 		    widget 'sexp 
@@ -1557,6 +1695,7 @@
 		    widget 'item 
 		    :format tag-format
 		    :action 'custom-tag-action
+		    :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
@@ -1565,6 +1704,7 @@
 	     (insert " ")
 	     (push (widget-create-child-and-convert 
 		  widget 'visibility
+		  :help-echo "Hide the value of this option."
 		  :action 'custom-toggle-parent
 		  t)
 		 buttons)	     
@@ -1573,15 +1713,29 @@
 		    :format value-format
 		    :value value)
 		   children))))
-    ;; Now update the state.
-    (unless (eq (preceding-char) ?\n)
-      (widget-insert "\n"))
-    (if (eq state 'hidden)
-	(widget-put widget :custom-state state)
-      (custom-variable-state-set widget))
-    (widget-put widget :custom-form form)	     
-    (widget-put widget :buttons buttons)
-    (widget-put widget :children children)))
+    (unless (eq custom-buffer-style 'tree)
+      ;; Now update the state.
+      (unless (eq (preceding-char) ?\n)
+	(widget-insert "\n"))
+      (if (eq state 'hidden)
+	  (widget-put widget :custom-state state)
+	(custom-variable-state-set widget))
+      ;; Create the magic button.
+      (let ((magic (widget-create-child-and-convert
+		    widget 'custom-magic nil)))
+	(widget-put widget :custom-magic magic)
+	(push magic buttons))
+      ;; Update properties.
+      (widget-put widget :custom-form form)	     
+      (widget-put widget :buttons buttons)
+      (widget-put widget :children children)
+      ;; Insert documentation.
+      (widget-default-format-handler widget ?h)
+      ;; See also.
+      (unless (eq state 'hidden)
+	(when (eq (widget-get widget :custom-level) 1)
+	  (custom-add-parent-links widget))
+	(custom-add-see-also widget)))))
 
 (defun custom-tag-action (widget &rest args)
   "Pass :action to first child of WIDGET's parent."
@@ -1623,13 +1777,7 @@
     (widget-put widget :custom-state state)))
 
 (defvar custom-variable-menu 
-  '(("Edit" custom-variable-edit 
-     (lambda (widget)
-       (not (eq (widget-get widget :custom-form) 'edit))))
-    ("Edit Lisp" custom-variable-edit-lisp
-     (lambda (widget)
-       (not (eq (widget-get widget :custom-form) 'lisp))))
-    ("Set" custom-variable-set
+  '(("Set" custom-variable-set
      (lambda (widget)
        (eq (widget-get widget :custom-state) 'modified)))
     ("Save" custom-variable-save
@@ -1648,7 +1796,14 @@
      (lambda (widget)
        (and (get (widget-value widget) 'standard-value)
 	    (memq (widget-get widget :custom-state)
-		  '(modified set changed saved rogue))))))
+		  '(modified set changed saved rogue)))))
+    ("---" 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
+     (lambda (widget)
+       (not (eq (widget-get widget :custom-form) 'lisp)))))
   "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
@@ -1856,8 +2011,6 @@
 
 (define-widget 'custom-face 'custom
   "Customize face."
-  :format "%{%t%}: %s %L\n%m%h%a%v"
-  :format-handler 'custom-face-format-handler
   :sample-face 'custom-face-tag-face
   :help-echo "Set or reset this face."
   :documentation-property '(lambda (face)
@@ -1873,26 +2026,6 @@
   :custom-reset-standard 'custom-face-reset-standard
   :custom-menu 'custom-face-menu-create)
 
-(defun custom-face-format-handler (widget escape)
-  ;; We recognize extra escape sequences.
-  (let (child
-	(symbol (widget-get widget :value)))
-    (cond ((eq escape ?s)
-	   (and (string-match "XEmacs" emacs-version)
-		;; XEmacs cannot display initialized faces.
-		(not (custom-facep symbol))
-		(copy-face 'custom-face-empty symbol))
-	   (setq child (widget-create-child-and-convert 
-			widget 'item
-			:format "(%{%t%})"
-			:sample-face symbol
-			:tag "sample")))
-	  (t 
-	   (custom-format-handler widget escape)))
-    (when child
-      (widget-put widget
-		  :buttons (cons child (widget-get widget :buttons))))))
-
 (define-widget 'custom-face-all 'editable-list 
   "An editable list of display specifications and attributes."
   :entry-format "%i %d %v"
@@ -1926,55 +2059,115 @@
   "Converted version of the `custom-face-selected' widget.")
 
 (defun custom-face-value-create (widget)
-  ;; Create a list of the display specifications.
-  (unless (eq (preceding-char) ?\n)
-    (insert "\n"))
-  (when (not (eq (widget-get widget :custom-state) 'hidden))
-    (message "Creating face editor...")
-    (custom-load-widget widget)
-    (let* ((symbol (widget-value widget))
-	   (spec (or (get symbol 'saved-face)
-		     (get symbol 'face-defface-spec)
-		     ;; Attempt to construct it.
-		     (list (list t (custom-face-attributes-get 
-				    symbol (selected-frame))))))
-	   (form (widget-get widget :custom-form))
-	   (indent (widget-get widget :indent))
-	   (edit (widget-create-child-and-convert
-		  widget
-		  (cond ((and (eq form 'selected)
-			      (widget-apply custom-face-selected :match spec))
-			 (when indent (insert-char ?\  indent))
-			 'custom-face-selected)
-			((and (not (eq form 'lisp))
-			      (widget-apply custom-face-all :match spec))
-			 'custom-face-all)
-			(t 
-			 (when indent (insert-char ?\  indent))
-			 'sexp))
-		  :value spec)))
-      (custom-face-state-set widget)
-      (widget-put widget :children (list edit)))
-    (message "Creating face editor...done")))
+  "Create a list of the display specifications for WIDGET."
+  (let ((buttons (widget-get widget :buttons))
+	(symbol (widget-get widget :value))
+	(tag (widget-get widget :tag))
+	(state (widget-get widget :custom-state))
+	(begin (point))
+	(is-last (widget-get widget :custom-last))
+	(prefix (widget-get widget :custom-prefix)))
+    (unless tag
+      (setq tag (prin1-to-string symbol)))
+    (cond ((eq custom-buffer-style 'tree)
+	   (insert prefix (if is-last " `--- " " |--- "))
+	   (push (widget-create-child-and-convert
+		  widget 'custom-tree-face-tag)
+		 buttons)
+	   (insert " " tag "\n")
+	   (widget-put widget :buttons buttons))
+	  (t
+	   ;; Create tag.
+	   (insert tag)
+	   (if (eq custom-buffer-style 'face)
+	       (insert " ")
+	     (widget-specify-sample widget begin (point))
+	     (insert ": "))
+	   ;; Sample.
+	   (and (string-match "XEmacs" emacs-version)
+		;; XEmacs cannot display uninitialized faces.
+		(not (custom-facep symbol))
+		(copy-face 'custom-face-empty symbol))
+	   (push (widget-create-child-and-convert widget 'item
+						  :format "(%{%t%})"
+						  :sample-face symbol
+						  :tag "sample")
+		 buttons)
+	   ;; Visibility.
+	   (insert " ")
+	   (push (widget-create-child-and-convert 
+		  widget 'visibility
+		  :help-echo "Hide or show this face."
+		  :action 'custom-toggle-parent
+		  (not (eq state 'hidden)))
+		 buttons)
+	   ;; Magic.
+	   (insert "\n")
+	   (let ((magic (widget-create-child-and-convert
+			 widget 'custom-magic nil)))
+	     (widget-put widget :custom-magic magic)
+	     (push magic buttons))
+	   ;; Update buttons.
+	   (widget-put widget :buttons buttons)
+	   ;; Insert documentation.
+	   (widget-default-format-handler widget ?h)
+	   ;; See also.
+	   (unless (eq state 'hidden)
+	     (when (eq (widget-get widget :custom-level) 1)
+	       (custom-add-parent-links widget))
+	     (custom-add-see-also widget))
+	   ;; Editor.
+	   (unless (eq (preceding-char) ?\n)
+	     (insert "\n"))
+	   (unless (eq state 'hidden)
+	     (message "Creating face editor...")
+	     (custom-load-widget widget)
+	     (let* ((symbol (widget-value widget))
+		    (spec (or (get symbol 'saved-face)
+			      (get symbol 'face-defface-spec)
+			      ;; Attempt to construct it.
+			      (list (list t (custom-face-attributes-get 
+					     symbol (selected-frame))))))
+		    (form (widget-get widget :custom-form))
+		    (indent (widget-get widget :indent))
+		    (edit (widget-create-child-and-convert
+			   widget
+			   (cond ((and (eq form 'selected)
+				       (widget-apply custom-face-selected 
+						     :match spec))
+				  (when indent (insert-char ?\  indent))
+				  'custom-face-selected)
+				 ((and (not (eq form 'lisp))
+				       (widget-apply custom-face-all
+						     :match spec))
+				  'custom-face-all)
+				 (t 
+				  (when indent (insert-char ?\  indent))
+				  'sexp))
+			   :value spec)))
+	       (custom-face-state-set widget)
+	       (widget-put widget :children (list edit)))
+	     (message "Creating face editor...done"))))))
 
 (defvar custom-face-menu 
-  '(("Edit Selected" custom-face-edit-selected
-     (lambda (widget)
-       (not (eq (widget-get widget :custom-form) 'selected))))
-    ("Edit All" custom-face-edit-all
-     (lambda (widget)
-       (not (eq (widget-get widget :custom-form) 'all))))
-    ("Edit Lisp" custom-face-edit-lisp
-     (lambda (widget)
-       (not (eq (widget-get widget :custom-form) 'lisp))))
-    ("Set" custom-face-set)
+  '(("Set" custom-face-set)
     ("Save" custom-face-save)
     ("Reset to Saved" custom-face-reset-saved
      (lambda (widget)
        (get (widget-value widget) 'saved-face)))
     ("Reset to Standard Setting" custom-face-reset-standard
      (lambda (widget)
-       (get (widget-value widget) 'face-defface-spec))))
+       (get (widget-value widget) 'face-defface-spec)))
+    ("---" ignore ignore)
+    ("Show all display specs" custom-face-edit-all
+     (lambda (widget)
+       (not (eq (widget-get widget :custom-form) 'all))))
+    ("Just current attributes" custom-face-edit-selected
+     (lambda (widget)
+       (not (eq (widget-get widget :custom-form) 'selected))))
+    ("Show as Lisp expression" custom-face-edit-lisp
+     (lambda (widget)
+       (not (eq (widget-get widget :custom-form) 'lisp)))))
   "Alist of actions for the `custom-face' 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
@@ -2082,7 +2275,9 @@
 (define-widget 'face 'default
   "Select and customize a face."
   :convert-widget 'widget-value-convert-widget
-  :format "%[%t%]: %v"
+  :button-prefix 'widget-push-button-prefix
+  :button-suffix 'widget-push-button-suffix
+  :format "%t: %[select face%] %v"
   :tag "Face"
   :value 'default
   :value-create 'widget-face-value-create
@@ -2095,9 +2290,9 @@
 (defun widget-face-value-create (widget)
   ;; Create a `custom-face' child.
   (let* ((symbol (widget-value widget))
+	 (custom-buffer-style 'face)
 	 (child (widget-create-child-and-convert
 		 widget 'custom-face
-		 :format "%t %s %L\n%m%h%v"
 		 :custom-level nil
 		 :value symbol)))
     (custom-magic-reset child)
@@ -2149,6 +2344,16 @@
     (widget-put widget :args args)
     widget))
 
+;;; The `custom-group-link' Widget.
+
+(define-widget 'custom-group-link 'link
+  "Show parent in other window when activated."
+  :help-echo "Create customize buffer for this group group."
+  :action 'custom-group-link-action)
+
+(defun custom-group-link-action (widget &rest ignore)
+  (customize-group (widget-value widget)))
+
 ;;; The `custom-group' Widget.
 
 (defcustom custom-group-tag-faces '(custom-group-tag-face-1)
@@ -2181,7 +2386,7 @@
 
 (define-widget 'custom-group 'custom
   "Customize group."
-  :format "%l %{%t%} group: %L %-\n%m%h%a%v%e"
+  :format "%v"
   :sample-face-get 'custom-group-sample-face-get
   :documentation-property 'group-documentation
   :help-echo "Set or reset all members of this group."
@@ -2201,42 +2406,209 @@
       'custom-group-tag-face))
 
 (defun custom-group-value-create (widget)
-  (let ((state (widget-get widget :custom-state)))
-    (unless (eq state 'hidden)
-      (message "Creating group...")
-      (custom-load-widget widget)
-      (let* ((level (widget-get widget :custom-level))
-	     (symbol (widget-value widget))
-	     (members (sort (sort (copy-sequence (get symbol 'custom-group))
-				  custom-buffer-sort-predicate)
-			    custom-buffer-order-predicate))
-	     (prefixes (widget-get widget :custom-prefixes))
-	     (custom-prefix-list (custom-prefix-add symbol prefixes))
-	     (length (length members))
-	     (count 0)
-	     (children (mapcar (lambda (entry)
-				 (widget-insert "\n")
-				 (message "Creating group members... %2d%%"
-					  (/ (* 100.0 count) length))
-				 (setq count (1+ count))
-				 (prog1
-				     (widget-create-child-and-convert
-				      widget (nth 1 entry)
-				      :group widget
-				      :tag (custom-unlispify-tag-name
-					    (nth 0 entry))
-				      :custom-prefixes custom-prefix-list
-				      :custom-level (1+ level)
-				      :value (nth 0 entry))
-				   (unless (eq (preceding-char) ?\n)
-				     (widget-insert "\n"))))
-			       members)))
-	(message "Creating group magic...")
-	(mapcar 'custom-magic-reset children)
-	(message "Creating group state...")
-	(widget-put widget :children children)
-	(custom-group-state-update widget)
-	(message "Creating group... done")))))
+  "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)))
+    (cond ((and (eq custom-buffer-style 'tree)
+		(eq state 'hidden))
+	   (custom-tree-insert prefix)
+	   (push (widget-create-child-and-convert
+		  widget 'custom-tree-visibility 
+		  ;; :tag-glyph "plus"
+		  :tag "+")
+		 buttons)
+	   (insert "-- ")
+	   ;; (widget-glyph-insert nil "-- " "horizontal")
+	   (push (widget-create-child-and-convert
+		  widget 'custom-tree-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)
+	   (insert "[ ]-- ")
+	   ;; (widget-glyph-insert nil "[ ]" "empty")
+	   ;; (widget-glyph-insert nil "-- " "horizontal")
+	   (push (widget-create-child-and-convert 
+		  widget 'custom-tree-group-tag)
+		 buttons)
+	   (insert " " tag "\n")
+	   (widget-put widget :buttons buttons))
+	  ((eq custom-buffer-style 'tree)
+	   (custom-tree-insert prefix)
+	   (custom-load-widget widget)
+	   (if (zerop (length (get symbol 'custom-group)))
+	       (progn 
+		 (custom-tree-insert prefix)
+		 (insert "[ ]-- ")
+		 ;; (widget-glyph-insert nil "[ ]" "empty")
+		 ;; (widget-glyph-insert nil "-- " "horizontal")
+		 (push (widget-create-child-and-convert 
+			widget 'custom-tree-group-tag)
+		       buttons)
+		 (insert " " tag "\n")
+		 (widget-put widget :buttons buttons))
+	     (push (widget-create-child-and-convert 
+		    widget 'custom-tree-visibility 
+		    ;; :tag-glyph "minus"
+		    :tag "-")
+		   buttons)
+	     (insert "-+ ")
+	     ;; (widget-glyph-insert nil "-+ " "top")
+	     (push (widget-create-child-and-convert 
+		    widget 'custom-tree-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))
+		    (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)
+				      "   "
+				    " | "))
+		    (prefix (concat prefix extra-prefix))
+		    children entry)
+	       (while members
+		 (setq entry (car members)
+		       members (cdr members))
+		 (push (widget-create-child-and-convert
+			widget (nth 1 entry)
+			:group widget
+			:tag (custom-unlispify-tag-name
+			      (nth 0 entry))
+			:custom-prefixes custom-prefix-list
+			:custom-level (1+ level)
+			:custom-last (null members)
+			:value (nth 0 entry)
+			:custom-prefix prefix)
+		       children))
+	       (widget-put widget :children (reverse children)))
+	     (message "Creating group...done")))
+	  ;; Nested style.
+	  ((eq state 'hidden)
+	   ;; Create level indicator.
+	   (insert-char ?\  (* custom-buffer-indent (1- level)))
+	   (insert "-- ")
+	   ;; Create tag.
+	   (let ((begin (point)))
+	     (insert tag)
+	     (widget-specify-sample widget begin (point)))
+	   (insert " group: ")
+	   ;; Create link/visibility indicator.
+	   (if (eq custom-buffer-style 'links)
+	       (push (widget-create-child-and-convert
+		      widget 'custom-group-link 
+		      :tag "Show"
+		      symbol)
+		     buttons)
+	     (push (widget-create-child-and-convert 
+		    widget 'visibility
+		    :help-echo "Show members of this group."
+		    :action 'custom-toggle-parent
+		    (not (eq state 'hidden)))
+		   buttons))
+	   (insert " \n")
+	   ;; Create magic button.
+	   (let ((magic (widget-create-child-and-convert
+			 widget 'custom-magic nil)))
+	     (widget-put widget :custom-magic magic)
+	     (push magic buttons))
+	   ;; Update buttons.
+	   (widget-put widget :buttons buttons)
+	   ;; Insert documentation.
+	   (widget-default-format-handler widget ?h))
+	  ;; Nested style.
+	  (t				;Visible.
+	   ;; Create level indicator.
+	   (insert-char ?\  (* custom-buffer-indent (1- level)))
+	   (insert "/- ")
+	   ;; Create tag.
+	   (let ((start (point)))
+	     (insert tag)
+	     (widget-specify-sample widget start (point)))
+	   (insert " group: ")
+	   ;; Create visibility indicator.
+	   (unless (eq custom-buffer-style 'links)
+	     (insert "--------")
+	     (push (widget-create-child-and-convert 
+		    widget 'visibility
+		    :help-echo "Hide members of this group."
+		    :action 'custom-toggle-parent
+		    (not (eq state 'hidden)))
+		   buttons)
+	     (insert " "))
+	   ;; Create more dashes.
+	   ;; Use 76 instead of 75 to compensate for the temporary "<"
+	   ;; added by `widget-insert'.  
+	   (insert-char ?- (- 76 (current-column)
+			      (* custom-buffer-indent level)))
+	   (insert "\\\n")
+	   ;; Create magic button.
+	   (let ((magic (widget-create-child-and-convert
+			 widget 'custom-magic 
+			 :indent 0
+			 nil)))
+	     (widget-put widget :custom-magic magic)
+	     (push magic buttons))
+	   ;; Update buttons.
+	   (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))
+	   (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))
+		  (prefixes (widget-get widget :custom-prefixes))
+		  (custom-prefix-list (custom-prefix-add symbol prefixes))
+		  (length (length members))
+		  (count 0)
+		  (children (mapcar (lambda (entry)
+				      (widget-insert "\n")
+				      (message "\
+Creating group members... %2d%%"
+					       (/ (* 100.0 count) length))
+				      (setq count (1+ count))
+				      (prog1
+					  (widget-create-child-and-convert
+					   widget (nth 1 entry)
+					   :group widget
+					   :tag (custom-unlispify-tag-name
+						 (nth 0 entry))
+					   :custom-prefixes custom-prefix-list
+					   :custom-level (1+ level)
+					   :value (nth 0 entry))
+					(unless (eq (preceding-char) ?\n)
+					  (widget-insert "\n"))))
+				    members)))
+	     (message "Creating group magic...")
+	     (mapcar 'custom-magic-reset children)
+	     (message "Creating group state...")
+	     (widget-put widget :children children)
+	     (custom-group-state-update widget)
+	     (message "Creating group... done"))
+	   ;; End line
+	   (insert "\n")
+	   (insert-char ?\  (* custom-buffer-indent (1- level)))
+	   (insert "\\- " (widget-get widget :tag) " group end ")
+	   (insert-char ?- (- 75 (current-column) (* custom-buffer-indent level)))
+	   (insert "/\n")))))
 
 (defvar custom-group-menu 
   '(("Set" custom-group-set
@@ -2337,8 +2709,10 @@
   (custom-magic-reset widget))
 
 ;;; The `custom-save-all' Function.
-
-(defcustom custom-file "~/.emacs"
+;;;###autoload
+(defcustom custom-file (if (featurep 'xemacs)
+			   "~/.xemacs-custom"
+			 "~/.emacs")
   "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."
@@ -2462,14 +2836,19 @@
 ;;; 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]
-			       ["Apropos..." customize-apropos t])
+  (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")
 
@@ -2549,9 +2928,8 @@
 	     (< (length (get symbol 'custom-group)) widget-menu-max-size))
 	(let ((custom-prefix-list (custom-prefix-add symbol
 						     custom-prefix-list))
-	      (members (sort (sort (copy-sequence (get symbol 'custom-group))
-				   custom-menu-sort-predicate)
-			     custom-menu-order-predicate)))
+	      (members (sort (copy-sequence (get symbol 'custom-group))
+			     'custom-menu-sort-predicate)))
 	  (custom-load-symbol symbol)
 	  `(,(custom-unlispify-menu-entry symbol t)
 	    ,item
@@ -2591,15 +2969,11 @@
   (suppress-keymap custom-mode-map)
   (define-key custom-mode-map "q" 'bury-buffer))
 
-(easy-menu-define custom-mode-customize-menu 
-    custom-mode-map
-  "Menu used to customize customization buffers."
-  (customize-menu-create 'customize))
-
 (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]
@@ -2633,7 +3007,6 @@
   (setq major-mode 'custom-mode
 	mode-name "Custom")
   (use-local-map custom-mode-map)
-  (easy-menu-add custom-mode-customize-menu)
   (easy-menu-add custom-mode-menu)
   (make-local-variable 'custom-options)
   (run-hooks 'custom-mode-hook))