Drew Adams <drew.adams at oracle.com>
[bpt/emacs.git] / lisp / help.el
index 9a779f1..b957f88 100644 (file)
@@ -1,7 +1,7 @@
 ;;; help.el --- help commands for Emacs
 
 ;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999, 2000, 2001, 2002,
-;;   2003, 2004, 2005 Free Software Foundation, Inc.
+;;   2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: help, internal
@@ -10,7 +10,7 @@
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
@@ -46,6 +46,7 @@
     (define-key map "." 'display-local-help)
     (define-key map "?" 'help-for-help)
 
+    (define-key map "\C-a" 'about-emacs)
     (define-key map "\C-c" 'describe-copying)
     (define-key map "\C-d" 'describe-distribution)
     (define-key map "\C-e" 'view-emacs-problems)
@@ -143,7 +144,7 @@ specifies what to do when the user exits the help buffer."
                    ((not (one-window-p t))
                     (setq help-return-method
                           (cons (selected-window) 'quit-window))
-                    "Type \\[switch-to-buffer-other-window] RET to restore the other window.")
+                    "Type \\[display-buffer] RET to restore the other window.")
                    (pop-up-windows
                     (setq help-return-method (cons (selected-window) t))
                     "Type \\[delete-other-windows] to remove help window.")
@@ -178,36 +179,32 @@ specifies what to do when the user exits the help buffer."
 (defalias 'help-for-help 'help-for-help-internal)
 ;; It can't find this, but nobody will look.
 (make-help-screen help-for-help-internal
-  "a b c C e f F i I k C-k l L m p s t v w C-c C-d C-f C-n C-p C-t C-w . or ? :"
+  "a b c C e f F i I k C-k l L m p s t v w C-c C-d C-f C-n C-p C-t C-w . or ? :"
   "You have typed %THIS-KEY%, the help character.  Type a Help option:
 \(Use SPC or DEL to scroll through this text.  Type \\<help-map>\\[help-quit] to exit the Help command.)
 
-a  command-apropos.  Give a list of words or a regexp, to get a list of
-        commands whose names match (they contain two or more of the words,
-       or a match for the regexp).  See also the  apropos  command.
-b  describe-bindings.  Display table of all key bindings.
-c  describe-key-briefly.  Type a command key sequence;
-       it prints the function name that sequence runs.
-C  describe-coding-system.  This describes either a specific coding system
-        (if you type its name) or the coding systems currently in use
-       (if you type just RET).
-d  apropos-documentation.  Give a pattern (a list or words or a regexp), and
-       see a list of functions, variables, and other items whose built-in
-       doucmentation string matches that pattern.  See also the apropos command.
-e  view-echo-area-messages.  Show the buffer where the echo-area messages
-       are stored.
-f  describe-function.  Type a function name and get its documentation.
-F  Info-goto-emacs-command-node.  Type a function name;
-       it takes you to the on-line manual's section that describes
-       the command.
+a  command-apropos.  Type a list of words or a regexp; it shows a list of
+        commands whose names match.  See also the  apropos  command.
+b  describe-bindings.  Display a table of all key bindings.
+c  describe-key-briefly.  Type a key sequence;
+       it displays the command name run by that key sequence.
+C  describe-coding-system.  Type the name of the coding system to describe,
+        or just RET to describe the ones currently in use.
+d  apropos-documentation.  Type a pattern (a list of words or a regexp), and
+       it shows a list of functions, variables, and other items whose
+       documentation matches that pattern.  See also the apropos command.
+e  view-echo-area-messages.  Go to the buffer that logs echo-area messages.
+f  describe-function.  Type a function name and you see its documentation.
+F  Info-goto-emacs-command-node.  Type a command name;
+       it goes to the on-line manual's section that describes the command.
 h  Display the HELLO file which illustrates various scripts.
-i  info. The Info documentation reader: read on-line manuals.
+i  info.  The Info documentation reader: read on-line manuals.
 I  describe-input-method.  Describe a specific input method (if you type
        its name) or the current input method (if you type just RET).
-k  describe-key.  Type a command key sequence;
+k  describe-key.  Type a key sequence;
        it displays the full documentation for that key sequence.
-K Info-goto-emacs-key-command-node.  Type a command key sequence;
-       it takes you to the on-line manual's section that describes
+K  Info-goto-emacs-key-command-node.  Type a key sequence;
+       it goes to the on-line manual's section that describes
        the command bound to that key.
 l  view-lossage.  Show last 100 characters you typed.
 L  describe-language-environment.  This describes either a
@@ -217,17 +214,19 @@ m  describe-mode.  Display documentation of current minor modes,
        and the current major mode, including their special commands.
 n  view-emacs-news.  Display news of recent Emacs changes.
 p  finder-by-keyword. Find packages matching a given topic keyword.
+r  info-emacs-manual.  Display the Emacs manual in Info mode.
 s  describe-syntax.  Display contents of syntax table, plus explanations.
-S  info-lookup-symbol.  Display the definition of a specific symbol
-        as found in the manual for the language this buffer is written in.
+S  info-lookup-symbol.  Type a symbol; it goes to that symbol in the
+        on-line manual for the programming language used in this buffer.
 t  help-with-tutorial.  Select the Emacs learn-by-doing tutorial.
 v  describe-variable.  Type name of a variable;
        it displays the variable's documentation and value.
-w  where-is.  Type command name; it prints which keystrokes
+w  where-is.  Type a command name; it displays which keystrokes
        invoke that command.
 .  display-local-help.  Display any available local help at point
         in the echo area.
 
+C-a Display information about Emacs.
 C-c Display Emacs copying permission (GNU General Public License).
 C-d Display Emacs ordering information.
 C-e Display info about Emacs problems.
@@ -312,7 +311,7 @@ If that doesn't give a function, return nil."
 The prefix described consists of all but the last event
 of the key sequence that ran this command."
   (interactive)
-  (let* ((key (this-command-keys)))
+  (let ((key (this-command-keys)))
     (describe-bindings
      (if (stringp key)
         (substring key 0 (1- (length key)))
@@ -326,63 +325,76 @@ of the key sequence that ran this command."
 ;; run describe-prefix-bindings.
 (setq prefix-help-command 'describe-prefix-bindings)
 
-(defun view-emacs-news (&optional arg)
+(defun view-emacs-news (&optional version)
   "Display info on recent changes to Emacs.
 With argument, display info only for the selected version."
   (interactive "P")
-  (if (not arg)
-      (view-file (expand-file-name "NEWS" data-directory))
-    (let* ((map (sort
-                 (delete-dups
-                  (apply
-                   'nconc
-                   (mapcar
-                    (lambda (file)
-                      (with-temp-buffer
-                        (insert-file-contents
-                         (expand-file-name file data-directory))
-                        (let (res)
-                          (while (re-search-forward
-                                  (if (string-match "^ONEWS\\.[0-9]+$" file)
-                                      "Changes in \\(?:Emacs\\|version\\)?[ \t]*\\([0-9]+\\(?:\\.[0-9]+\\)?\\)"
-                                    "^\* [^0-9\n]*\\([0-9]+\\.[0-9]+\\)") nil t)
-                            (setq res (cons (list (match-string-no-properties 1)
-                                                  file) res)))
-                          res)))
-                    (append '("NEWS" "ONEWS")
-                            (directory-files data-directory nil
-                                             "^ONEWS\\.[0-9]+$" nil)))))
-                 (lambda (a b)
-                   (string< (car b) (car a)))))
-           (current (caar map))
-           (version (completing-read
-                     (format "Read NEWS for the version (default %s): " current)
-                     (mapcar 'car map) nil nil nil nil current))
-           (file (cadr (assoc version map)))
-           res)
-      (if (not file)
-          (error "No news is good news")
-        (view-file (expand-file-name file data-directory))
-        (widen)
-        (goto-char (point-min))
-        (when (re-search-forward
-               (concat (if (string-match "^ONEWS\\.[0-9]+$" file)
-                           "Changes in \\(?:Emacs\\|version\\)?[ \t]*"
-                         "^\* [^0-9\n]*") version)
-               nil t)
-          (beginning-of-line)
-          (narrow-to-region
-           (point)
-           (save-excursion
-             (while (and (setq res
-                               (re-search-forward
-                                (if (string-match "^ONEWS\\.[0-9]+$" file)
-                                    "Changes in \\(?:Emacs\\|version\\)?[ \t]*\\([0-9]+\\(?:\\.[0-9]+\\)?\\)"
-                                  "^\* [^0-9\n]*\\([0-9]+\\.[0-9]+\\)") nil t))
-                         (equal (match-string-no-properties 1) version)))
-             (or res (goto-char (point-max)))
-             (beginning-of-line)
-             (point))))))))
+  (unless version
+    (setq version emacs-major-version))
+  (when (consp version)
+    (let* ((all-versions
+           (let (res)
+             (mapc
+              (lambda (file)
+                (with-temp-buffer
+                  (insert-file-contents
+                   (expand-file-name file data-directory))
+                  (while (re-search-forward
+                          (if (member file '("NEWS.18" "NEWS.1-17"))
+                              "Changes in \\(?:Emacs\\|version\\)?[ \t]*\\([0-9]+\\(?:\\.[0-9]+\\)?\\)"
+                            "^\* [^0-9\n]*\\([0-9]+\\.[0-9]+\\)") nil t)
+                    (setq res (cons (match-string-no-properties 1) res)))))
+              (cons "NEWS"
+                    (directory-files data-directory nil
+                                     "^NEWS\\.[0-9][-0-9]*$" nil)))
+             (sort (delete-dups res) (lambda (a b) (string< b a)))))
+          (current (car all-versions)))
+      (setq version (completing-read
+                    (format "Read NEWS for the version (default %s): " current)
+                    all-versions nil nil nil nil current))
+      (if (integerp (string-to-number version))
+         (setq version (string-to-number version))
+       (unless (or (member version all-versions)
+                   (<= (string-to-number version) (string-to-number current)))
+         (error "No news about version %s" version)))))
+  (when (integerp version)
+    (cond ((<= version 12)
+          (setq version (format "1.%d" version)))
+         ((<= version 18)
+          (setq version (format "%d" version)))
+         ((> version emacs-major-version)
+          (error "No news about Emacs %d (yet)" version))))
+  (let* ((vn (if (stringp version)
+                (string-to-number version)
+              version))
+        (file (cond
+               ((>= vn emacs-major-version) "NEWS")
+               ((< vn 18) "NEWS.1-17")
+               (t (format "NEWS.%d" vn))))
+        res)
+    (view-file (expand-file-name file data-directory))
+    (widen)
+    (goto-char (point-min))
+    (when (stringp version)
+      (when (re-search-forward
+            (concat (if (< vn 19)
+                        "Changes in Emacs[ \t]*"
+                      "^\* [^0-9\n]*") version "$")
+            nil t)
+       (beginning-of-line)
+       (narrow-to-region
+        (point)
+        (save-excursion
+          (while (and (setq res
+                            (re-search-forward
+                             (if (< vn 19)
+                                 "Changes in \\(?:Emacs\\|version\\)?[ \t]*\\([0-9]+\\(?:\\.[0-9]+\\)?\\)"
+                               "^\* [^0-9\n]*\\([0-9]+\\.[0-9]+\\)") nil t))
+                      (equal (match-string-no-properties 1) version)))
+          (or res (goto-char (point-max)))
+          (beginning-of-line)
+          (point)))))))
+
 
 (defun view-todo (&optional arg)
   "Display the Emacs TODO list."
@@ -429,8 +441,9 @@ To record all your input on a file, use `open-dribble-file'."
     (with-current-buffer standard-output
       (goto-char (point-min))
       (while (progn (move-to-column 50) (not (eobp)))
-       (search-forward " " nil t)
-       (insert "\n")))
+        (when (search-forward " " nil t)
+          (delete-char -1))
+        (insert "\n")))
     (print-help-return-message)))
 
 \f
@@ -480,6 +493,7 @@ If INSERT (the prefix arg) is non-nil, insert the message in the buffer."
                  "Where is command: ")
                obarray 'commandp t))
      (list (if (equal val "") fn (intern val)) current-prefix-arg)))
+  (unless definition (error "No command"))
   (let ((func (indirect-function definition))
         (defs nil)
         (standard-output (if insert (current-buffer) t)))
@@ -510,7 +524,7 @@ If INSERT (the prefix arg) is non-nil, insert the message in the buffer."
                (if (> (length keys) 0)
                    (if remapped
                        (format "%s is remapped to %s which is on %s"
-                               definition symbol keys)
+                               symbol remapped keys)
                      (format "%s is on %s" symbol keys))
                  ;; If this is the command the user asked about,
                  ;; and it is not on any key, say so.
@@ -524,28 +538,6 @@ If INSERT (the prefix arg) is non-nil, insert the message in the buffer."
          (princ string)))))
   nil)
 
-(defun string-key-binding (key)
-  "Value is the binding of KEY in a string.
-If KEY is an event on a string, and that string has a `local-map'
-or `keymap' property, return the binding of KEY in the string's keymap."
-  (let* ((defn nil)
-        (start (when (vectorp key)
-                 (if (memq (aref key 0)
-                           '(mode-line header-line left-margin right-margin))
-                     (event-start (aref key 1))
-                   (and (consp (aref key 0))
-                        (event-start (aref key 0))))))
-        (string-info (and (consp start) (nth 4 start))))
-    (when string-info
-      (let* ((string (car string-info))
-            (pos (cdr string-info))
-            (local-map (and (>= pos 0)
-                            (< pos (length string))
-                            (or (get-text-property pos 'local-map string)
-                                (get-text-property pos 'keymap string)))))
-       (setq defn (and local-map (lookup-key local-map key)))))
-    defn))
-
 (defun help-key-description (key untranslated)
   (let ((string (key-description key)))
     (if (or (not untranslated)
@@ -556,52 +548,75 @@ or `keymap' property, return the binding of KEY in the string's keymap."
            string
          (format "%s (translated from %s)" string otherstring))))))
 
-(defun describe-key-briefly (key &optional insert untranslated)
+(defun describe-key-briefly (&optional key insert untranslated)
   "Print the name of the function KEY invokes.  KEY is a string.
 If INSERT (the prefix arg) is non-nil, insert the message in the buffer.
-If non-nil UNTRANSLATED is a vector of the untranslated events.
+If non-nil, UNTRANSLATED is a vector of the untranslated events.
 It can also be a number in which case the untranslated events from
-the last key hit are used."
-  (interactive "kDescribe key briefly: \nP\np")
+the last key hit are used.
+
+If KEY is a menu item or a tool-bar button that is disabled, this command
+temporarily enables it to allow getting help on disabled items and buttons."
+  (interactive
+   (let ((enable-disabled-menus-and-buttons t)
+        (cursor-in-echo-area t)
+        saved-yank-menu)
+     (unwind-protect
+        (let (key)
+          ;; If yank-menu is empty, populate it temporarily, so that
+          ;; "Select and Paste" menu can generate a complete event.
+          (when (null (cdr yank-menu))
+            (setq saved-yank-menu (copy-sequence yank-menu))
+            (menu-bar-update-yank-menu "(any string)" nil))
+          (setq key (read-key-sequence "Describe key (or click or menu item): "))
+          ;; If KEY is a down-event, read and discard the
+          ;; corresponding up-event.  Note that there are also
+          ;; down-events on scroll bars and mode lines: the actual
+          ;; event then is in the second element of the vector.
+          (and (vectorp key)
+               (let ((last-idx (1- (length key))))
+                 (and (eventp (aref key last-idx))
+                      (memq 'down (event-modifiers (aref key last-idx)))))
+               (read-event))
+          (list
+           key
+           (if current-prefix-arg (prefix-numeric-value current-prefix-arg))
+           1))
+       ;; Put yank-menu back as it was, if we changed it.
+       (when saved-yank-menu
+        (setq yank-menu (copy-sequence saved-yank-menu))
+        (fset 'yank-menu (cons 'keymap yank-menu))))))
   (if (numberp untranslated)
       (setq untranslated (this-single-command-raw-keys)))
-  (save-excursion
-    (let ((modifiers (event-modifiers (aref key 0)))
-         (standard-output (if insert (current-buffer) t))
-         window position)
-      ;; For a mouse button event, go to the button it applies to
-      ;; to get the right key bindings.  And go to the right place
-      ;; in case the keymap depends on where you clicked.
-      (if (or (memq 'click modifiers) (memq 'down modifiers)
-             (memq 'drag modifiers))
-         (setq window (posn-window (event-start (aref key 0)))
-               position (posn-point (event-start (aref key 0)))))
-      (if (windowp window)
-         (progn
-           (set-buffer (window-buffer window))
-           (goto-char position)))
-      ;; Ok, now look up the key and name the command.
-      (let ((defn (or (string-key-binding key)
-                     (key-binding key t)))
-           key-desc)
-       ;; Don't bother user with strings from (e.g.) the select-paste menu.
-       (if (stringp (aref key (1- (length key))))
-           (aset key (1- (length key)) "(any string)"))
-       (if (and (> (length untranslated) 0)
-                (stringp (aref untranslated (1- (length untranslated)))))
-           (aset untranslated (1- (length untranslated))
-                 "(any string)"))
-       ;; Now describe the key, perhaps as changed.
-       (setq key-desc (help-key-description key untranslated))
-       (if (or (null defn) (integerp defn) (equal defn 'undefined))
-           (princ (format "%s is undefined" key-desc))
-         (princ (format (if (windowp window)
-                            "%s at that spot runs the command %s"
-                          "%s runs the command %s")
-                        key-desc
-                        (if (symbolp defn) defn (prin1-to-string defn)))))))))
-
-(defun describe-key (key &optional untranslated up-event)
+  (let* ((event (if (and (symbolp (aref key 0))
+                        (> (length key) 1)
+                        (consp (aref key 1)))
+                   (aref key 1)
+                 (aref key 0)))
+        (modifiers (event-modifiers event))
+        (standard-output (if insert (current-buffer) t))
+        (mouse-msg (if (or (memq 'click modifiers) (memq 'down modifiers)
+                           (memq 'drag modifiers)) " at that spot" ""))
+        (defn (key-binding key t))
+        key-desc)
+    ;; Handle the case where we faked an entry in "Select and Paste" menu.
+    (if (and (eq defn nil)
+            (stringp (aref key (1- (length key))))
+            (eq (key-binding (substring key 0 -1)) 'yank-menu))
+       (setq defn 'menu-bar-select-yank))
+    ;; Don't bother user with strings from (e.g.) the select-paste menu.
+    (if (stringp (aref key (1- (length key))))
+       (aset key (1- (length key)) "(any string)"))
+    (if (and (> (length untranslated) 0)
+            (stringp (aref untranslated (1- (length untranslated)))))
+       (aset untranslated (1- (length untranslated)) "(any string)"))
+    ;; Now describe the key, perhaps as changed.
+    (setq key-desc (help-key-description key untranslated))
+    (if (or (null defn) (integerp defn) (equal defn 'undefined))
+       (princ (format "%s%s is undefined" key-desc mouse-msg))
+      (princ (format "%s%s runs the command %S" key-desc mouse-msg defn)))))
+
+(defun describe-key (&optional key untranslated up-event)
   "Display documentation of the function invoked by KEY.
 KEY can be any kind of a key sequence; it can include keyboard events,
 mouse events, and/or menu events.  When calling from a program,
@@ -609,97 +624,139 @@ pass KEY as a string or a vector.
 
 If non-nil, UNTRANSLATED is a vector of the corresponding untranslated events.
 It can also be a number, in which case the untranslated events from
-the last key sequence entered are used."
-  ;; UP-EVENT is the up-event that was discarded by reading KEY, or nil.
-  (interactive "kDescribe key (or click or menu item): \np\nU")
+the last key sequence entered are used.
+UP-EVENT is the up-event that was discarded by reading KEY, or nil.
+
+If KEY is a menu item or a tool-bar button that is disabled, this command
+temporarily enables it to allow getting help on disabled items and buttons."
+  (interactive
+   (let ((enable-disabled-menus-and-buttons t)
+        (cursor-in-echo-area t)
+        saved-yank-menu)
+     (unwind-protect
+        (let (key)
+          ;; If yank-menu is empty, populate it temporarily, so that
+          ;; "Select and Paste" menu can generate a complete event.
+          (when (null (cdr yank-menu))
+            (setq saved-yank-menu (copy-sequence yank-menu))
+            (menu-bar-update-yank-menu "(any string)" nil))
+          (setq key (read-key-sequence "Describe key (or click or menu item): "))
+          (list
+           key
+           (prefix-numeric-value current-prefix-arg)
+           ;; If KEY is a down-event, read and include the
+           ;; corresponding up-event.  Note that there are also
+           ;; down-events on scroll bars and mode lines: the actual
+           ;; event then is in the second element of the vector.
+           (and (vectorp key)
+                (let ((last-idx (1- (length key))))
+                  (and (eventp (aref key last-idx))
+                       (memq 'down (event-modifiers (aref key last-idx)))))
+                (or (and (eventp (aref key 0))
+                         (memq 'down (event-modifiers (aref key 0)))
+                         ;; However, for the C-down-mouse-2 popup
+                         ;; menu, there is no subsequent up-event.  In
+                         ;; this case, the up-event is the next
+                         ;; element in the supplied vector.
+                         (= (length key) 1))
+                    (and (> (length key) 1)
+                         (eventp (aref key 1))
+                         (memq 'down (event-modifiers (aref key 1)))))
+                (read-event))))
+       ;; Put yank-menu back as it was, if we changed it.
+       (when saved-yank-menu
+        (setq yank-menu (copy-sequence saved-yank-menu))
+        (fset 'yank-menu (cons 'keymap yank-menu))))))
   (if (numberp untranslated)
       (setq untranslated (this-single-command-raw-keys)))
-  (save-excursion
-    (let ((modifiers (event-modifiers (aref key 0)))
-         window position)
-      ;; For a mouse button event, go to the button it applies to
-      ;; to get the right key bindings.  And go to the right place
-      ;; in case the keymap depends on where you clicked.
-      (if (or (memq 'click modifiers) (memq 'down modifiers)
-             (memq 'drag modifiers))
-         (setq window (posn-window (event-start (aref key 0)))
-               position (posn-point (event-start (aref key 0)))))
-      (when (windowp window)
-           (set-buffer (window-buffer window))
-       (goto-char position))
-      (let ((defn (or (string-key-binding key) (key-binding key t))))
-       (if (or (null defn) (integerp defn) (equal defn 'undefined))
-           (message "%s is undefined" (help-key-description key untranslated))
-         (help-setup-xref (list #'describe-function defn) (interactive-p))
-         ;; Don't bother user with strings from (e.g.) the select-paste menu.
-         (if (stringp (aref key (1- (length key))))
-             (aset key (1- (length key)) "(any string)"))
-         (if (and untranslated
-                  (stringp (aref untranslated (1- (length untranslated)))))
-             (aset untranslated (1- (length untranslated))
-                   "(any string)"))
-         (with-output-to-temp-buffer (help-buffer)
-           (princ (help-key-description key untranslated))
-           (if (windowp window)
-               (princ " at that spot"))
-           (princ " runs the command ")
-           (prin1 defn)
-           (princ "\n   which is ")
-           (describe-function-1 defn)
-           (when up-event
-             (let ((ev (aref up-event 0))
-                   (descr (key-description up-event))
-                   (hdr "\n\n-------------- up event ---------------\n\n")
-                   defn
-                   mouse-1-tricky mouse-1-remapped)
-               (when (and (consp ev)
-                          (eq (car ev) 'mouse-1)
-                          (windowp window)
+  (let* ((event (aref key (if (and (symbolp (aref key 0))
+                                  (> (length key) 1)
+                                  (consp (aref key 1)))
+                             1
+                           0)))
+        (modifiers (event-modifiers event))
+        (mouse-msg (if (or (memq 'click modifiers) (memq 'down modifiers)
+                           (memq 'drag modifiers)) " at that spot" ""))
+        (defn (key-binding key t))
+        defn-up defn-up-tricky ev-type
+        mouse-1-remapped mouse-1-tricky)
+
+    ;; Handle the case where we faked an entry in "Select and Paste" menu.
+    (when (and (eq defn nil)
+              (stringp (aref key (1- (length key))))
+              (eq (key-binding (substring key 0 -1)) 'yank-menu))
+      (setq defn 'menu-bar-select-yank))
+    (if (or (null defn) (integerp defn) (equal defn 'undefined))
+       (message "%s%s is undefined"
+                (help-key-description key untranslated) mouse-msg)
+      (help-setup-xref (list #'describe-function defn) (interactive-p))
+      ;; Don't bother user with strings from (e.g.) the select-paste menu.
+      (when (stringp (aref key (1- (length key))))
+       (aset key (1- (length key)) "(any string)"))
+      (when (and untranslated
+                (stringp (aref untranslated (1- (length untranslated)))))
+       (aset untranslated (1- (length untranslated))
+             "(any string)"))
+      ;; Need to do this before erasing *Help* buffer in case event
+      ;; is a mouse click in an existing *Help* buffer.
+      (when up-event
+       (setq ev-type (event-basic-type up-event))
+       (let ((sequence (vector up-event)))
+         (when (and (eq ev-type 'mouse-1)
+                    mouse-1-click-follows-link
+                    (not (eq mouse-1-click-follows-link 'double))
+                    (setq mouse-1-remapped
+                          (mouse-on-link-p (event-start up-event))))
+           (setq mouse-1-tricky (and (integerp mouse-1-click-follows-link)
+                                     (> mouse-1-click-follows-link 0)))
+           (cond ((stringp mouse-1-remapped)
+                  (setq sequence mouse-1-remapped))
+                 ((vectorp mouse-1-remapped)
+                  (setcar up-event (elt mouse-1-remapped 0)))
+                 (t (setcar up-event 'mouse-2))))
+         (setq defn-up (key-binding sequence nil nil (event-start up-event)))
+         (when mouse-1-tricky
+           (setq sequence (vector up-event))
+           (aset sequence 0 'mouse-1)
+           (setq defn-up-tricky (key-binding sequence nil nil (event-start up-event))))))
+      (with-output-to-temp-buffer (help-buffer)
+       (princ (help-key-description key untranslated))
+       (princ (format "\
+%s runs the command %S
+  which is "
+                      mouse-msg defn))
+       (describe-function-1 defn)
+       (when up-event
+         (unless (or (null defn-up)
+                     (integerp defn-up)
+                     (equal defn-up 'undefined))
+           (princ (format "
+
+----------------- up-event %s----------------
+
+<%S>%s%s runs the command %S
+  which is "
+                          (if mouse-1-tricky "(short click) " "")
+                          ev-type mouse-msg
+                          (if mouse-1-remapped
+                              " is remapped to <mouse-2>\nwhich" "")
+                          defn-up))
+           (describe-function-1 defn-up))
+         (unless (or (null defn-up-tricky)
+                     (integerp defn-up-tricky)
+                     (eq defn-up-tricky 'undefined))
+           (princ (format "
+
+----------------- up-event (long click) ----------------
+
+Pressing <%S>%s for longer than %d milli-seconds
+runs the command %S
+  which is "
+                          ev-type mouse-msg
                           mouse-1-click-follows-link
-                          (not (eq mouse-1-click-follows-link 'double))
-                          (with-current-buffer (window-buffer window)
-                            (mouse-on-link-p (posn-point (event-start ev)))))
-                 (setq mouse-1-tricky (integerp mouse-1-click-follows-link)
-                       mouse-1-remapped (or (not mouse-1-tricky)
-                                            (> mouse-1-click-follows-link 0)))
-                 (if mouse-1-remapped
-                     (setcar ev 'mouse-2)))
-               (setq defn (or (string-key-binding up-event) (key-binding up-event)))
-               (unless (or (null defn) (integerp defn) (equal defn 'undefined))
-                 (princ (if mouse-1-tricky
-                            "\n\n----------------- up-event (short click) ----------------\n\n"
-                          hdr))
-                 (setq hdr nil)
-                 (princ descr)
-                 (if (windowp window)
-                     (princ " at that spot"))
-                 (if mouse-1-remapped
-                     (princ " is remapped to <mouse-2>\n  which" ))
-                 (princ " runs the command ")
-                 (prin1 defn)
-                 (princ "\n   which is ")
-                 (describe-function-1 defn))
-               (when mouse-1-tricky
-                 (setcar ev
-                         (if (> mouse-1-click-follows-link 0) 'mouse-1 'mouse-2))
-                 (setq defn (or (string-key-binding up-event) (key-binding up-event)))
-                 (unless (or (null defn) (integerp defn) (equal defn 'undefined))
-                   (princ (or hdr
-                              "\n\n----------------- up-event (long click) ----------------\n\n"))
-                   (princ "Pressing ")
-                   (princ descr)
-                   (if (windowp window)
-                       (princ " at that spot"))
-                   (princ (format " for longer than %d milli-seconds\n"
-                                  (abs mouse-1-click-follows-link)))
-                   (if (not mouse-1-remapped)
-                       (princ " remaps it to <mouse-2> which" ))
-                   (princ " runs the command ")
-                   (prin1 defn)
-                   (princ "\n   which is ")
-                   (describe-function-1 defn)))))
-           (print-help-return-message)))))))
-
+                          defn-up-tricky))
+           (describe-function-1 defn-up-tricky)))
+       (print-help-return-message)))))
 \f
 (defun describe-mode (&optional buffer)
   "Display documentation of current major mode and minor modes.
@@ -710,7 +767,7 @@ descriptions of the minor modes, each on a separate page.
 For this to work correctly for a minor mode, the mode's indicator
 variable \(listed in `minor-mode-alist') must also be a function
 whose documentation describes the minor mode."
-  (interactive)
+  (interactive "@")
   (unless buffer (setq buffer (current-buffer)))
   (help-setup-xref (list #'describe-mode buffer)
                   (interactive-p))
@@ -746,16 +803,13 @@ whose documentation describes the minor mode."
              (sort minor-modes
                    (lambda (a b) (string-lessp (cadr a) (cadr b)))))
        (when minor-modes
-         (princ "Summary of minor modes:\n")
+         (princ "Enabled minor modes:\n")
          (make-local-variable 'help-button-cache)
          (with-current-buffer standard-output
            (dolist (mode minor-modes)
              (let ((mode-function (nth 0 mode))
                    (pretty-minor-mode (nth 1 mode))
                    (indicator (nth 2 mode)))
-               (setq indicator (if (zerop (length indicator))
-                                   "no indicator"
-                                 (format "indicator%s" indicator)))
                (add-text-properties 0 (length pretty-minor-mode)
                                     '(face bold) pretty-minor-mode)
                (save-excursion
@@ -764,21 +818,28 @@ whose documentation describes the minor mode."
                  (push (point-marker) help-button-cache)
                  ;; Document the minor modes fully.
                  (insert pretty-minor-mode)
-                 (princ (format " minor mode (%s):\n" indicator))
+                 (princ (format " minor mode (%s):\n"
+                                (if (zerop (length indicator))
+                                    "no indicator"
+                                  (format "indicator%s"
+                                          indicator))))
                  (princ (documentation mode-function)))
-               (princ "  ")
                (insert-button pretty-minor-mode
                               'action (car help-button-cache)
                               'follow-link t
                               'help-echo "mouse-2, RET: show full information")
-               (princ (format " minor mode (%s):\n" indicator)))))
-         (princ "\n(Full information about these minor modes
-follows the description of the major mode.)\n\n"))
+               (newline)))
+           (forward-line -1)
+           (fill-paragraph nil)
+           (forward-line 1))
+
+         (princ "\n(Information about these minor modes follows the major mode info.)\n\n"))
        ;; Document the major mode.
        (let ((mode mode-name))
          (with-current-buffer standard-output
-           (insert mode)
-           (add-text-properties (- (point) (length mode)) (point) '(face bold))))
+            (let ((start (point)))
+              (insert (format-mode-line mode))
+              (add-text-properties start (point) '(face bold)))))
        (princ " mode:\n")
        (princ (documentation major-mode)))
       (print-help-return-message))))
@@ -829,7 +890,7 @@ appeared on the mode-line."
                    (cond
                     ((= 0 (length i))
                      nil)
-                    ((eq (aref i 0) ?\ )
+                    ((eq (aref i 0) ?\s)
                      (substring i 1))
                     (t
                      i))))
@@ -851,7 +912,7 @@ is currently activated with completion."
   "Return a minor mode symbol from its indicator on the modeline."
   ;; remove first space if existed
   (if (and (< 0 (length indicator))
-          (eq (aref indicator 0) ?\ ))
+          (eq (aref indicator 0) ?\s))
       (setq indicator (substring indicator 1)))
   (let ((minor-modes minor-mode-alist)
        result)
@@ -862,7 +923,7 @@ is currently activated with completion."
        ;; remove first space if existed
        (if (and (stringp anindicator)
                 (> (length anindicator) 0)
-                (eq (aref anindicator 0) ?\ ))
+                (eq (aref anindicator 0) ?\s))
            (setq anindicator (substring anindicator 1)))
        (if (equal indicator anindicator)
            (setq result minor-mode
@@ -874,12 +935,12 @@ is currently activated with completion."
 ;;; Automatic resizing of temporary buffers.
 
 (defcustom temp-buffer-max-height (lambda (buffer) (/ (- (frame-height) 2) 2))
-  "*Maximum height of a window displaying a temporary buffer.
-This is the maximum height (in text lines) which `resize-temp-buffer-window'
+  "Maximum height of a window displaying a temporary buffer.
+This is effective only when Temp Buffer Resize mode is enabled.
+The value is the maximum height (in lines) which `resize-temp-buffer-window'
 will give to a window displaying a temporary buffer.
-It can also be a function which will be called with the object corresponding
-to the buffer to be displayed as argument and should return an integer
-positive number."
+It can also be a function to be called to choose the height for such a buffer.
+It gets one argumemt, the buffer, and should return a positive integer."
   :type '(choice integer function)
   :group 'help
   :version "20.4")
@@ -899,22 +960,21 @@ This applies to `help', `apropos' and `completion' buffers, and some others."
     (remove-hook 'temp-buffer-show-hook 'resize-temp-buffer-window)))
 
 (defun resize-temp-buffer-window ()
-  "Resize the current window to fit its contents.
+  "Resize the selected window to fit its contents.
 Will not make it higher than `temp-buffer-max-height' nor smaller than
 `window-min-height'.  Do nothing if it is the only window on its frame, if it
 is not as wide as the frame or if some of the window's contents are scrolled
 out of view."
   (unless (or (one-window-p 'nomini)
               (not (pos-visible-in-window-p (point-min)))
-              (/=  (frame-width) (window-width)))
+              (not (window-full-width-p)))
     (fit-window-to-buffer
      (selected-window)
      (if (functionp temp-buffer-max-height)
         (funcall temp-buffer-max-height (current-buffer))
        temp-buffer-max-height))))
 
-;; Provide this for the sake of define-minor-mode which generates
-;; defcustoms which require 'help'.
+\f
 (provide 'help)
 
 ;; arch-tag: cf427352-27e9-49b7-9a6f-741ebab02423