]> code.delx.au - gnu-emacs/blobdiff - lisp/cus-edit.el
* faces.el (secondary-selection): Change background to yellow.
[gnu-emacs] / lisp / cus-edit.el
index e10db897f9fc521f93e3f230c9e2c49afe8337f8..5f876b66dce16fe0488684bff953a25e4efa58b9 100644 (file)
@@ -1,11 +1,10 @@
 ;;; cus-edit.el --- Tools for customizating Emacs and Lisp packages.
 ;;
-;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc.
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Keywords: help, faces
-;; Version: 1.9954
-;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
+;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ (probably obsolete)
 
 ;; This file is part of GNU Emacs.
 
@@ -39,7 +38,9 @@
 (require 'cus-face)
 (require 'wid-edit)
 (require 'easymenu)
-(eval-when-compile (require 'cl))
+(eval-when-compile
+  (require 'cl)
+  (defvar custom-versions-load-alist)) ; from cus-load
 
 (condition-case nil
     (require 'cus-load)
     (require 'cus-start)
   (error nil))
 
-(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 
-  :custom-reset-standard)
-
 (put 'custom-define-hook 'custom-type 'hook)
 (put 'custom-define-hook 'standard-value '(nil))
 (custom-add-to-group 'customize 'custom-define-hook 'custom-variable)
   :group 'external
   :group 'development)
 
+(defgroup convenience nil
+  "Convenience features for faster editing."
+  :group 'emacs)
+
 (defgroup programming nil
   "Support for programming in other languages."
   :group 'emacs)
   "Support for on-line help systems."
   :group 'emacs)
 
+(defgroup multimedia nil
+  "Non-textual support, specifically images and sound."
+  :group 'emacs)
+
 (defgroup local nil
   "Code local to your site."
   :group 'emacs)
 
 (defgroup customize '((widgets custom-group))
   "Customization of the Customization support."
-  :link '(custom-manual "(custom)Top")
-  :link '(url-link :tag "Development Page" 
+  :link '(custom-manual "(elisp)Customization")
+  :link '(url-link :tag "(Old?) Development Page"
                   "http://www.dina.kvl.dk/~abraham/custom/")
   :prefix "custom-"
   :group 'help)
 
 ;;; 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))
@@ -374,14 +364,16 @@ With optional argument N, returns Nth-to-last link (default 1)."
               (memq (car sexp) '(lambda)))
          (stringp sexp)
          (numberp sexp)
-         (and (fboundp 'characterp)
-              (characterp sexp)))
+         (vectorp sexp)
+;;;      (and (fboundp 'characterp)
+;;;           (characterp sexp))
+         )
       sexp
     (list 'quote sexp)))
 
 (defun custom-split-regexp-maybe (regexp)
   "If REGEXP is a string, split it to a list at `\\|'.
-You can get the original back with from the result with: 
+You can get the original back with from the result with:
   (mapconcat 'identity result \"\\|\")
 
 IF REGEXP is not a string, return it unchanged."
@@ -401,14 +393,15 @@ Return a list suitable for use in `interactive'."
    (let ((v (variable-at-point))
         (enable-recursive-minibuffers t)
         val)
-     (setq val (completing-read 
+     (setq val (completing-read
                (if (symbolp v)
                    (format "Customize option: (default %s) " v)
                  "Customize variable: ")
                obarray (lambda (symbol)
                          (and (boundp symbol)
                               (or (get symbol 'custom-type)
-                                  (user-variable-p symbol))))))
+                                  (get symbol 'custom-loads)
+                                  (user-variable-p symbol)))) t))
      (list (if (equal val "")
               (if (symbolp v) v nil)
             (intern val)))))
@@ -419,7 +412,7 @@ MENU should be in the same format as `custom-variable-menu'.
 WIDGET is the widget to apply the filter entries of MENU on."
   (let ((result nil)
        current name action filter)
-    (while menu 
+    (while menu
       (setq current (car menu)
            name (nth 0 current)
            action (nth 1 current)
@@ -469,13 +462,13 @@ WIDGET is the widget to apply the filter entries of MENU on."
                 (while prefixes
                   (setq prefix (car prefixes))
                   (if (search-forward prefix (+ (point) (length prefix)) t)
-                      (progn 
+                      (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 
+          (unless no-suffix
             (goto-char (point-max))
             (insert "..."))
           (buffer-string)))))
@@ -509,10 +502,10 @@ WIDGET is the widget to apply the filter entries of MENU on."
     ("-alist\\'" (repeat (cons sexp sexp))))
   "Alist of (MATCH TYPE).
 
-MATCH should be a regexp matching the name of a symbol, and TYPE should 
+MATCH should be a regexp matching the name of a symbol, and TYPE should
 be a widget suitable for editing the value of that symbol.  The TYPE
 of the first entry where MATCH matches the name of the symbol will be
-used. 
+used.
 
 This is used for guessing the type of variables not declared with
 customize."
@@ -535,7 +528,7 @@ customize."
 
 (defun custom-guess-type (symbol)
   "Guess a widget suitable for editing the value of SYMBOL.
-This is done by matching SYMBOL with `custom-guess-name-alist' and 
+This is done by matching SYMBOL with `custom-guess-name-alist' and
 if that fails, the doc string with `custom-guess-doc-alist'."
   (let ((name (symbol-name symbol))
        (names custom-guess-name-alist)
@@ -549,7 +542,7 @@ if that fails, the doc string with `custom-guess-doc-alist'."
     (unless found
       (let ((doc (documentation-property symbol 'variable-documentation))
            (docs custom-guess-doc-alist))
-       (when doc 
+       (when doc
          (while docs
            (setq current (car docs)
                  docs (cdr docs))
@@ -607,6 +600,8 @@ If `last', order groups after non-groups."
                 (const :tag "none" nil))
   :group 'custom-menu)
 
+;;;###autoload (add-hook 'same-window-regexps "\\`\\*Customiz.*\\*\\'")
+
 (defun custom-sort-items (items sort-alphabetically order-groups)
   "Return a sorted copy of ITEMS.
 ITEMS should be a `custom-group' property.
@@ -653,12 +648,13 @@ groups after non-groups, if nil do not order groups at all."
   (interactive)
   (let ((children custom-options))
     (mapcar (lambda (child)
-             (when (memq (widget-get child :custom-state) '(modified set))
+             (when (memq (widget-get child :custom-state)
+                         '(modified set changed rogue))
                (widget-apply child :custom-save)))
            children))
   (custom-save-all))
 
-(defvar custom-reset-menu 
+(defvar custom-reset-menu
   '(("Current" . Custom-reset-current)
     ("Saved" . Custom-reset-saved)
     ("Standard Settings" . Custom-reset-standard))
@@ -680,32 +676,38 @@ when the action is chosen.")
   "Reset all modified group members to their current value."
   (interactive)
   (let ((children custom-options))
-    (mapcar (lambda (child)
-             (when (eq (widget-get child :custom-state) 'modified)
-               (widget-apply child :custom-reset-current)))
+    (mapcar (lambda (widget)
+             (and (default-boundp (widget-value widget))
+                  (if (memq (widget-get widget :custom-state)
+                            '(modified changed))
+                      (widget-apply widget :custom-reset-current))))
            children)))
 
 (defun Custom-reset-saved (&rest ignore)
   "Reset all modified or set group members to their saved value."
   (interactive)
   (let ((children custom-options))
-    (mapcar (lambda (child)
-             (when (eq (widget-get child :custom-state) 'modified)
-               (widget-apply child :custom-reset-saved)))
+    (mapcar (lambda (widget)
+             (and (get (widget-value widget) 'saved-value)
+                  (if (memq (widget-get widget :custom-state)
+                            '(modified set changed rogue))
+                      (widget-apply widget :custom-reset-saved))))
            children)))
 
 (defun Custom-reset-standard (&rest ignore)
   "Reset all modified, set, or saved group members to their standard settings."
   (interactive)
   (let ((children custom-options))
-    (mapcar (lambda (child)
-             (when (eq (widget-get child :custom-state) 'modified)
-               (widget-apply child :custom-reset-standard)))
+    (mapcar (lambda (widget)
+             (and (get (widget-value widget) 'standard-value)
+                  (if (memq (widget-get widget :custom-state)
+                            '(modified set changed saved rogue))
+                      (widget-apply widget :custom-reset-standard))))
            children)))
 
 ;;; The Customize Commands
 
-(defun custom-prompt-variable (prompt-var prompt-val)
+(defun custom-prompt-variable (prompt-var prompt-val &optional comment)
   "Prompt for a variable and a value and return them as a list.
 PROMPT-VAR is the prompt for the variable, and PROMPT-VAL is the
 prompt for the value.  The %s escape in PROMPT-VAL is replaced with
@@ -715,10 +717,13 @@ If the 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 the variable has a `custom-type' property, it must be a widget and the
-`:prompt-value' property of that widget will be used for reading the value."
+`:prompt-value' property of that widget will be used for reading the value.
+
+If optional COMMENT argument is non nil, also prompt for a comment and return
+it as the third element in the list."
   (let* ((var (read-variable prompt-var))
-        (minibuffer-help-form '(describe-variable var)))
-    (list var
+        (minibuffer-help-form '(describe-variable var))
+        (val
          (let ((prop (get var 'variable-interactive))
                (type (get var 'custom-type))
                (prompt (format prompt-val var)))
@@ -737,24 +742,35 @@ If the variable has a `custom-type' property, it must be a widget and the
                                            (symbol-value var))
                                        (not (boundp var))))
                  (t
-                  (eval-minibuffer prompt)))))))
+                  (eval-minibuffer prompt))))))
+    (if comment
+       (list var val
+             (read-string "Comment: " (get var 'variable-comment)))
+      (list var val))))
 
 ;;;###autoload
-(defun customize-set-value (var val)
+(defun customize-set-value (var val &optional comment)
   "Set VARIABLE to VALUE.  VALUE is a Lisp object.
 
 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." 
+`:prompt-value' property of that widget will be used for reading the value.
+
+If given a prefix (or a COMMENT argument), also prompt for a comment."
   (interactive (custom-prompt-variable "Set variable: "
-                                      "Set %s to value: "))
+                                      "Set %s to value: "
+                                      current-prefix-arg))
    
-  (set var val))
+  (set var val)
+  (cond ((string= comment "")
+        (put var 'variable-comment nil))
+       (comment
+        (put var 'variable-comment comment))))
 
 ;;;###autoload
-(defun customize-set-variable (var val)
+(defun customize-set-variable (var val &optional comment)
   "Set the default for VARIABLE to VALUE.  VALUE is a Lisp object.
 
 If VARIABLE has a `custom-set' property, that is used for setting
@@ -767,14 +783,23 @@ 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. " 
+`:prompt-value' property of that widget will be used for reading the value.
+
+If given a prefix (or a COMMENT argument), also prompt for a comment."
   (interactive (custom-prompt-variable "Set variable: "
-                                      "Set customized value for %s to: "))
+                                      "Set customized value for %s to: "
+                                      current-prefix-arg))
   (funcall (or (get var 'custom-set) 'set-default) var val)
-  (put var 'customized-value (list (custom-quote val))))
+  (put var 'customized-value (list (custom-quote val)))
+  (cond ((string= comment "")
+        (put var 'variable-comment nil)
+        (put var 'customized-variable-comment nil))
+       (comment
+        (put var 'variable-comment comment)
+        (put var 'customized-variable-comment comment))))
 
 ;;;###autoload
-(defun customize-save-variable (var val)
+(defun customize-save-variable (var val &optional comment)
   "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.
@@ -786,11 +811,20 @@ 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. " 
+`:prompt-value' property of that widget will be used for reading the value.
+
+If given a prefix (or a COMMENT argument), also prompt for a comment."
   (interactive (custom-prompt-variable "Set and ave variable: "
-                                      "Set and save value for %s as: "))
+                                      "Set and save value for %s as: "
+                                      current-prefix-arg))
   (funcall (or (get var 'custom-set) 'set-default) var val)
   (put var 'saved-value (list (custom-quote val)))
+  (cond ((string= comment "")
+        (put var 'variable-comment nil)
+        (put var 'saved-variable-comment nil))
+       (comment
+        (put var 'variable-comment comment)
+        (put var 'saved-variable-comment comment)))
   (custom-save-all))
 
 ;;;###autoload
@@ -807,7 +841,7 @@ are shown; the contents of those subgroups are initially hidden."
   "Customize GROUP, which must be a customization group."
   (interactive (list (let ((completion-ignore-case t))
                       (completing-read "Customize group: (default emacs) "
-                                       obarray 
+                                       obarray
                                        (lambda (symbol)
                                          (or (get symbol 'custom-loads)
                                              (get symbol 'custom-group)))
@@ -821,28 +855,39 @@ are shown; the contents of those subgroups are initially hidden."
   (let ((name (format "*Customize Group: %s*"
                      (custom-unlispify-tag-name group))))
     (if (get-buffer name)
-       (switch-to-buffer name)
+       (pop-to-buffer name)
       (custom-buffer-create (list (list group 'custom-group))
                            name
                            (concat " for group "
                                    (custom-unlispify-tag-name group))))))
 
 ;;;###autoload
-(defun customize-group-other-window (symbol)
-  "Customize SYMBOL, which must be a customization group."
-  (interactive (list (completing-read "Customize group: (default emacs) "
-                                     obarray 
-                                     (lambda (symbol)
-                                       (get symbol 'custom-group))
-                                     t)))
-
-  (when (stringp symbol)
-    (if (string-equal "" symbol)
-       (setq symbol 'emacs)
-      (setq symbol (intern symbol))))
-  (custom-buffer-create-other-window
-   (list (list symbol 'custom-group))
-   (format "*Customize Group: %s*" (custom-unlispify-tag-name symbol))))
+(defun customize-group-other-window (group)
+  "Customize GROUP, which must be a customization group."
+  (interactive (list (let ((completion-ignore-case t))
+                      (completing-read "Customize group: (default emacs) "
+                                       obarray
+                                       (lambda (symbol)
+                                         (or (get symbol 'custom-loads)
+                                             (get symbol 'custom-group)))
+                                       t))))
+  (when (stringp group)
+    (if (string-equal "" group)
+       (setq group 'emacs)
+      (setq group (intern group))))
+  (or (get group 'custom-group)
+      (custom-load-symbol group))
+  (let ((name (format "*Customize Group: %s*"
+                     (custom-unlispify-tag-name group))))
+    (if (get-buffer name)
+       (let ((window (selected-window)))
+         (pop-to-buffer name)
+         (select-window window))
+      (custom-buffer-create-other-window
+       (list (list group 'custom-group))
+       name
+       (concat " for group "
+              (custom-unlispify-tag-name group))))))
 
 ;;;###autoload
 (defalias 'customize-variable 'customize-option)
@@ -851,10 +896,114 @@ are shown; the contents of those subgroups are initially hidden."
 (defun customize-option (symbol)
   "Customize SYMBOL, which must be a user option variable."
   (interactive (custom-variable-prompt))
+  ;; If we don't have SYMBOL's real definition loaded,
+  ;; try to load it.
+  (unless (get symbol 'custom-type)
+    (let ((loaddefs-file (locate-library "loaddefs.el" t))
+         file)
+      ;; See if it is autoloaded from some library.
+      (when loaddefs-file
+       (with-temp-buffer
+         (insert-file-contents loaddefs-file)
+         (when (re-search-forward (concat "^(defvar " (symbol-name symbol))
+                                  nil t)
+           (search-backward "\n;;; Generated autoloads from ")
+           (goto-char (match-end 0))
+           (setq file (buffer-substring (point)
+                                        (progn (end-of-line) (point)))))))
+      ;; If it is, load that library.
+      (when file
+       (when (string-match "\\.el\\'" file)
+         (setq file (substring file 0 (match-beginning 0))))
+       (load file))))
+  (unless (get symbol 'custom-type)
+    (error "Variable %s cannot be customized" symbol))
   (custom-buffer-create (list (list symbol 'custom-variable))
                        (format "*Customize Option: %s*"
                                (custom-unlispify-tag-name symbol))))
 
+(defvar customize-changed-options-previous-release "20.2"
+  "Version for `customize-changed-options' to refer back to by default.")
+
+;;;###autoload
+(defun customize-changed-options (since-version)
+  "Customize all user option variables changed in Emacs itself.
+This includes new user option variables and faces, and new
+customization groups, as well as older options and faces whose default
+values have changed since the previous major Emacs release.
+
+With argument SINCE-VERSION (a string), customize all user option
+variables that were added (or their meanings were changed) since that
+version."
+
+  (interactive "sCustomize options changed, since version (default all versions): ")
+  (if (equal since-version "")
+      (setq since-version nil))
+  (unless since-version
+    (setq since-version customize-changed-options-previous-release))
+  (let ((found nil)
+       (versions nil))
+    (mapatoms (lambda (symbol)
+               (and (or (boundp symbol)
+                        ;; For variables not yet loaded.
+                        (get symbol 'standard-value)
+                        ;; For groups the previous test fails, this one
+                        ;; could be used to determine if symbol is a
+                        ;; group. Is there a better way for this?
+                        (get symbol 'group-documentation))
+                    (let ((version (get symbol 'custom-version)))
+                      (and version
+                           (or (null since-version)
+                               (customize-version-lessp since-version version))
+                           (if (member version versions)
+                               t
+                             ;;; Collect all versions that we use.
+                             (push version versions))))
+                    (setq found
+                          ;; We have to set the right thing here,
+                          ;; depending if we have a group or a
+                          ;; variable.
+                          (if (get  symbol 'group-documentation)
+                              (cons (list symbol 'custom-group) found)
+                            (cons (list symbol 'custom-variable) found))))))
+    (if (not found)
+       (error "No user option defaults have been changed since Emacs %s"
+              since-version)
+      (let ((flist nil))
+       (while versions
+         (push (copy-sequence
+                (cdr (assoc (car versions)  custom-versions-load-alist)))
+               flist)
+         (setq versions (cdr versions)))
+       (put 'custom-versions-load-alist 'custom-loads
+            ;; Get all the files that correspond to element from the
+            ;; VERSIONS list. This could use some simplification.
+            (apply 'nconc flist)))
+      ;; Because we set all the files needed to be loaded as a
+      ;; `custom-loads' property to `custom-versions-load-alist' this
+      ;; call will actually load them.
+      (custom-load-symbol 'custom-versions-load-alist)
+      ;; Clean up
+      (put 'custom-versions-load-alist 'custom-loads nil)
+      (custom-buffer-create (custom-sort-items found t 'first)
+                           "*Customize Changed Options*"))))
+
+(defun customize-version-lessp (version1 version2)
+  ;; In case someone made a mistake and left out the quotes
+  ;; in the :version value.
+  (if (numberp version2)
+      (setq version2 (prin1-to-string version2)))
+  (let (major1 major2 minor1 minor2)
+    (string-match "\\([0-9]+\\)[.]\\([0-9]+\\)" version1)
+    (setq major1 (read (match-string 1 version1)))
+    (setq minor1 (read (match-string 2 version1)))
+    (string-match "\\([0-9]+\\)[.]\\([0-9]+\\)" version2)
+    (setq major2 (read (match-string 1 version2)))
+    (setq minor2 (read (match-string 2 version2)))
+    (or (< major1 major2)
+       (and (= major1 major2)
+            (< minor1 minor2)))))
+  
 ;;;###autoload
 (defalias 'customize-variable-other-window 'customize-option-other-window)
 
@@ -871,7 +1020,7 @@ Show the buffer in another window, but don't select it."
 (defun customize-face (&optional symbol)
   "Customize SYMBOL, which should be a face name or nil.
 If SYMBOL is nil, customize all faces."
-  (interactive (list (completing-read "Customize face: (default all) " 
+  (interactive (list (completing-read "Customize face: (default all) "
                                      obarray 'custom-facep)))
   (if (or (null symbol) (and (stringp symbol) (zerop (length symbol))))
       (custom-buffer-create (custom-sort-items
@@ -891,7 +1040,7 @@ If SYMBOL is nil, customize all faces."
 ;;;###autoload
 (defun customize-face-other-window (&optional symbol)
   "Show customization buffer for FACE in other window."
-  (interactive (list (completing-read "Customize face: " 
+  (interactive (list (completing-read "Customize face: "
                                      obarray 'custom-facep)))
   (if (or (null symbol) (and (stringp symbol) (zerop (length symbol))))
       ()
@@ -899,7 +1048,7 @@ If SYMBOL is nil, customize all faces."
        (setq symbol (intern symbol)))
     (unless (symbolp symbol)
       (error "Should be a symbol %S" symbol))
-    (custom-buffer-create-other-window 
+    (custom-buffer-create-other-window
      (list (list symbol 'custom-face))
      (format "*Customize Face: %s*" (custom-unlispify-tag-name symbol)))))
 
@@ -909,10 +1058,12 @@ If SYMBOL is nil, customize all faces."
   (interactive)
   (let ((found nil))
     (mapatoms (lambda (symbol)
-               (and (get symbol 'customized-face)
+               (and (or (get symbol 'customized-face)
+                        (get symbol 'customized-face-comment))
                     (custom-facep symbol)
                     (push (list symbol 'custom-face) found))
-               (and (get symbol 'customized-value)
+               (and (or (get symbol 'customized-value)
+                        (get symbol 'customized-variable-comment))
                     (boundp symbol)
                     (push (list symbol 'custom-variable) found))))
     (if (not found)
@@ -926,10 +1077,12 @@ If SYMBOL is nil, customize all faces."
   (interactive)
   (let ((found nil))
     (mapatoms (lambda (symbol)
-               (and (get symbol 'saved-face)
+               (and (or (get symbol 'saved-face)
+                        (get symbol 'saved-face-comment))
                     (custom-facep symbol)
                     (push (list symbol 'custom-face) found))
-               (and (get symbol 'saved-value)
+               (and (or (get symbol 'saved-value)
+                        (get symbol 'saved-variable-comment))
                     (boundp symbol)
                     (push (list symbol 'custom-variable) found))))
     (if (not found )
@@ -1000,6 +1153,18 @@ links: groups have links to subgroups."
                (const links))
   :group 'custom-buffer)
 
+(defun custom-bury-buffer (buffer)
+  (bury-buffer))
+
+(defcustom custom-buffer-done-function 'bury-buffer
+  "*Function called to remove a Custom buffer when the user is done with it.
+Called with one argument, the buffer to remove."
+  :type '(choice (function-item custom-bury-buffer)
+                (function-item kill-buffer)
+                (function :tag "Other"))
+  :version "21.1"
+  :group 'custom-buffer)
+
 (defcustom custom-buffer-indent 3
   "Number of spaces to indent nested groups."
   :type 'integer
@@ -1014,7 +1179,7 @@ SYMBOL is a customization option, and WIDGET is a widget for editing
 that option."
   (unless name (setq name "*Customization*"))
   (kill-buffer (get-buffer-create name))
-  (switch-to-buffer (get-buffer-create name))
+  (pop-to-buffer (get-buffer-create name))
   (custom-buffer-create-internal options description))
 
 ;;;###autoload
@@ -1026,8 +1191,13 @@ SYMBOL is a customization option, and WIDGET is a widget for editing
 that option."
   (unless name (setq name "*Customization*"))
   (kill-buffer (get-buffer-create name))
-  (let ((window (selected-window)))
-    (switch-to-buffer-other-window (get-buffer-create name))
+  (let ((window (selected-window))
+       (pop-up-windows t)
+       (special-display-buffer-names nil)
+       (special-display-regexps nil)
+       (same-window-buffer-names nil)
+       (same-window-regexps nil))
+    (pop-to-buffer (get-buffer-create name))
     (custom-buffer-create-internal options description)
     (select-window window)))
 
@@ -1037,19 +1207,34 @@ This button will have a menu with all three reset operations."
   :type 'boolean
   :group 'custom-buffer)
 
+(defun Custom-buffer-done (&rest ignore)
+  "Remove current buffer by calling `custom-buffer-done-function'."
+  (interactive)
+  (funcall custom-buffer-done-function (current-buffer)))
+
+(defcustom custom-raised-buttons (not (equal (face-valid-attribute-values :box)
+                                            '(("unspecified" . unspecified))))
+  "If non-nil, indicate active buttons in a `raised-button' style.
+Otherwise use brackets."
+  :type 'boolean
+  :version "21.1"
+  :group 'custom-buffer)
+
 (defun custom-buffer-create-internal (options &optional description)
   (message "Creating customization buffer...")
   (custom-mode)
   (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
+  (widget-insert (format ".
+%s 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 
+Invoke " (if custom-raised-buttons
+            "`Raised' buttons"
+            "Square brackets")))
+  (widget-create 'info-link
                 :tag "Help"
                 :help-echo "Read the online help."
                 "(emacs)Easy Customization")
@@ -1098,13 +1283,12 @@ Reset all values in this buffer to their standard settings."
                   :action 'Custom-reset-standard))
   (widget-insert "   ")
   (widget-create 'push-button
-                :tag "Bury Buffer"
-                :help-echo "Bury the buffer."
-                :action (lambda (widget &optional event)
-                          (bury-buffer)))
+                :tag "Finish"
+                :help-echo "Bury or kill the buffer."
+                :action #'Custom-buffer-done)
   (widget-insert "\n\n")
   (message "Creating customization items...")
-  (setq custom-options 
+  (setq custom-options
        (if (= (length options) 1)
            (mapcar (lambda (entry)
                      (widget-create (nth 1 entry)
@@ -1118,7 +1302,7 @@ Reset all values in this buffer to their standard settings."
                (length (length options)))
            (mapcar (lambda (entry)
                        (prog2
-                           (message "Creating customization items %2d%%..."
+                           (message "Creating customization items ...%2d%%"
                                     (/ (* 100.0 count) length))
                            (widget-create (nth 1 entry)
                                         :tag (custom-unlispify-tag-name
@@ -1131,7 +1315,7 @@ Reset all values in this buffer to their standard settings."
                      options))))
   (unless (eq (preceding-char) ?\n)
     (widget-insert "\n"))
-  (message "Creating customization items %2d%%...done" 100)
+  (message "Creating customization items ...%2d%%done" 100)
   (unless (eq custom-buffer-style 'tree)
     (mapcar 'custom-magic-reset custom-options))
   (message "Creating customization setup...")
@@ -1149,7 +1333,7 @@ Reset all values in this buffer to their standard settings."
     (setq group 'emacs))
   (let ((name "*Customize Browser*"))
     (kill-buffer (get-buffer-create name))
-    (switch-to-buffer (get-buffer-create name)))
+    (pop-to-buffer (get-buffer-create name)))
   (custom-mode)
   (widget-insert "\
 Square brackets show active fields; type RET or click mouse-1
@@ -1158,25 +1342,25 @@ 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 
+    (widget-insert "Invoke the ")
+    (widget-create 'item
                   :format "%t"
                   :tag "[Group]"
                   :tag-glyph "folder")
     (widget-insert ", ")
-    (widget-create 'item 
+    (widget-create 'item
                   :format "%t"
                   :tag "[Face]"
                   :tag-glyph "face")
     (widget-insert ", and ")
-    (widget-create 'item 
+    (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 
+    (widget-create 'custom-group
                   :custom-last t
                   :custom-state 'unknown
                   :tag (custom-unlispify-tag-name group)
@@ -1184,7 +1368,7 @@ item in another window.\n\n"))
   (goto-char (point-min)))
 
 (define-widget 'custom-browse-visibility 'item
-  "Control visibility of of items in the customize tree browser."
+  "Control visibility of items in the customize tree browser."
   :format "%[[%t]%]"
   :action 'custom-browse-visibility-action)
 
@@ -1230,8 +1414,9 @@ item in another window.\n\n"))
 
 (defun custom-browse-insert-prefix (prefix)
   "Insert PREFIX.  On XEmacs convert it to line graphics."
+  ;; Fixme: do graphics.
   (if nil ; (string-match "XEmacs" emacs-version)
-      (progn 
+      (progn
        (insert "*")
        (while (not (string-equal prefix ""))
          (let ((entry (substring prefix 0 3)))
@@ -1290,21 +1475,21 @@ item in another window.\n\n"))
   "Face used when the customize item is not defined for customization."
   :group 'custom-magic-faces)
 
-(defface custom-modified-face '((((class color)) 
+(defface custom-modified-face '((((class color))
                                 (:foreground "white" :background "blue"))
                                (t
                                 (:italic t :bold)))
   "Face used when the customize item has been modified."
   :group 'custom-magic-faces)
 
-(defface custom-set-face '((((class color)) 
+(defface custom-set-face '((((class color))
                                (:foreground "blue" :background "white"))
                               (t
                                (:italic t)))
   "Face used when the customize item has been set."
   :group 'custom-magic-faces)
 
-(defface custom-changed-face '((((class color)) 
+(defface custom-changed-face '((((class color))
                                (:foreground "white" :background "blue"))
                               (t
                                (:italic t)))
@@ -1343,7 +1528,7 @@ something in this group is not prepared for customization.")
 this %c is unchanged from its standard setting." "\
 visible group members are all at standard settings."))
   "Alist of customize option states.
-Each entry is of the form (STATE MAGIC FACE ITEM-DESC [ GROUP-DESC ]), where 
+Each entry is of the form (STATE MAGIC FACE ITEM-DESC [ GROUP-DESC ]), where
 
 STATE is one of the following symbols:
 
@@ -1352,7 +1537,7 @@ STATE is one of the following symbols:
 `unknown'
    For internal use, should never occur.
 `hidden'
-   This item is not being displayed. 
+   This item is not being displayed.
 `invalid'
    This item is modified, but has an invalid form.
 `modified'
@@ -1386,8 +1571,8 @@ The list should be sorted most significant first.")
   "If non-nil, show textual description of the state.
 If `long', show a full-line description, not just one word."
   :type '(choice (const :tag "no" nil)
-                (const short)
-                (const long))
+                (const long)
+                (other :tag "short" short))
   :group 'custom-buffer)
 
 (defcustom custom-magic-show-hidden '(option face)
@@ -1414,7 +1599,7 @@ and `face'."
 
 (defun widget-magic-mouse-down-action (widget &optional event)
   ;; Non-nil unless hidden.
-  (not (eq (widget-get (widget-get (widget-get widget :parent) :parent) 
+  (not (eq (widget-get (widget-get (widget-get widget :parent) :parent)
                       :custom-state)
           'hidden)))
 
@@ -1433,7 +1618,7 @@ and `face'."
         (form (widget-get parent :custom-form))
         children)
     (while (string-match "\\`\\(.*\\)%c\\(.*\\)\\'" text)
-      (setq text (concat (match-string 1 text) 
+      (setq text (concat (match-string 1 text)
                         (symbol-name category)
                         (match-string 2 text))))
     (when (and custom-magic-show
@@ -1445,8 +1630,8 @@ and `face'."
                           (> (widget-get parent :custom-level) 1))))
        (insert-char ?\  (* custom-buffer-indent
                            (widget-get parent :custom-level))))
-      (push (widget-create-child-and-convert 
-            widget 'choice-item 
+      (push (widget-create-child-and-convert
+            widget 'choice-item
             :help-echo "Change the state of this item."
             :format (if hidden "%t" "%[%t%]")
             :button-prefix 'widget-push-button-prefix
@@ -1475,8 +1660,8 @@ and `face'."
        (let ((indent (widget-get parent :indent)))
          (when indent
            (insert-char ?  indent))))
-      (push (widget-create-child-and-convert 
-            widget 'choice-item 
+      (push (widget-create-child-and-convert
+            widget 'choice-item
             :mouse-down-action 'widget-magic-mouse-down-action
             :button-face face
             :button-prefix ""
@@ -1497,8 +1682,22 @@ and `face'."
 
 ;;; The `custom' Widget.
 
-(defface custom-button-face nil
+(defface custom-button-face
+  '((((type x) (class color))          ; Like default modeline
+     (:box (:line-width 2 :style released-button) :background "lightgrey"))
+    (t
+     nil))
   "Face used for buttons in customization buffers."
+  :version "21.1"
+  :group 'custom-faces)
+
+(defface custom-button-pressed-face
+  '((((type x) (class color))
+     (:box (:line-width 2 :style pressed-button) :background "lightgrey"))
+    (t
+     (:inverse-video t)))
+  "Face used for buttons in customization buffers."
+  :version "21.1"
   :group 'custom-faces)
 
 (defface custom-documentation-face nil
@@ -1533,7 +1732,7 @@ and `face'."
 (defun custom-convert-widget (widget)
   ;; Initialize :value and :tag from :args in WIDGET.
   (let ((args (widget-get widget :args)))
-    (when args 
+    (when args
       (widget-put widget :value (widget-apply widget
                                              :value-to-internal (car args)))
       (widget-put widget :tag (custom-unlispify-tag-name (car args)))
@@ -1561,7 +1760,7 @@ and `face'."
       (custom-redraw-magic widget))
     (when (and (>= pos from) (<= pos to))
       (condition-case nil
-         (progn 
+         (progn
            (if (> column 0)
                (goto-line line)
              (goto-line (1+ line)))
@@ -1570,9 +1769,9 @@ and `face'."
 
 (defun custom-redraw-magic (widget)
   "Redraw WIDGET state with current settings."
-  (while widget 
+  (while widget
     (let ((magic (widget-get widget :custom-magic)))
-      (cond (magic 
+      (cond (magic
             (widget-value-set magic (widget-value magic))
             (when (setq widget (widget-get widget :group))
               (custom-group-state-update widget)))
@@ -1596,7 +1795,7 @@ and `face'."
 (defun custom-load-symbol (symbol)
   "Load all dependencies for SYMBOL."
   (unless custom-load-recursion
-    (let ((custom-load-recursion t) 
+    (let ((custom-load-recursion t)
          (loads (get symbol 'custom-loads))
          load)
       (while loads
@@ -1654,7 +1853,7 @@ and `face'."
           (error "There are unset changes"))
          ((eq state 'hidden)
           (widget-put widget :custom-state 'unknown))
-         (t 
+         (t
           (widget-put widget :documentation-shown nil)
           (widget-put widget :custom-state 'hidden)))
     (custom-redraw widget)
@@ -1688,7 +1887,7 @@ Insert PREFIX first if non-nil."
               (if many
                   (insert ", and ")
                 (insert " and ")))
-             (t 
+             (t
               (insert ", "))))
       (widget-put widget :buttons buttons))))
 
@@ -1706,8 +1905,8 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
                (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 
+                   (push (widget-create-child-and-convert
+                          widget 'custom-group-link
                           :tag (custom-unlispify-tag-name symbol)
                           symbol)
                          buttons)
@@ -1718,6 +1917,67 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
       (delete-region start (point)))
     found))
 
+;;; The `custom-comment' Widget.
+
+;; like the editable field
+(defface custom-comment-face '((((class grayscale color)
+                                (background light))
+                               (:background "gray85"))
+                              (((class grayscale color)
+                                (background dark))
+                               (:background "dim gray"))
+                              (t
+                               (:italic t)))
+  "Face used for comments on variables or faces"
+  :version "21.1"
+  :group 'custom-faces)
+
+;; like font-lock-comment-face
+(defface custom-comment-tag-face
+  '((((class color) (background dark)) (:foreground "gray80"))
+    (((class color) (background light)) (:foreground "blue4"))
+    (((class grayscale) (background light))
+     (:foreground "DimGray" :bold t :italic t))
+    (((class grayscale) (background dark))
+     (:foreground "LightGray" :bold t :italic t))
+    (t (:bold t)))
+  "Face used for variables or faces comment tags"
+  :group 'custom-faces)
+
+(define-widget 'custom-comment 'string
+  "User comment."
+  :tag "Comment"
+  :help-echo "Edit a comment here."
+  :sample-face 'custom-comment-tag-face
+  :value-face 'custom-comment-face
+  :shown nil
+  :create 'custom-comment-create)
+
+(defun custom-comment-create (widget)
+  (let* ((null-comment (equal "" (widget-value widget))))
+    (if (or (widget-get (widget-get widget :parent) :comment-shown)
+           (not null-comment))
+       (widget-default-create widget)
+      ;; `widget-default-delete' expects markers in these slots --
+      ;; maybe it shouldn't.
+      (widget-put widget :from (point-marker))
+      (widget-put widget :to (point-marker)))))
+
+(defun custom-comment-hide (widget)
+  (widget-put (widget-get widget :parent) :comment-shown nil))
+
+;; Those functions are for the menu. WIDGET is NOT the comment widget. It's
+;; the global custom one
+(defun custom-comment-show (widget)
+  (widget-put widget :comment-shown t)
+  (custom-redraw widget)
+  (widget-setup))
+
+(defun custom-comment-invisible-p (widget)
+  (let ((val (widget-value (widget-get widget :comment-widget))))
+    (and (equal "" val)
+        (not (widget-get widget :comment-shown)))))
+
 ;;; The `custom-variable' Widget.
 
 (defface custom-variable-tag-face '((((class color)
@@ -1734,6 +1994,13 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
   "Face used for pushable variable tags."
   :group 'custom-faces)
 
+(defcustom custom-variable-default-form 'edit
+  "Default form of displaying variable values."
+  :type '(choice (const edit)
+                (const lisp))
+  :group 'custom-buffer
+  :version "20.3")
+
 (define-widget 'custom-variable 'custom
   "Customize variable."
   :format "%v"
@@ -1742,7 +2009,7 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
   :custom-category 'option
   :custom-state nil
   :custom-menu 'custom-variable-menu-create
-  :custom-form 'edit
+  :custom-form nil ; defaults to value of `custom-variable-default-form'
   :value-create 'custom-variable-value-create
   :action 'custom-variable-action
   :custom-set 'custom-variable-set
@@ -1753,7 +2020,7 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
 
 (defun custom-variable-type (symbol)
   "Return a widget suitable for editing the value of SYMBOL.
-If SYMBOL has a `custom-type' property, use that.  
+If SYMBOL has a `custom-type' property, use that.
 Otherwise, look up symbol in `custom-guess-type-alist'."
   (let* ((type (or (get symbol 'custom-type)
                   (and (not (get symbol 'standard-value))
@@ -1768,8 +2035,10 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
     tmp))
 
 (defun custom-variable-value-create (widget)
-  "Here is where you edit the variables value."
+  "Here is where you edit the variable's value."
   (custom-load-widget widget)
+  (unless (widget-get widget :custom-form)
+    (widget-put widget :custom-form custom-variable-default-form))
   (let* ((buttons (widget-get widget :buttons))
         (children (widget-get widget :children))
         (form (widget-get widget :custom-form))
@@ -1784,7 +2053,7 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
         (value (if (default-boundp symbol)
                    (funcall get symbol)
                  (widget-get conv :value))))
-    ;; If the widget is new, the child determine whether it is hidden.
+    ;; If the widget is new, the child determines whether it is hidden.
     (cond (state)
          ((custom-show type value)
           (setq state 'unknown))
@@ -1805,14 +2074,14 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
           (widget-put widget :buttons buttons))
          ((eq state 'hidden)
           ;; Indicate hidden value.
-          (push (widget-create-child-and-convert 
+          (push (widget-create-child-and-convert
                  widget 'item
                  :format "%{%t%}: "
                  :sample-face 'custom-variable-tag-face
                  :tag tag
                  :parent widget)
                 buttons)
-          (push (widget-create-child-and-convert 
+          (push (widget-create-child-and-convert
                  widget 'visibility
                  :help-echo "Show the value of this option."
                  :action 'custom-toggle-parent
@@ -1829,15 +2098,15 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
                               (t
                                (custom-quote (widget-get conv :value))))))
             (insert (symbol-name symbol) ": ")
-            (push (widget-create-child-and-convert 
+            (push (widget-create-child-and-convert
                    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 
+            (push (widget-create-child-and-convert
+                   widget 'sexp
                    :button-face 'custom-variable-button-face
                    :format "%v"
                    :tag (symbol-name symbol)
@@ -1853,7 +2122,7 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
             (setq tag-format (substring format 0 (match-end 0)))
             (setq value-format (substring format (match-end 0)))
             (push (widget-create-child-and-convert
-                   widget 'item 
+                   widget 'item
                    :format tag-format
                    :action 'custom-tag-action
                    :help-echo "Change value of this option."
@@ -1863,35 +2132,53 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
                    tag)
                   buttons)
             (insert " ")
-            (push (widget-create-child-and-convert 
-                 widget 'visibility
-                 :help-echo "Hide the value of this option."
-                 :action 'custom-toggle-parent
-                 t)
-                buttons)            
             (push (widget-create-child-and-convert
-                   widget type 
+                   widget 'visibility
+                   :help-echo "Hide the value of this option."
+                   :action 'custom-toggle-parent
+                   t)
+                  buttons)
+            (push (widget-create-child-and-convert
+                   widget type
                    :format value-format
                    :value value)
                   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)         
+      ;; ### NOTE: this is ugly!!!! I need to update the :buttons property
+      ;; before the call to `widget-default-format-handler'. Otherwise, I
+      ;; loose my current `buttons'. This function shouldn't be called like
+      ;; this anyway. The doc string widget should be added like the others.
+      ;; --dv
       (widget-put widget :buttons buttons)
-      (widget-put widget :children children)
       ;; Insert documentation.
       (widget-default-format-handler widget ?h)
+
+      ;; The comment field
+      (unless (eq state 'hidden)
+       (let* ((comment (get symbol 'variable-comment))
+              (comment-widget
+               (widget-create-child-and-convert
+                widget 'custom-comment
+                :parent widget
+                :value (or comment ""))))
+         (widget-put widget :comment-widget comment-widget)
+         ;; Don't push it !!! Custom assumes that the first child is the
+         ;; value one.
+         (setq children (append children (list comment-widget)))))
+      ;; Update the rest of the properties properties.
+      (widget-put widget :custom-form form)
+      (widget-put widget :children children)
+      ;; Now update the state.
+      (if (eq state 'hidden)
+         (widget-put widget :custom-state state)
+       (custom-variable-state-set widget))
       ;; See also.
       (unless (eq state 'hidden)
        (when (eq (widget-get widget :custom-level) 1)
@@ -1915,29 +2202,39 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
         (value (if (default-boundp symbol)
                    (funcall get symbol)
                  (widget-get widget :value)))
+        (comment (get symbol 'variable-comment))
         tmp
-        (state (cond ((setq tmp (get symbol 'customized-value))
+        temp
+        (state (cond ((progn (setq tmp (get symbol 'customized-value))
+                             (setq temp
+                                   (get symbol 'customized-variable-comment))
+                             (or tmp temp))
                       (if (condition-case nil
-                              (equal value (eval (car tmp)))
+                              (and (equal value (eval (car tmp)))
+                                   (equal comment temp))
                             (error nil))
                           'set
                         'changed))
-                     ((setq tmp (get symbol 'saved-value))
+                     ((progn (setq tmp (get symbol 'saved-value))
+                             (setq temp (get symbol 'saved-variable-comment))
+                             (or tmp temp))
                       (if (condition-case nil
-                              (equal value (eval (car tmp)))
+                              (and (equal value (eval (car tmp)))
+                                   (equal comment temp))
                             (error nil))
                           'saved
                         'changed))
                      ((setq tmp (get symbol 'standard-value))
                       (if (condition-case nil
-                              (equal value (eval (car tmp)))
+                              (and (equal value (eval (car tmp)))
+                                   (equal comment nil))
                             (error nil))
                           'standard
                         'changed))
                      (t 'rogue))))
     (widget-put widget :custom-state state)))
 
-(defvar custom-variable-menu 
+(defvar custom-variable-menu
   '(("Set for Current Session" custom-variable-set
      (lambda (widget)
        (eq (widget-get widget :custom-state) 'modified)))
@@ -1950,7 +2247,8 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
            (memq (widget-get widget :custom-state) '(modified changed)))))
     ("Reset to Saved" custom-variable-reset-saved
      (lambda (widget)
-       (and (get (widget-value widget) 'saved-value)
+       (and (or (get (widget-value widget) 'saved-value)
+               (get (widget-value widget) 'saved-variable-comment))
            (memq (widget-get widget :custom-state)
                  '(modified set changed rogue)))))
     ("Reset to Standard Settings" custom-variable-reset-standard
@@ -1959,7 +2257,9 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
            (memq (widget-get widget :custom-state)
                  '(modified set changed saved rogue)))))
     ("---" ignore ignore)
-    ("Don't show as Lisp expression" custom-variable-edit 
+    ("Add Comment" custom-comment-show custom-comment-invisible-p)
+    ("---" ignore ignore)
+    ("Don't show as Lisp expression" custom-variable-edit
      (lambda (widget)
        (eq (widget-get widget :custom-form) 'lisp)))
     ("Show initial Lisp expression" custom-variable-edit-lisp
@@ -2009,18 +2309,32 @@ Optional EVENT is the location for the menu."
         (child (car (widget-get widget :children)))
         (symbol (widget-value widget))
         (set (or (get symbol 'custom-set) 'set-default))
-         val)
+        (comment-widget (widget-get widget :comment-widget))
+        (comment (widget-value comment-widget))
+        val)
     (cond ((eq state 'hidden)
           (error "Cannot set hidden variable"))
          ((setq val (widget-apply child :validate))
           (goto-char (widget-get val :from))
           (error "%s" (widget-get val :error)))
          ((memq form '(lisp mismatch))
+          (when (equal comment "")
+            (setq comment nil)
+            ;; Make the comment invisible by hand if it's empty
+            (custom-comment-hide comment-widget))
           (funcall set symbol (eval (setq val (widget-value child))))
-          (put symbol 'customized-value (list val)))
+          (put symbol 'customized-value (list val))
+          (put symbol 'variable-comment comment)
+          (put symbol 'customized-variable-comment comment))
          (t
+          (when (equal comment "")
+            (setq comment nil)
+            ;; Make the comment invisible by hand if it's empty
+            (custom-comment-hide comment-widget))
           (funcall set symbol (setq val (widget-value child)))
-          (put symbol 'customized-value (list (custom-quote val)))))
+          (put symbol 'customized-value (list (custom-quote val)))
+          (put symbol 'variable-comment comment)
+          (put symbol 'customized-variable-comment comment)))
     (custom-variable-state-set widget)
     (custom-redraw-magic widget)))
 
@@ -2031,6 +2345,8 @@ Optional EVENT is the location for the menu."
         (child (car (widget-get widget :children)))
         (symbol (widget-value widget))
         (set (or (get symbol 'custom-set) 'set-default))
+        (comment-widget (widget-get widget :comment-widget))
+        (comment (widget-value comment-widget))
         val)
     (cond ((eq state 'hidden)
           (error "Cannot set hidden variable"))
@@ -2038,14 +2354,26 @@ Optional EVENT is the location for the menu."
           (goto-char (widget-get val :from))
           (error "%s" (widget-get val :error)))
          ((memq form '(lisp mismatch))
+          (when (equal comment "")
+            (setq comment nil)
+            ;; Make the comment invisible by hand if it's empty
+            (custom-comment-hide comment-widget))
           (put symbol 'saved-value (list (widget-value child)))
-          (funcall set symbol (eval (widget-value child))))
+          (funcall set symbol (eval (widget-value child)))
+          (put symbol 'variable-comment comment)
+          (put symbol 'saved-variable-comment comment))
          (t
-          (put symbol
-               'saved-value (list (custom-quote (widget-value
-                                                 child))))
-          (funcall set symbol (widget-value child))))
+          (when (equal comment "")
+            (setq comment nil)
+            ;; Make the comment invisible by hand if it's empty
+            (custom-comment-hide comment-widget))
+          (put symbol 'saved-value
+               (list (custom-quote (widget-value child))))
+          (funcall set symbol (widget-value child))
+          (put symbol 'variable-comment comment)
+          (put symbol 'saved-variable-comment comment)))
     (put symbol 'customized-value nil)
+    (put symbol 'customized-variable-comment nil)
     (custom-save-all)
     (custom-variable-state-set widget)
     (custom-redraw-magic widget)))
@@ -2053,28 +2381,40 @@ Optional EVENT is the location for the menu."
 (defun custom-variable-reset-saved (widget)
   "Restore the saved value for the variable being edited by WIDGET."
   (let* ((symbol (widget-value widget))
-        (set (or (get symbol 'custom-set) 'set-default)))
-    (if (get symbol 'saved-value)
-       (condition-case nil
-           (funcall set symbol (eval (car (get symbol 'saved-value))))
-         (error nil))
-      (error "No saved value for %s" symbol))
+        (set (or (get symbol 'custom-set) 'set-default))
+        (comment-widget (widget-get widget :comment-widget))
+        (value (get symbol 'saved-value))
+        (comment (get symbol 'saved-variable-comment)))
+    (cond ((or value comment)
+          (put symbol 'variable-comment comment)
+          (condition-case nil
+              (funcall set symbol (eval (car value)))
+            (error nil)))
+         (t
+          (error "No saved value for %s" symbol)))
     (put symbol 'customized-value nil)
+    (put symbol 'customized-variable-comment nil)
     (widget-put widget :custom-state 'unknown)
+    ;; This call will possibly make the comment invisible
     (custom-redraw widget)))
 
 (defun custom-variable-reset-standard (widget)
   "Restore the standard setting for the variable being edited by WIDGET."
   (let* ((symbol (widget-value widget))
-        (set (or (get symbol 'custom-set) 'set-default)))
+        (set (or (get symbol 'custom-set) 'set-default))
+        (comment-widget (widget-get widget :comment-widget)))
     (if (get symbol 'standard-value)
        (funcall set symbol (eval (car (get symbol 'standard-value))))
       (error "No standard setting known for %S" symbol))
+    (put symbol 'variable-comment nil)
     (put symbol 'customized-value nil)
-    (when (get symbol 'saved-value)
+    (put symbol 'customized-variable-comment nil)
+    (when (or (get symbol 'saved-value) (get symbol 'saved-variable-comment))
       (put symbol 'saved-value nil)
+      (put symbol 'saved-variable-comment nil)
       (custom-save-all))
     (widget-put widget :custom-state 'unknown)
+    ;; This call will possibly make the comment invisible
     (custom-redraw widget)))
 
 ;;; The `custom-face-edit' Widget.
@@ -2084,12 +2424,12 @@ Optional EVENT is the location for the menu."
   :format "%t: %v"
   :tag "Attributes"
   :extra-offset 12
-  :button-args '(:help-echo "Control whether this attribute have any effect.")
+  :button-args '(:help-echo "Control whether this attribute has any effect.")
   :args (mapcar (lambda (att)
-                 (list 'group 
+                 (list 'group
                        :inline t
                        :sibling-args (widget-get (nth 1 att) :sibling-args)
-                       (list 'const :format "" :value (nth 0 att)) 
+                       (list 'const :format "" :value (nth 0 att))
                        (nth 1 att)))
                custom-face-attributes))
 
@@ -2170,6 +2510,14 @@ Match frames with dark backgrounds.")
   "Face used for face tags."
   :group 'custom-faces)
 
+(defcustom custom-face-default-form 'selected
+  "Default form of displaying face definition."
+  :type '(choice (const all)
+                (const selected)
+                (const lisp))
+  :group 'custom-buffer
+  :version "20.3")
+
 (define-widget 'custom-face 'custom
   "Customize face."
   :sample-face 'custom-face-tag-face
@@ -2179,7 +2527,7 @@ Match frames with dark backgrounds.")
   :value-create 'custom-face-value-create
   :action 'custom-face-action
   :custom-category 'face
-  :custom-form 'selected
+  :custom-form nil ; defaults to value of `custom-face-default-form'
   :custom-set 'custom-face-set
   :custom-save 'custom-face-save
   :custom-reset-current 'custom-redraw
@@ -2187,7 +2535,7 @@ Match frames with dark backgrounds.")
   :custom-reset-standard 'custom-face-reset-standard
   :custom-menu 'custom-face-menu-create)
 
-(define-widget 'custom-face-all 'editable-list 
+(define-widget 'custom-face-all 'editable-list
   "An editable list of display specifications and attributes."
   :entry-format "%i %d %v"
   :insert-button-args '(:help-echo "Insert new display specification here.")
@@ -2206,7 +2554,7 @@ Match frames with dark backgrounds.")
   "Non-nil if VALUE is an unselected display specification."
   (not (face-spec-set-match-display value (selected-frame))))
 
-(define-widget 'custom-face-selected 'group 
+(define-widget 'custom-face-selected 'group
   "Edit the attributes of the selected display in a face specification."
   :args '((repeat :format ""
                  :inline t
@@ -2222,6 +2570,7 @@ Match frames with dark backgrounds.")
 (defun custom-face-value-create (widget)
   "Create a list of the display specifications for WIDGET."
   (let ((buttons (widget-get widget :buttons))
+       children
        (symbol (widget-get widget :value))
        (tag (widget-get widget :tag))
        (state (widget-get widget :custom-state))
@@ -2245,10 +2594,6 @@ Match frames with dark backgrounds.")
             (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
@@ -2256,7 +2601,7 @@ Match frames with dark backgrounds.")
                 buttons)
           ;; Visibility.
           (insert " ")
-          (push (widget-create-child-and-convert 
+          (push (widget-create-child-and-convert
                  widget 'visibility
                  :help-echo "Hide or show this face."
                  :action 'custom-toggle-parent
@@ -2272,6 +2617,16 @@ Match frames with dark backgrounds.")
           (widget-put widget :buttons buttons)
           ;; Insert documentation.
           (widget-default-format-handler widget ?h)
+          ;; The comment field
+          (unless (eq state 'hidden)
+            (let* ((comment (get symbol 'face-comment))
+                   (comment-widget
+                    (widget-create-child-and-convert
+                     widget 'custom-comment
+                     :parent widget
+                     :value (or comment ""))))
+              (widget-put widget :comment-widget comment-widget)
+              (push comment-widget children)))
           ;; See also.
           (unless (eq state 'hidden)
             (when (eq (widget-get widget :custom-level) 1)
@@ -2283,11 +2638,13 @@ Match frames with dark backgrounds.")
           (unless (eq state 'hidden)
             (message "Creating face editor...")
             (custom-load-widget widget)
+            (unless (widget-get widget :custom-form)
+                (widget-put widget :custom-form custom-face-default-form))
             (let* ((symbol (widget-value widget))
                    (spec (or (get symbol 'saved-face)
                              (get symbol 'face-defface-spec)
                              ;; Attempt to construct it.
-                             (list (list t (custom-face-attributes-get 
+                             (list (list t (custom-face-attributes-get
                                             symbol (selected-frame))))))
                    (form (widget-get widget :custom-form))
                    (indent (widget-get widget :indent))
@@ -2299,7 +2656,7 @@ Match frames with dark backgrounds.")
               (setq edit (widget-create-child-and-convert
                           widget
                           (cond ((and (eq form 'selected)
-                                      (widget-apply custom-face-selected 
+                                      (widget-apply custom-face-selected
                                                     :match spec))
                                  (when indent (insert-char ?\  indent))
                                  'custom-face-selected)
@@ -2307,24 +2664,28 @@ Match frames with dark backgrounds.")
                                       (widget-apply custom-face-all
                                                     :match spec))
                                  'custom-face-all)
-                                (t 
+                                (t
                                  (when indent (insert-char ?\  indent))
                                  'sexp))
                           :value spec))
               (custom-face-state-set widget)
-              (widget-put widget :children (list edit)))
+              (push edit children)
+              (widget-put widget :children children))
             (message "Creating face editor...done"))))))
 
-(defvar custom-face-menu 
+(defvar custom-face-menu
   '(("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)))
+       (or (get (widget-value widget) 'saved-face)
+          (get (widget-value widget) 'saved-face-comment))))
     ("Reset to Standard Setting" custom-face-reset-standard
      (lambda (widget)
        (get (widget-value widget) 'face-defface-spec)))
     ("---" ignore ignore)
+    ("Add Comment" custom-comment-show custom-comment-invisible-p)
+    ("---" ignore ignore)
     ("Show all display specs" custom-face-edit-all
      (lambda (widget)
        (not (eq (widget-get widget :custom-form) 'all))))
@@ -2361,15 +2722,30 @@ widget. If FILTER is nil, ACTION is always valid.")
 
 (defun custom-face-state-set (widget)
   "Set the state of WIDGET."
-  (let ((symbol (widget-value widget)))
-    (widget-put widget :custom-state (cond ((get symbol 'customized-face)
-                                           'set)
-                                          ((get symbol 'saved-face)
-                                           'saved)
-                                          ((get symbol 'face-defface-spec)
-                                           'standard)
-                                          (t 
-                                           'rogue)))))
+  (let* ((symbol (widget-value widget))
+        (comment (get symbol 'face-comment))
+        tmp temp)
+    (widget-put widget :custom-state
+               (cond ((progn
+                        (setq tmp (get symbol 'customized-face))
+                        (setq temp (get symbol 'customized-face-comment))
+                        (or tmp temp))
+                      (if (equal temp comment)
+                          'set
+                        'changed))
+                     ((progn
+                        (setq tmp (get symbol 'saved-face))
+                        (setq temp (get symbol 'saved-face-comment))
+                        (or tmp temp))
+                      (if (equal temp comment)
+                          'saved
+                        'changed))
+                     ((get symbol 'face-defface-spec)
+                      (if (equal comment nil)
+                          'standard
+                        'changed))
+                     (t
+                      'rogue)))))
 
 (defun custom-face-action (widget &optional event)
   "Show the menu for `custom-face' WIDGET.
@@ -2390,9 +2766,17 @@ Optional EVENT is the location for the menu."
   "Make the face attributes in WIDGET take effect."
   (let* ((symbol (widget-value widget))
         (child (car (widget-get widget :children)))
-        (value (widget-value child)))
+        (value (widget-value child))
+        (comment-widget (widget-get widget :comment-widget))
+        (comment (widget-value comment-widget)))
+    (when (equal comment "")
+      (setq comment nil)
+      ;; Make the comment invisible by hand if it's empty
+      (custom-comment-hide comment-widget))
     (put symbol 'customized-face value)
     (face-spec-set symbol value)
+    (put symbol 'customized-face-comment comment)
+    (put symbol 'face-comment comment)
     (custom-face-state-set widget)
     (custom-redraw-magic widget)))
 
@@ -2405,10 +2789,20 @@ Optional EVENT is the location for the menu."
   "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)))
+        (value (widget-value child))
+        (comment-widget (widget-get widget :comment-widget))
+        (comment (widget-value comment-widget)))
+    (when (equal comment "")
+      (setq comment nil)
+      ;; Make the comment invisible by hand if it's empty
+      (custom-comment-hide comment-widget))
     (face-spec-set symbol value)
     (put symbol 'saved-face value)
     (put symbol 'customized-face nil)
+    (put symbol 'face-comment comment)
+    (put symbol 'customized-face-comment nil)
+    (put symbol 'saved-face-comment comment)
+    (custom-save-all)
     (custom-face-state-set widget)
     (custom-redraw-magic widget)))
 
@@ -2416,12 +2810,18 @@ Optional EVENT is the location for the menu."
   "Restore WIDGET to the face's default attributes."
   (let* ((symbol (widget-value widget))
         (child (car (widget-get widget :children)))
-        (value (get symbol 'saved-face)))
-    (unless value
+        (value (get symbol 'saved-face))
+        (comment (get symbol 'saved-face-comment))
+        (comment-widget (widget-get widget :comment-widget)))
+    (unless (or value comment)
       (error "No saved value for this face"))
     (put symbol 'customized-face nil)
+    (put symbol 'customized-face-comment nil)
     (face-spec-set symbol value)
+    (put symbol 'face-comment comment)
     (widget-value-set child value)
+    ;; This call manages the comment visibility
+    (widget-value-set comment-widget (or comment ""))
     (custom-face-state-set widget)
     (custom-redraw-magic widget)))
 
@@ -2429,15 +2829,21 @@ Optional EVENT is the location for the menu."
   "Restore WIDGET to the face's standard settings."
   (let* ((symbol (widget-value widget))
         (child (car (widget-get widget :children)))
-        (value (get symbol 'face-defface-spec)))
+        (value (get symbol 'face-defface-spec))
+        (comment-widget (widget-get widget :comment-widget)))
     (unless value
       (error "No standard setting for this face"))
     (put symbol 'customized-face nil)
-    (when (get symbol 'saved-face)
+    (put symbol 'customized-face-comment nil)
+    (when (or (get symbol 'saved-face) (get symbol 'saved-face-comment))
       (put symbol 'saved-face nil)
+      (put symbol 'saved-face-comment nil)
       (custom-save-all))
     (face-spec-set symbol value)
+    (put symbol 'face-comment nil)
     (widget-value-set child value)
+    ;; This call manages the comment visibility
+    (widget-value-set comment-widget "")
     (custom-face-state-set widget)
     (custom-redraw-magic widget)))
 
@@ -2485,7 +2891,7 @@ Optional EVENT is the location for the menu."
                                 (mapcar (lambda (face)
                                           (list (symbol-name face)))
                                         (face-list))
-                                nil nil nil                             
+                                nil nil nil
                                 'face-history)))
     (unless (zerop (length answer))
       (widget-value-set widget (intern answer))
@@ -2502,14 +2908,14 @@ Optional EVENT is the location for the menu."
                         value))
   :match (lambda (widget value)
           (or (symbolp value)
-              (widget-editable-list-match widget value)))
+              (widget-group-match widget value)))
   :convert-widget 'custom-hook-convert-widget
   :tag "Hook")
 
 (defun custom-hook-convert-widget (widget)
   ;; Handle `:custom-options'.
   (let* ((options (widget-get widget :options))
-        (other `(editable-list :inline t 
+        (other `(editable-list :inline t
                                :entry-format "%i %d%v"
                                (function :format " %v")))
         (args (if options
@@ -2536,6 +2942,7 @@ Optional EVENT is the location for the menu."
 
 (defcustom custom-group-tag-faces nil
   ;; In XEmacs, this ought to play games with font size.
+  ;; Fixme: make it do so in Emacs.
   "Face used for group tags.
 The first member is used for level 1 groups, the second for level 2,
 and so forth.  The remaining group tags are shown with
@@ -2621,7 +3028,7 @@ If GROUPS-ONLY non-nil, return only those members that are groups."
                (or members (custom-unloaded-widget-p widget)))
           (custom-browse-insert-prefix prefix)
           (push (widget-create-child-and-convert
-                 widget 'custom-browse-visibility 
+                 widget 'custom-browse-visibility
                  ;; :tag-glyph "plus"
                  :tag "+")
                 buttons)
@@ -2638,7 +3045,7 @@ If GROUPS-ONLY non-nil, return only those members that are groups."
           (insert "[ ]-- ")
           ;; (widget-glyph-insert nil "[ ]" "empty")
           ;; (widget-glyph-insert nil "-- " "horizontal")
-          (push (widget-create-child-and-convert 
+          (push (widget-create-child-and-convert
                  widget 'custom-browse-group-tag)
                 buttons)
           (insert " " tag "\n")
@@ -2647,24 +3054,24 @@ If GROUPS-ONLY non-nil, return only those members that are groups."
           (custom-browse-insert-prefix prefix)
           (custom-load-widget widget)
           (if (zerop (length members))
-              (progn 
+              (progn
                 (custom-browse-insert-prefix prefix)
                 (insert "[ ]-- ")
                 ;; (widget-glyph-insert nil "[ ]" "empty")
                 ;; (widget-glyph-insert nil "-- " "horizontal")
-                (push (widget-create-child-and-convert 
+                (push (widget-create-child-and-convert
                        widget 'custom-browse-group-tag)
                       buttons)
                 (insert " " tag "\n")
                 (widget-put widget :buttons buttons))
-            (push (widget-create-child-and-convert 
-                   widget 'custom-browse-visibility 
+            (push (widget-create-child-and-convert
+                   widget 'custom-browse-visibility
                    ;; :tag-glyph "minus"
                    :tag "-")
                   buttons)
             (insert "-\\ ")
             ;; (widget-glyph-insert nil "-\\ " "top")
-            (push (widget-create-child-and-convert 
+            (push (widget-create-child-and-convert
                    widget 'custom-browse-group-tag)
                   buttons)
             (insert " " tag "\n")
@@ -2709,11 +3116,11 @@ If GROUPS-ONLY non-nil, return only those members that are groups."
           ;; Create link/visibility indicator.
           (if (eq custom-buffer-style 'links)
               (push (widget-create-child-and-convert
-                     widget 'custom-group-link 
+                     widget 'custom-group-link
                      :tag "Go to Group"
                      symbol)
                     buttons)
-            (push (widget-create-child-and-convert 
+            (push (widget-create-child-and-convert
                    widget 'custom-group-visibility
                    :help-echo "Show members of this group."
                    :action 'custom-toggle-parent
@@ -2751,7 +3158,7 @@ If GROUPS-ONLY non-nil, return only those members that are groups."
           ;; Create visibility indicator.
           (unless (eq custom-buffer-style 'links)
             (insert "--------")
-            (push (widget-create-child-and-convert 
+            (push (widget-create-child-and-convert
                    widget 'visibility
                    :help-echo "Hide members of this group."
                    :action 'custom-toggle-parent
@@ -2760,13 +3167,13 @@ If GROUPS-ONLY non-nil, return only those members that are groups."
             (insert " "))
           ;; Create more dashes.
           ;; Use 76 instead of 75 to compensate for the temporary "<"
-          ;; added by `widget-insert'.  
+          ;; 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 
+                        widget 'custom-magic
                         :indent 0
                         nil)))
             (widget-put widget :custom-magic magic)
@@ -2781,7 +3188,7 @@ If GROUPS-ONLY non-nil, return only those members that are groups."
               (when (eq level 1)
                 (insert-char ?\  custom-buffer-indent)
                 (custom-add-parent-links widget)))
-          (custom-add-see-also widget 
+          (custom-add-see-also widget
                                (make-string (* custom-buffer-indent level)
                                             ?\ ))
           ;; Members.
@@ -2825,7 +3232,7 @@ Creating group members... %2d%%"
           (insert-char ?- (- 75 (current-column) (* custom-buffer-indent level)))
           (insert "/\n")))))
 
-(defvar custom-group-menu 
+(defvar custom-group-menu
   '(("Set for Current Session" custom-group-set
      (lambda (widget)
        (eq (widget-get widget :custom-state) 'modified)))
@@ -2846,7 +3253,7 @@ 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
 menu is selected, and FILTER is a predicate which takes a `custom-group'
 widget as an argument, and returns non-nil if ACTION is valid on that
-widget. If FILTER is nil, ACTION is always valid.")
+widget.  If FILTER is nil, ACTION is always valid.")
 
 (defun custom-group-action (widget &optional event)
   "Show the menu for `custom-group' WIDGET.
@@ -2933,53 +3340,88 @@ you need to explicitly load that file for the settings to take effect."
   :type '(choice (const :tag "Your Emacs init file" nil) file)
   :group 'customize)
 
+(defun custom-file ()
+  "Return the file name for saving customizations."
+  (setq custom-file
+       (or custom-file
+           user-init-file
+           (read-file-name "File for customizations: "
+                           "~/" nil nil ".emacs"))))
+
 (defun custom-save-delete (symbol)
-  "Delete the call to SYMBOL form `custom-file'.
+  "Delete the call to SYMBOL from `custom-file'.
 Leave point at the location of the call, or after the last expression."
-  (set-buffer (find-file-noselect (or custom-file user-init-file)))
+  (let ((default-major-mode))
+    (set-buffer (find-file-noselect (custom-file))))
   (goto-char (point-min))
+  ;; Skip all whitespace and comments.
+  (while (forward-comment 1))
+  (or (eobp)
+      (save-excursion (forward-sexp (buffer-size)))) ; Test for scan errors.
   (catch 'found
     (while t
-      (let ((sexp (condition-case nil
+      ;; Skip all whitespace and comments.
+      (while (forward-comment 1))
+      (let ((start (point))
+           (sexp (condition-case nil
                      (read (current-buffer))
                    (end-of-file (throw 'found nil)))))
        (when (and (listp sexp)
                   (eq (car sexp) symbol))
-         (delete-region (save-excursion
-                          (backward-sexp)
-                          (point))
-                        (point))
+         (delete-region start (point))
          (throw 'found nil))))))
 
 (defun custom-save-variables ()
   "Save all customized variables in `custom-file'."
   (save-excursion
     (custom-save-delete 'custom-set-variables)
-    (let ((standard-output (current-buffer)))
+    (let ((standard-output (current-buffer))
+         (saved-list (make-list 1 0))
+         sort-fold-case)
+      ;; First create a sorted list of saved variables.
+      (mapatoms
+       (lambda (symbol)
+        (if (get symbol 'saved-value)
+            (nconc saved-list (list symbol)))))
+      (setq saved-list (sort (cdr saved-list) 'string<))
       (unless (bolp)
        (princ "\n"))
       (princ "(custom-set-variables")
-      (mapatoms (lambda (symbol)
-                 (let ((value (get symbol 'saved-value))
-                       (requests (get symbol 'custom-requests))
-                       (now (not (or (get symbol 'standard-value)
-                                     (and (not (boundp symbol))
-                                          (not (get symbol 'force-value)))))))
-                   (when value
-                     (princ "\n '(")
-                     (princ symbol)
-                     (princ " ")
-                     (prin1 (car value))
-                     (cond (requests
-                            (if now
-                                (princ " t ")
-                              (princ " nil "))
-                            (prin1 requests)
-                            (princ ")"))
-                           (now
-                            (princ " t)"))
-                           (t
-                            (princ ")")))))))
+      (mapcar
+       (lambda (symbol)
+        (let ((value (get symbol 'saved-value))
+              (requests (get symbol 'custom-requests))
+              (now (not (or (get symbol 'standard-value)
+                            (and (not (boundp symbol))
+                                 (not (get symbol 'force-value))))))
+              (comment (get symbol 'saved-variable-comment))
+              sep)
+          (when (or value comment)
+            (princ "\n '(")
+            (prin1 symbol)
+            (princ " ")
+            (prin1 (car value))
+            (cond ((or now requests comment)
+                   (princ " ")
+                   (if now
+                       (princ "t")
+                     (princ "nil"))
+                   (cond ((or requests comment)
+                          (princ " ")
+                          (if requests
+                              (prin1 requests)
+                            (princ "nil"))
+                          (cond (comment
+                                 (princ " ")
+                                 (prin1 comment)
+                                 (princ ")"))
+                                (t
+                                 (princ ")"))))
+                         (t
+                          (princ ")"))))
+                  (t
+                   (princ ")"))))))
+       saved-list)
       (princ ")")
       (unless (looking-at "\n")
        (princ "\n")))))
@@ -2988,34 +3430,48 @@ Leave point at the location of the call, or after the last expression."
   "Save all customized faces in `custom-file'."
   (save-excursion
     (custom-save-delete 'custom-set-faces)
-    (let ((standard-output (current-buffer)))
+    (let ((standard-output (current-buffer))
+         (saved-list (make-list 1 0))
+         sort-fold-case)
+      ;; First create a sorted list of saved faces.
+      (mapatoms
+       (lambda (symbol)
+        (if (get symbol 'saved-face)
+            (nconc saved-list (list symbol)))))
+      (setq saved-list (sort (cdr saved-list) 'string<))
+      ;; The default face must be first, since it affects the others.
+      (if (memq 'default saved-list)
+         (setq saved-list (cons 'default (delq 'default saved-list))))
       (unless (bolp)
        (princ "\n"))
       (princ "(custom-set-faces")
-      (let ((value (get 'default 'saved-face)))
-       ;; The default face must be first, since it affects the others.
-       (when value
-         (princ "\n '(default ")
-         (prin1 value)
-         (if (or (get 'default 'face-defface-spec)
-                 (and (not (custom-facep 'default))
-                      (not (get 'default 'force-face))))
-             (princ ")")
-           (princ " t)"))))
-      (mapatoms (lambda (symbol)
-                 (let ((value (get symbol 'saved-face)))
-                   (when (and (not (eq symbol 'default))
-                              ;; Don't print default face here.
-                              value)
-                     (princ "\n '(")
-                     (princ symbol)
-                     (princ " ")
-                     (prin1 value)
-                     (if (or (get symbol 'face-defface-spec)
-                             (and (not (custom-facep symbol))
-                                  (not (get symbol 'force-face))))
-                         (princ ")")
-                       (princ " t)"))))))
+      (mapcar
+       (lambda (symbol)
+        (let ((value (get symbol 'saved-face))
+              (now (not (or (get 'default 'face-defface-spec)
+                            (and (not (custom-facep 'default))
+                                 (not (get 'default 'force-face))))))
+              (comment (get 'default 'saved-face-comment)))
+          (unless (eq symbol 'default))
+          ;; Don't print default face here.
+          (princ "\n '(")
+          (prin1 symbol)
+          (princ " ")
+          (prin1 value)
+          (cond ((or now comment)
+                 (princ " ")
+                 (if now
+                     (princ "t")
+                   (princ "nil"))
+                 (cond (comment
+                        (princ " ")
+                        (prin1 comment)
+                        (princ ")"))
+                       (t
+                        (princ ")"))))
+                (t
+                 (princ ")")))))
+       saved-list)
       (princ ")")
       (unless (looking-at "\n")
        (princ "\n")))))
@@ -3026,13 +3482,22 @@ Leave point at the location of the call, or after the last expression."
   (interactive)
   (mapatoms (lambda (symbol)
              (let ((face (get symbol 'customized-face))
-                   (value (get symbol 'customized-value)))
-               (when face 
+                   (value (get symbol 'customized-value))
+                   (face-comment (get symbol 'customized-face-comment))
+                   (variable-comment
+                    (get symbol 'customized-variable-comment)))
+               (when face
                  (put symbol 'saved-face face)
                  (put symbol 'customized-face nil))
-               (when value 
+               (when value
                  (put symbol 'saved-value value)
-                 (put symbol 'customized-value nil)))))
+                 (put symbol 'customized-value nil))
+               (when variable-comment
+                 (put symbol 'saved-variable-comment variable-comment)
+                 (put symbol 'customized-variable-comment nil))
+               (when face-comment
+                 (put symbol 'saved-face-comment face-comment)
+                 (put symbol 'customized-face-comment nil)))))
   ;; We really should update all custom buffers here.
   (custom-save-all))
 
@@ -3043,7 +3508,8 @@ Leave point at the location of the call, or after the last expression."
     (custom-save-variables)
     (custom-save-faces)
     (save-excursion
-      (set-buffer (find-file-noselect (or custom-file user-init-file)))
+      (let ((default-major-mode nil))
+       (set-buffer (find-file-noselect (custom-file))))
       (save-buffer))))
 
 ;;; The Customize Menu.
@@ -3080,7 +3546,8 @@ Leave point at the location of the call, or after the last expression."
                                   ':style 'toggle
                                   ':selected symbol)))
 
-(if (string-match "XEmacs" emacs-version)
+;; Fixme: sort out use of :filter in Emacs
+(if nil ; (string-match "XEmacs" emacs-version)
     ;; XEmacs can create menus dynamically.
     (defun custom-group-menu-create (widget symbol)
       "Ignoring WIDGET, create a menu entry for customization group SYMBOL."
@@ -3124,12 +3591,13 @@ The menu is in a format applicable to `easy-menu-define'."
 ;;;###autoload
 (defun customize-menu-create (symbol &optional name)
   "Return a customize menu for customization group SYMBOL.
-If optional NAME is given, use that as the name of the menu. 
+If optional NAME is given, use that as the name of the menu.
 Otherwise the menu will be named `Customize'.
 The format is suitable for use with `easy-menu-define'."
   (unless name
     (setq name "Customize"))
-  (if (string-match "XEmacs" emacs-version)
+  ;; Fixme: sort out use of :filter in Emacs
+  (if nil ;(string-match "XEmacs" emacs-version)
       ;; We can delay it under XEmacs.
       `(,name
        :filter (lambda (&rest junk)
@@ -3148,7 +3616,7 @@ The format is suitable for use with `easy-menu-define'."
   (suppress-keymap custom-mode-map)
   (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 "q" 'Custom-buffer-done)
   (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)
@@ -3164,7 +3632,7 @@ The format is suitable for use with `easy-menu-define'."
        (if button
            (widget-button-click event)))))
 
-(easy-menu-define Custom-mode-menu 
+(easy-menu-define Custom-mode-menu
     custom-mode-map
   "Menu used in customization buffers."
   `("Custom"
@@ -3174,7 +3642,7 @@ The format is suitable for use with `easy-menu-define'."
     ["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]))
+    ["Info" (Info-goto-node "(emacs)Easy Customization") t]))
 
 (defun Custom-goto-parent ()
   "Go to the parent group listed at the top of this buffer.
@@ -3188,7 +3656,7 @@ If several parents are listed, go to the first of them."
          (customize-group parent)))))
 
 (defcustom custom-mode-hook nil
-  "Hook called when entering custom-mode."
+  "Hook called when entering Custom mode."
   :type 'hook
   :group 'custom-buffer )
 
@@ -3226,6 +3694,17 @@ if that value is non-nil."
   (setq widget-documentation-face 'custom-documentation-face)
   (make-local-variable 'widget-button-face)
   (setq widget-button-face 'custom-button-face)
+  (set (make-local-variable 'widget-button-pressed-face)
+       'custom-button-pressed-face)
+  (set (make-local-variable 'widget-mouse-face)
+       'custom-button-pressed-face)    ; buttons `depress' when moused
+  ;; When possible, use relief for buttons, not bracketing.  This test
+  ;; may not be optimal.
+  (when custom-raised-buttons
+    (set (make-local-variable 'widget-push-button-prefix) "")
+    (set (make-local-variable 'widget-push-button-suffix) "")
+    (set (make-local-variable 'widget-link-prefix) "")
+    (set (make-local-variable 'widget-link-suffix) ""))
   (make-local-hook 'widget-edit-functions)
   (add-hook 'widget-edit-functions 'custom-state-buffer-message nil t)
   (run-hooks 'custom-mode-hook))
@@ -3234,4 +3713,4 @@ if that value is non-nil."
 
 (provide 'cus-edit)
 
-;; cus-edit.el ends here
+;;; cus-edit.el ends here