diff lisp/help.el @ 231:557eaa0339bf r20-5b14

Import from CVS: tag r20-5b14
author cvs
date Mon, 13 Aug 2007 10:13:48 +0200
parents 434959a2fba3
children 52952cbfc5b5
line wrap: on
line diff
--- a/lisp/help.el	Mon Aug 13 10:13:03 2007 +0200
+++ b/lisp/help.el	Mon Aug 13 10:13:48 2007 +0200
@@ -191,7 +191,16 @@
   )
 
 (define-key help-mode-map "q" 'help-mode-quit)
+(define-key help-mode-map "Q" 'help-mode-bury)
 (define-key help-mode-map "f" 'find-function-at-point)
+(define-key help-mode-map "d" 'describe-function-at-point)
+(define-key help-mode-map "v" 'describe-variable-at-point)
+(define-key help-mode-map "i" 'Info-elisp-ref)
+(define-key help-mode-map "c" 'customize-variable)
+(define-key help-mode-map [tab] 'help-next-symbol)
+(define-key help-mode-map [(shift tab)] 'help-prev-symbol)
+(define-key help-mode-map "n" 'help-next-section)
+(define-key help-mode-map "p" 'help-prev-section)
 
 (defun describe-function-at-point ()
   "Describe directly the function at point in the other window."
@@ -199,29 +208,43 @@
   (let ((symb (function-at-point)))
     (when symb
       (describe-function symb))))
+
 (defun describe-variable-at-point ()
   "Describe directly the variable at point in the other window."
   (interactive)
   (let ((symb (variable-at-point)))
     (when symb
       (describe-variable symb))))
+
 (defun help-next-symbol ()
   "Move point to the next quoted symbol."
   (interactive)
   (search-forward "`" nil t))
+
 (defun help-prev-symbol ()
   "Move point to the previous quoted symbol."
   (interactive)
   (search-backward "'" nil t))
-(define-key help-mode-map "d" 'describe-function-at-point)
-(define-key help-mode-map "v" 'describe-variable-at-point)
-(define-key help-mode-map [tab] 'help-next-symbol)
-(define-key help-mode-map [(shift tab)] 'help-prev-symbol)
+
+(defun help-next-section ()
+  "Move point to the next quoted symbol."
+  (interactive)
+  (search-forward-regexp "^\\w+:" nil t))
 
+(defun help-prev-section ()
+  "Move point to the previous quoted symbol."
+  (interactive)
+  (search-backward-regexp "^\\w+:" nil t))
 
-(defun help-mode-quit ()
+(defun help-mode-bury ()
+  "Buries the buffer, possibly restoring the previous window configuration."
+  (interactive)
+  (help-mode-quit t))
+
+(defun help-mode-quit (&optional bury)
   "Exits from help mode, possibly restoring the previous window configuration.
-Bury the help buffer to the end of the buffer list."
+If the optional argument BURY is non-nil, the help buffer is buried,
+otherwise it is killed."
   (interactive)
   (let ((buf (current-buffer)))
     (cond ((frame-property (selected-frame) 'help-window-config)
@@ -230,7 +253,9 @@
 	   (set-frame-property  (selected-frame) 'help-window-config nil))
 	  ((not (one-window-p))
 	   (delete-window)))
-    (bury-buffer buf)))
+    (if bury
+	(bury-buffer buf)
+      (kill-buffer buf))))
 
 (defun help-quit ()
   (interactive)
@@ -390,80 +415,88 @@
   :type 'boolean
   :group 'help-appearance)
 
+(defun help-buffer-name (name)
+  "Return a name for a Help buffer using string NAME for context."
+  (if (stringp name)
+      (format "*Help: %s*" name)
+    "*Help*"))
+
 ;; Use this function for displaying help when C-h something is pressed
 ;; or in similar situations.  Do *not* use it when you are displaying
 ;; a help message and then prompting for input in the minibuffer --
 ;; this macro usually selects the help buffer, which is not what you
 ;; want in those situations.
-
-;;; ### Should really be a macro (as suggested above) to eliminate the
-;;; requirement of caller to code a lambda form in THUNK -- mrb
-(defun with-displaying-help-buffer (thunk)
-  (let ((winconfig (current-window-configuration))
-        (was-one-window (one-window-p))
-	(help-not-visible
-	 (not (and (windows-of-buffer "*Help*") ;shortcut
-		   (member (selected-frame)
-			   (mapcar 'window-frame
-				   (windows-of-buffer "*Help*")))))))
-    (prog1 (with-output-to-temp-buffer "*Help*"
-             (prog1 (funcall thunk)
-               (save-excursion
-                 (set-buffer standard-output)
-                 (help-mode))))
-      (let ((helpwin (get-buffer-window "*Help*")))
-        (when helpwin
-	  (with-current-buffer (window-buffer helpwin)
-	    ;; If the *Help* buffer is already displayed on this
-	    ;; frame, don't override the previous configuration
-	    (when help-not-visible
-	      (set-frame-property (selected-frame)
-				  'help-window-config winconfig)))
-	  (when help-selects-help-window
-	    (select-window helpwin))
-	  (cond ((eq helpwin (selected-window))
-		 (display-message 'command
-		   (substitute-command-keys "Type \\[help-mode-quit] to remove help window, \\[scroll-up] to scroll the help.")))
-		(was-one-window
-		 (display-message 'command
-		   (substitute-command-keys "Type \\[delete-other-windows] to remove help window, \\[scroll-other-window] to scroll the help.")))
-		(t
-		 (display-message 'command
-		   (substitute-command-keys "Type \\[switch-to-buffer-other-window] to restore the other window, \\[scroll-other-window] to scroll the help.")))))))))
+(defmacro with-displaying-help-buffer (name &rest body)
+  "Form which makes a help buffer with given NAME and evaluates BODY there.
+The actual name of the buffer is generated by the function `help-buffer-name'."
+  `(let* ((winconfig (current-window-configuration))
+	  (was-one-window (one-window-p))
+	  (buffer-name (help-buffer-name ,name))
+	  (help-not-visible
+	   (not (and (windows-of-buffer buffer-name) ;shortcut
+		     (member (selected-frame)
+			     (mapcar 'window-frame
+				     (windows-of-buffer buffer-name)))))))
+     (prog1 (with-output-to-temp-buffer buffer-name
+	      (prog1 ,@body
+		(save-excursion
+		  (set-buffer standard-output)
+		  (help-mode))))
+       (let ((helpwin (get-buffer-window buffer-name)))
+	 (when helpwin
+	   (with-current-buffer (window-buffer helpwin)
+	     ;; If the *Help* buffer is already displayed on this
+	     ;; frame, don't override the previous configuration
+	     (when help-not-visible
+	       (set-frame-property (selected-frame)
+				   'help-window-config winconfig)))
+	   (when help-selects-help-window
+	     (select-window helpwin))
+	   (cond ((eq helpwin (selected-window))
+		  (display-message 'command
+		    (substitute-command-keys "Type \\[help-mode-quit] to remove help window, \\[scroll-up] to scroll the help.")))
+		 (was-one-window
+		  (display-message 'command
+		    (substitute-command-keys "Type \\[delete-other-windows] to remove help window, \\[scroll-other-window] to scroll the help.")))
+		 (t
+		  (display-message 'command
+		    (substitute-command-keys "Type \\[switch-to-buffer-other-window] to restore the other window, \\[scroll-other-window] to scroll the help.")))))))))
+(put 'with-displaying-help-buffer 'lisp-indent-function 1)
+(put 'with-displaying-help-buffer 'edebug-form-spec '(form body))
 
 (defun describe-key (key)
   "Display documentation of the function invoked by KEY.
 KEY is a string, or vector of events.
 When called interactively, KEY may also be a menu selection."
   (interactive "kDescribe key: ")
-  (let ((defn (key-or-menu-binding key)))
+  (let ((defn (key-or-menu-binding key))
+	(key-string (key-description key)))
     (if (or (null defn) (integerp defn))
-        (message "%s is undefined" (key-description key))
-      (with-displaying-help-buffer
-       (lambda ()
-	 (princ (key-description key))
-	 (princ " runs ")
-	 (if (symbolp defn) (princ (format "`%S'" defn))
-	   (prin1 defn))
-	 (princ "\n\n")
-	 (cond ((or (stringp defn) (vectorp defn))
-		(let ((cmd (key-binding defn)))
-		  (if (not cmd)
-		      (princ "a keyboard macro")
-		    (progn
-		      (princ "a keyboard macro which runs the command ")
-		      (prin1 cmd)
-		      (princ ":\n\n")
-		      (if (documentation cmd) (princ (documentation cmd)))))))
-	       ((and (consp defn) (not (eq 'lambda (car-safe defn))))
-		(let ((describe-function-show-arglist nil))
-		  (describe-function-1 (car defn) standard-output)))
-	       ((symbolp defn)
-		(describe-function-1 defn standard-output))
-	       ((documentation defn)
-		(princ (documentation defn)))
-	       (t
-		(princ "not documented"))))))))
+        (message "%s is undefined" key-string)
+      (with-displaying-help-buffer (format "key `%s'" key-string)
+	(princ key-string)
+	(princ " runs ")
+	(if (symbolp defn) (princ (format "`%S'" defn))
+	  (prin1 defn))
+	(princ "\n\n")
+	(cond ((or (stringp defn) (vectorp defn))
+	       (let ((cmd (key-binding defn)))
+		 (if (not cmd)
+		     (princ "a keyboard macro")
+		   (progn
+		     (princ "a keyboard macro which runs the command ")
+		     (prin1 cmd)
+		     (princ ":\n\n")
+		     (if (documentation cmd) (princ (documentation cmd)))))))
+	      ((and (consp defn) (not (eq 'lambda (car-safe defn))))
+	       (let ((describe-function-show-arglist nil))
+		 (describe-function-1 (car defn))))
+	      ((symbolp defn)
+	       (describe-function-1 defn))
+	      ((documentation defn)
+	       (princ (documentation defn)))
+	      (t
+	       (princ "not documented")))))))
 
 (defun describe-mode ()
   "Display documentation of current major mode and minor modes.
@@ -471,39 +504,38 @@
 \(listed in `minor-mode-alist') must also be a function whose documentation
 describes the minor mode."
   (interactive)
-  (with-displaying-help-buffer
-   (lambda ()
-     ;; XEmacs change: print the major-mode documentation before
-     ;; the minor modes.
-     (princ mode-name)
-     (princ " mode:\n")
-     (princ (documentation major-mode))
-     (princ "\n\n----\n\n")
-     (let ((minor-modes minor-mode-alist))
-       (while minor-modes
-	 (let* ((minor-mode (car (car minor-modes)))
-		(indicator (car (cdr (car minor-modes)))))
-	   ;; Document a minor mode if it is listed in minor-mode-alist,
-	   ;; bound locally in this buffer, non-nil, and has a function
-	   ;; definition.
-	   (if (and (boundp minor-mode)
-		    (symbol-value minor-mode)
-		    (fboundp minor-mode))
-	       (let ((pretty-minor-mode minor-mode))
-		 (if (string-match "-mode\\'" (symbol-name minor-mode))
-		     (setq pretty-minor-mode
-			   (capitalize
-			    (substring (symbol-name minor-mode)
-				       0 (match-beginning 0)))))
-		 (while (and (consp indicator) (extentp (car indicator)))
-		   (setq indicator (cdr indicator)))
-		 (while (and indicator (symbolp indicator))
-		   (setq indicator (symbol-value indicator)))
-		 (princ (format "%s minor mode (indicator%s):\n"
-				pretty-minor-mode indicator))
-		 (princ (documentation minor-mode))
-		 (princ "\n\n----\n\n"))))
-	 (setq minor-modes (cdr minor-modes)))))))
+  (with-displaying-help-buffer (format "%s mode" mode-name)
+    ;; XEmacs change: print the major-mode documentation before
+    ;; the minor modes.
+    (princ mode-name)
+    (princ " mode:\n")
+    (princ (documentation major-mode))
+    (princ "\n\n----\n\n")
+    (let ((minor-modes minor-mode-alist))
+      (while minor-modes
+	(let* ((minor-mode (car (car minor-modes)))
+	       (indicator (car (cdr (car minor-modes)))))
+	  ;; Document a minor mode if it is listed in minor-mode-alist,
+	  ;; bound locally in this buffer, non-nil, and has a function
+	  ;; definition.
+	  (if (and (boundp minor-mode)
+		   (symbol-value minor-mode)
+		   (fboundp minor-mode))
+	      (let ((pretty-minor-mode minor-mode))
+		(if (string-match "-mode\\'" (symbol-name minor-mode))
+		    (setq pretty-minor-mode
+			  (capitalize
+			   (substring (symbol-name minor-mode)
+				      0 (match-beginning 0)))))
+		(while (and (consp indicator) (extentp (car indicator)))
+		  (setq indicator (cdr indicator)))
+		(while (and indicator (symbolp indicator))
+		  (setq indicator (symbol-value indicator)))
+		(princ (format "%s minor mode (indicator%s):\n"
+			       pretty-minor-mode indicator))
+		(princ (documentation minor-mode))
+		(princ "\n\n----\n\n"))))
+	(setq minor-modes (cdr minor-modes))))))
 
 ;; So keyboard macro definitions are documented correctly
 (fset 'defining-kbd-macro (symbol-function 'start-kbd-macro))
@@ -556,9 +588,8 @@
 If the second argument (prefix arg, interactively) is non-null
 then only the mouse bindings are displayed."
   (interactive (list nil current-prefix-arg))
-  (with-displaying-help-buffer
-   (lambda ()
-     (describe-bindings-1 prefix mouse-only-p))))
+  (with-displaying-help-buffer (format "bindings for %s" major-mode)
+    (describe-bindings-1 prefix mouse-only-p)))
 
 (defun describe-bindings-1 (&optional prefix mouse-only-p)
   (let ((heading (if mouse-only-p
@@ -592,7 +623,8 @@
                                 nil shadow prefix mouse-only-p)
     (when (and prefix function-key-map (not mouse-only-p))
       (insert "\nFunction key map translations:\n" heading)
-      (describe-bindings-internal function-key-map nil nil prefix mouse-only-p))
+      (describe-bindings-internal function-key-map nil nil
+				  prefix mouse-only-p))
     (set-buffer buffer)))
 
 (defun describe-prefix-bindings ()
@@ -607,12 +639,11 @@
     (while (< i (length prefix))
       (aset prefix i (aref key i))
       (setq i (1+ i)))
-    (with-displaying-help-buffer
-     (lambda ()
-       (princ "Key bindings starting with ")
-       (princ (key-description prefix))
-       (princ ":\n\n")
-       (describe-bindings-1 prefix nil)))))
+    (with-displaying-help-buffer (format "%s prefix" (key-description prefix))
+      (princ "Key bindings starting with ")
+      (princ (key-description prefix))
+      (princ ":\n\n")
+      (describe-bindings-1 prefix nil))))
 
 ;; Make C-h after a prefix, when not specifically bound, 
 ;; run describe-prefix-bindings.
@@ -664,31 +695,30 @@
 The number of keys shown is controlled by `view-lossage-key-count'.
 The number of messages shown is controlled by `view-lossage-message-count'."
   (interactive)
-  (with-displaying-help-buffer
-   (lambda ()
-     (princ (key-description (recent-keys view-lossage-key-count)))
-     (save-excursion
-       (set-buffer standard-output)
-       (goto-char (point-min))
-       (insert "Recent keystrokes:\n\n")
-       (while (progn (move-to-column 50) (not (eobp)))
-	 (search-forward " " nil t)
-	 (insert "\n")))
-     ;; XEmacs addition
-     (princ "\n\n\nRecent minibuffer messages (most recent first):\n\n")
-     (save-excursion
-       (let ((buffer (get-buffer-create " *Message-Log*"))
-	     (count 0)
-	     oldpoint)
-	 (set-buffer buffer)
-	 (goto-char (point-max))
-	 (set-buffer standard-output)
-	 (while (and (> (point buffer) (point-min buffer))
-		     (< count view-lossage-message-count))
-	   (setq oldpoint (point buffer))
-	   (forward-line -1 buffer)
-	   (insert-buffer-substring buffer (point buffer) oldpoint)
-	   (setq count (1+ count))))))))
+  (with-displaying-help-buffer "lossage"
+    (princ (key-description (recent-keys view-lossage-key-count)))
+    (save-excursion
+      (set-buffer standard-output)
+      (goto-char (point-min))
+      (insert "Recent keystrokes:\n\n")
+      (while (progn (move-to-column 50) (not (eobp)))
+	(search-forward " " nil t)
+	(insert "\n")))
+    ;; XEmacs addition
+    (princ "\n\n\nRecent minibuffer messages (most recent first):\n\n")
+    (save-excursion
+      (let ((buffer (get-buffer-create " *Message-Log*"))
+	    (count 0)
+	    oldpoint)
+	(set-buffer buffer)
+	(goto-char (point-max))
+	(set-buffer standard-output)
+	(while (and (> (point buffer) (point-min buffer))
+		    (< count view-lossage-message-count))
+	  (setq oldpoint (point buffer))
+	  (forward-line -1 buffer)
+	  (insert-buffer-substring buffer (point buffer) oldpoint)
+	  (setq count (1+ count)))))))
 
 (define-function 'help 'help-for-help)
 
@@ -731,64 +761,66 @@
 \\[describe-copying]	XEmacs copying permission (General Public License)."
   help-map)
 
+(defmacro with-syntax-table (syntab &rest body)
+  "Evaluate BODY with the syntax-table SYNTAB"
+  `(let ((stab (syntax-table)))
+     (unwind-protect
+	 (progn
+	   (set-syntax-table (copy-syntax-table ,syntab))
+	   ,@body)
+       (set-syntax-table stab))))
+(put 'with-syntax-table 'lisp-indent-function 1)
+(put 'with-syntax-table 'edebug-form-spec '(form body))
+
 (defun function-called-at-point ()
   "Return the function which is called by the list containing point.
 If that gives no function, return the function whose name is around point.
 If that doesn't give a function, return nil."
-  (or (condition-case ()
+  (or (ignore-errors
+	(save-excursion
+	  (save-restriction
+	    (narrow-to-region (max (point-min) (- (point) 1000))
+			      (point-max))
+	    (backward-up-list 1)
+	    (forward-char 1)
+	    (let (obj)
+	      (setq obj (read (current-buffer)))
+	      (and (symbolp obj) (fboundp obj) obj)))))
+      (ignore-errors
+	(with-syntax-table emacs-lisp-mode-syntax-table
 	  (save-excursion
-	    (save-restriction
-	      (narrow-to-region (max (point-min) (- (point) 1000)) (point-max))
-	      (backward-up-list 1)
-	      (forward-char 1)
-	      (let (obj)
-		(setq obj (read (current-buffer)))
-		(and (symbolp obj) (fboundp obj) obj))))
-	(error nil))
-      (condition-case ()
-	  (let ((stab (syntax-table)))
-	    (unwind-protect
-		(save-excursion
-		  (set-syntax-table emacs-lisp-mode-syntax-table)
-		  (or (not (zerop (skip-syntax-backward "_w")))
-		      (eq (char-syntax (char-after (point))) ?w)
-		      (eq (char-syntax (char-after (point))) ?_)
-		      (forward-sexp -1))
-		  (skip-chars-forward "`'")
-		  (let ((obj (read (current-buffer))))
-		    (and (symbolp obj) (fboundp obj) obj)))
-	      (set-syntax-table stab)))
-	(error nil))))
+	    (or (not (zerop (skip-syntax-backward "_w")))
+		(eq (char-syntax (char-after (point))) ?w)
+		(eq (char-syntax (char-after (point))) ?_)
+		(forward-sexp -1))
+	    (skip-chars-forward "`'")
+	    (let ((obj (read (current-buffer))))
+	      (and (symbolp obj) (fboundp obj) obj)))))))
 
 (defun function-at-point ()
   "Return the function whose name is around point.
 If that gives no function, return the function which is called by the
 list containing point.  If that doesn't give a function, return nil."
-  (or (condition-case ()
-	  (let ((stab (syntax-table)))
-	    (unwind-protect
-		(save-excursion
-		  (set-syntax-table emacs-lisp-mode-syntax-table)
-		  (or (not (zerop (skip-syntax-backward "_w")))
-		      (eq (char-syntax (char-after (point))) ?w)
-		      (eq (char-syntax (char-after (point))) ?_)
-		      (forward-sexp -1))
-		  (skip-chars-forward "`'")
-		  (let ((obj (read (current-buffer))))
-		    (and (symbolp obj) (fboundp obj) obj)))
-	      (set-syntax-table stab)))
-	(error nil))
-      (condition-case ()
+  (or (ignore-errors
+	(with-syntax-table emacs-lisp-mode-syntax-table
 	  (save-excursion
-	    (save-restriction
-	      (narrow-to-region (max (point-min) (- (point) 1000))
-				(point-max))
-	      (backward-up-list 1)
-	      (forward-char 1)
-	      (let (obj)
-		(setq obj (read (current-buffer)))
-		(and (symbolp obj) (fboundp obj) obj))))
-	(error nil))))
+	    (or (not (zerop (skip-syntax-backward "_w")))
+		(eq (char-syntax (char-after (point))) ?w)
+		(eq (char-syntax (char-after (point))) ?_)
+		(forward-sexp -1))
+	    (skip-chars-forward "`'")
+	    (let ((obj (read (current-buffer))))
+	      (and (symbolp obj) (fboundp obj) obj)))))
+      (ignore-errors
+	(save-excursion
+	  (save-restriction
+	    (narrow-to-region (max (point-min) (- (point) 1000))
+			      (point-max))
+	    (backward-up-list 1)
+	    (forward-char 1)
+	    (let (obj)
+	      (setq obj (read (current-buffer)))
+	      (and (symbolp obj) (fboundp obj) obj)))))))
 
 ;; Default to nil for the non-hackers?  Not until we find a way to
 ;; distinguish hackers from non-hackers automatically!
@@ -822,11 +854,8 @@
                         (gettext "Describe function: "))
                     obarray 'fboundp t nil 'function-history))))
       (list (if (equal val "") fn (intern val)))))
-  (with-displaying-help-buffer
-   (lambda ()
-     (describe-function-1 function standard-output)
-     ;; Return the text we displayed.
-     (buffer-string nil nil standard-output))))
+  (with-displaying-help-buffer (format "function `%s'" function)
+    (describe-function-1 function)))
 
 (defun function-obsolete-p (function)
   "Return non-nil if FUNCTION is obsolete."
@@ -878,13 +907,56 @@
 ;(gettext "an autoloaded Lisp macro")
 ;(gettext "an interactive autoloaded Lisp macro")
 
-(defun describe-function-1 (function stream &optional nodoc)
-  (princ (format "`%S' is " function) stream)
+;; taken out of `describe-function-1'
+(defun function-arglist (function)
+  "Returns a string giving the argument list of FUNCTION.
+For example:
+
+	(function-arglist 'function-arglist)
+	=> (function-arglist FUNCTION)
+
+This function is used by `describe-function-1' to list function
+arguments in the standard Lisp style."
+  (let* ((fndef (symbol-function function))
+	 (arglist
+	 (cond ((compiled-function-p fndef)
+		(compiled-function-arglist fndef))
+	       ((eq (car-safe fndef) 'lambda)
+		(nth 1 fndef))
+	       ((subrp fndef)
+		(let ((doc (documentation function)))
+		  (if (string-match "[\n\t ]*\narguments: ?(\\(.*\\))\n?\\'"
+				    doc)
+		      (substring doc (match-beginning 1) (match-end 1)))))
+	       (t t))))
+    (cond ((listp arglist)
+	   (prin1-to-string
+	    (cons function (mapcar (lambda (arg)
+				     (if (memq arg '(&optional &rest))
+					 arg
+				       (intern (upcase (symbol-name arg)))))
+				   arglist))
+	    t))
+	  ((stringp arglist)
+	   (format "(%s %s)" function arglist)))))
+
+(defun function-documentation (function &optional strip-arglist)
+  "Returns a string giving the documentation for FUNCTION if any.  
+If the optional argument STRIP-ARGLIST is non-nil remove the arglist
+part of the documentation of internal subroutines."
+  (let ((doc (condition-case nil
+		 (or (documentation function)
+		     (gettext "not documented"))
+	       (void-function ""))))
+    (if (and strip-arglist
+	     (string-match "[\n\t ]*\narguments: ?(\\(.*\\))\n?\\'" doc))
+	(setq doc (substring doc 0 (match-beginning 0))))
+    doc))
+
+(defun describe-function-1 (function &optional nodoc)
+  "This function does the work for `describe-function'."
+  (princ (format "`%S' is " function))
   (let* ((def function)
-         (doc (condition-case nil
-		  (or (documentation function)
-		      (gettext "not documented"))
-		(void-function "")))
 	 aliases file-name autoload-file kbd-macro-p fndef macrop)
     (while (and (symbolp def) (fboundp def))
       (when (not (eq def function))
@@ -905,7 +977,7 @@
 			     (compiled-function-annotation (cdr def)))
 	      macrop t)
       (setq fndef def))
-    (if aliases (princ aliases stream))
+    (if aliases (princ aliases))
     (let ((int #'(lambda (string an-p macro-p)
 		   (princ (format
 			   (gettext (concat
@@ -915,10 +987,9 @@
 					   (t "a "))
 				     "%s"
 				     (if macro-p " macro" " function")))
-			   string)
-			  stream))))
+			   string)))))
       (cond ((or (stringp def) (vectorp def))
-             (princ "a keyboard macro." stream)
+             (princ "a keyboard macro.")
 	     (setq kbd-macro-p t))
             ((subrp fndef)
              (funcall int "built-in" nil macrop))
@@ -927,7 +998,7 @@
 ;	     XEmacs -- we handle aliases above.
 ;            ((symbolp fndef)
 ;             (princ (format "alias for `%s'"
-;			    (prin1-to-string def)) stream))
+;			    (prin1-to-string def))))
             ((eq (car-safe fndef) 'lambda)
              (funcall int "Lisp" nil macrop))
             ((eq (car-safe fndef) 'mocklisp)
@@ -936,50 +1007,29 @@
 	     (setq autoload-file (elt def 1))
 	     (funcall int "autoloaded Lisp" t (elt def 4)))
 	    ((and (symbolp def) (not (fboundp def)))
-	     (princ "a symbol with a void (unbound) function definition." stream))
+	     (princ "a symbol with a void (unbound) function definition."))
             (t
              nil)))
-    (princ "\n" stream)
+    (princ "\n")
     (if autoload-file
-	(princ (format "  -- autoloads from \"%s\"\n" autoload-file) stream))
+	(princ (format "  -- autoloads from \"%s\"\n" autoload-file)))
     (or file-name
 	(setq file-name (describe-function-find-file function)))
     (if file-name
-	(princ (format "  -- loaded from \"%s\"\n" file-name)) stream)
-;;     (terpri stream)
+	(princ (format "  -- loaded from \"%s\"\n" file-name)))
+;;     (terpri)
     (if describe-function-show-arglist
-        (let ((arglist
-	       (cond ((compiled-function-p fndef)
-		      (compiled-function-arglist fndef))
-		     ((eq (car-safe fndef) 'lambda)
-		      (nth 1 fndef))
-		     ((and (subrp fndef)
-			   (string-match
-			    "[\n\t ]*\narguments: ?(\\(.*\\))\n?\\'"
-			    doc))
-		      (prog1
-			  (substring doc (match-beginning 1) (match-end 1))
-			(setq doc (substring doc 0 (match-beginning 0)))))
-		     (t t))))
-	  (if (listp arglist)
-	      (progn
-;; 		(princ "  ")
-		(princ (cons function
-			     (mapcar (lambda (arg)
-				       (if (memq arg '(&optional &rest))
-					   arg
-					 (intern (upcase (symbol-name arg)))))
-				       arglist)) stream)
-		(terpri stream)))
-	  (if (stringp arglist)
-	      (princ (format "(%s %s)\n" function arglist) stream))))
-    (terpri stream)
+	(let ((arglist (function-arglist function)))
+	  (when arglist
+	    (princ arglist)
+	    (terpri))))
+    (terpri)
     (cond (kbd-macro-p
-	   (princ "These characters are executed:\n\n\t" stream)
-	   (princ (key-description def) stream)
+	   (princ "These characters are executed:\n\n\t")
+	   (princ (key-description def))
 	   (cond ((setq def (key-binding def))
-		  (princ (format "\n\nwhich executes the command %S.\n\n" def) stream)
-		  (describe-function-1 def stream))))
+		  (princ (format "\n\nwhich executes the command %S.\n\n" def))
+		  (describe-function-1 def))))
 	  (nodoc nil)
 	  (t
 	   ;; tell the user about obsoleteness.
@@ -989,56 +1039,42 @@
 	   (let ((obsolete (function-obsoleteness-doc function))
 		 (compatible (function-compatibility-doc function)))
 	     (when obsolete
-	       (princ obsolete stream)
-	       (terpri stream)
-	       (terpri stream))
+	       (princ obsolete)
+	       (terpri)
+	       (terpri))
 	     (when compatible
-	       (princ compatible stream)
-	       (terpri stream)
-	       (terpri stream))
+	       (princ compatible)
+	       (terpri)
+	       (terpri))
 	     (unless (and obsolete aliases)
-	       (princ doc stream)
-	       (unless (or (equal doc "")
-			   (eq ?\n (aref doc (1- (length doc)))))
-		 (terpri stream))))))))
+	       (let ((doc (function-documentation function t)))
+		 (princ "Documentation:\n")
+		 (princ doc)
+		 (unless (or (equal doc "")
+			     (eq ?\n (aref doc (1- (length doc)))))
+		   (terpri)))))))))
 
 
-;;; this doesn't seem to be used for anything
-;;; Wrong!  Obnoxious, whining people who complain very LOUDLY on Usenet
-;;; are binding this to keys.
+;;; [Obnoxious, whining people who complain very LOUDLY on Usenet
+;;; are binding this to keys.]
 (defun describe-function-arglist (function)
   (interactive (list (or (function-at-point)
 			 (error "no function call at point"))))
-  (let ((b nil))
-    (unwind-protect
-	(save-excursion
-	  (set-buffer (setq b (get-buffer-create " *arglist*")))
-	  (buffer-disable-undo b)
-	  (erase-buffer)
-	  (describe-function-1 function b t)
-	  (goto-char (point-min))
-	  (end-of-line)
-	  (or (eobp) (delete-char 1))
-	  (just-one-space)
-	  (end-of-line)
-	  (message (buffer-substring (point-min) (point))))
-      (and b (kill-buffer b)))))
+  (message nil)
+  (message (function-arglist function)))
 
 
 (defun variable-at-point ()
   (ignore-errors
-    (let ((stab (syntax-table)))
-      (unwind-protect
-	  (save-excursion
-	    (set-syntax-table emacs-lisp-mode-syntax-table)
-	    (or (not (zerop (skip-syntax-backward "_w")))
-		(eq (char-syntax (char-after (point))) ?w)
-		(eq (char-syntax (char-after (point))) ?_)
-		(forward-sexp -1))
-	    (skip-chars-forward "'")
-	    (let ((obj (read (current-buffer))))
-	      (and (symbolp obj) (boundp obj) obj)))
-	(set-syntax-table stab)))))
+    (with-syntax-table emacs-lisp-mode-syntax-table
+      (save-excursion
+	(or (not (zerop (skip-syntax-backward "_w")))
+	    (eq (char-syntax (char-after (point))) ?w)
+	    (eq (char-syntax (char-after (point))) ?_)
+	    (forward-sexp -1))
+	(skip-chars-forward "'")
+	(let ((obj (read (current-buffer))))
+	  (and (symbolp obj) (boundp obj) obj))))))
 
 (defun variable-obsolete-p (variable)
   "Return non-nil if VARIABLE is obsolete."
@@ -1087,6 +1123,22 @@
        (if type "an unknown type of built-in variable?"
 	 "a variable declared in Lisp")))))
 
+(defun help-pretty-print-value (object)
+  "Print OBJECT in current buffer.
+Use `pp-internal' if defined, otherwise `cl-prettyprint'"
+  (princ
+   (with-output-to-string
+     (with-syntax-table emacs-lisp-mode-syntax-table
+       ;; print `#<...>' values better
+       (modify-syntax-entry ?< "(>")
+       (modify-syntax-entry ?> ")<")
+       (let ((indent-line-function 'lisp-indent-line))
+	 (if (fboundp 'pp-internal)
+	     (progn
+	       (pp-internal object "\n")
+	       (terpri))
+	   (cl-prettyprint object)))))))
+
 (defun describe-variable (variable)
   "Display the full documentation of VARIABLE (a symbol)."
   (interactive 
@@ -1098,78 +1150,75 @@
                        (gettext "Describe variable: "))
                    obarray 'boundp t nil 'variable-history))))
      (list (if (equal val "") v (intern val)))))
-  (with-displaying-help-buffer
-   (lambda ()
-     (let ((origvar variable)
-	   aliases)
-       (let ((print-escape-newlines t))
-	 (princ (format "`%s' is " (symbol-name variable)))
-	 (while (variable-alias variable)
-	   (let ((newvar (variable-alias variable)))
-	     (if aliases
-		 ;; I18N3 Need gettext due to concat
-		 (setq aliases
-		       (concat aliases 
-			       (format "\n     which is an alias for `%s', "
-				       (symbol-name newvar))))
-	       (setq aliases
-		     (format "an alias for `%s', "
-			     (symbol-name newvar))))
-	     (setq variable newvar)))
-	 (if aliases
-	     (princ (format "%s" aliases)))
-	 (princ (built-in-variable-doc variable))
- 	 (princ ".\n\n")
-	 (princ "Value: ")
-	 (if (not (boundp variable))
-	     (princ "void")
-	   (prin1 (symbol-value variable)))
-	 (terpri)
-	 (cond ((local-variable-p variable (current-buffer))
-		(let* ((void (cons nil nil))
-		       (def (condition-case nil
-				(default-value variable)
-			      (error void))))
-		  (princ "This value is specific to the current buffer.")
-		  (terpri)
-		  (if (local-variable-p variable nil)
-		      (progn
-			(princ "(Its value is local to each buffer.)")
-			(terpri)))
-		  (if (if (eq def void)
-			  (boundp variable)
-			(not (eq (symbol-value variable) def)))
-		      ;; #### I18N3 doesn't localize properly!
-		      (progn (princ "Its default-value is ")
-			     (if (eq def void)
-				 (princ "void.")
-			       (prin1 def))
-			     (terpri)))))
-	       ((local-variable-p variable (current-buffer) t)
-		(princ "Setting it would make its value buffer-local.\n"))))
-       (terpri)
-       (princ "Documentation:")
-       (terpri)
-       (let ((doc (documentation-property variable 'variable-documentation))
-	     (obsolete (variable-obsoleteness-doc origvar))
-	     (compatible (variable-compatibility-doc origvar)))
-	 (when obsolete
-	   (princ obsolete)
-	   (terpri)
-	   (terpri))
-	 (when compatible
-	   (princ compatible)
-	   (terpri)
-	   (terpri))
-	 ;; don't bother to print anything if variable is obsolete and aliased.
-	 (when (or (not obsolete) (not aliases))
-	   (if doc
-	       ;; note: documentation-property calls substitute-command-keys.
-	       (princ doc)
-	     (princ "not documented as a variable."))
-	   (terpri)))
-       ;; Return the text we displayed.
-       (buffer-string nil nil standard-output)))))
+  (with-displaying-help-buffer (format "variable `%s'" variable)
+    (let ((origvar variable)
+	  aliases)
+      (let ((print-escape-newlines t))
+	(princ (format "`%s' is " (symbol-name variable)))
+	(while (variable-alias variable)
+	  (let ((newvar (variable-alias variable)))
+	    (if aliases
+		;; I18N3 Need gettext due to concat
+		(setq aliases
+		      (concat aliases 
+			      (format "\n     which is an alias for `%s',"
+				      (symbol-name newvar))))
+	      (setq aliases
+		    (format "an alias for `%s',"
+			    (symbol-name newvar))))
+	    (setq variable newvar)))
+	(if aliases
+	    (princ (format "%s" aliases)))
+	(princ (built-in-variable-doc variable))
+	(princ ".\n")
+	(let ((file-name (describe-function-find-file variable)))
+	     (if file-name
+		 (princ (format "  -- loaded from \"%s\"\n" file-name))))
+	(princ "\nValue: ")
+	(if (not (boundp variable))
+	    (princ "void\n")
+	  (help-pretty-print-value (symbol-value variable)))
+	(terpri)
+	(cond ((local-variable-p variable (current-buffer))
+	       (let* ((void (cons nil nil))
+		      (def (condition-case nil
+			       (default-value variable)
+			     (error void))))
+		 (princ "This value is specific to the current buffer.\n")
+		 (if (local-variable-p variable nil)
+		     (princ "(Its value is local to each buffer.)\n"))
+		 (terpri)
+		 (if (if (eq def void)
+			 (boundp variable)
+		       (not (eq (symbol-value variable) def)))
+		     ;; #### I18N3 doesn't localize properly!
+		     (progn (princ "Default-value: ")
+			    (if (eq def void)
+				(princ "void\n")
+			      (help-pretty-print-value def))
+			    (terpri)))))
+	      ((local-variable-p variable (current-buffer) t)
+	       (princ "Setting it would make its value buffer-local.\n\n"))))
+      (princ "Documentation:")
+      (terpri)
+      (let ((doc (documentation-property variable 'variable-documentation))
+	    (obsolete (variable-obsoleteness-doc origvar))
+	    (compatible (variable-compatibility-doc origvar)))
+	(when obsolete
+	  (princ obsolete)
+	  (terpri)
+	  (terpri))
+	(when compatible
+	  (princ compatible)
+	  (terpri)
+	  (terpri))
+	;; don't bother to print anything if variable is obsolete and aliased.
+	(when (or (not obsolete) (not aliases))
+	  (if doc
+	      ;; note: documentation-property calls substitute-command-keys.
+	      (princ doc)
+	    (princ "not documented as a variable."))))
+      (terpri))))
 
 (defun sorted-key-descriptions (keys &optional separator)
   "Sort and separate the key descriptions for KEYS.
@@ -1209,10 +1258,9 @@
   "Describe the syntax specifications in the syntax table.
 The descriptions are inserted in a buffer, which is then displayed."
   (interactive)
-  (with-displaying-help-buffer
-   (lambda ()
-     ;; defined in syntax.el
-     (describe-syntax-table (syntax-table) standard-output))))
+  (with-displaying-help-buffer (format "syntax-table for %s" major-mode)
+    ;; defined in syntax.el
+    (describe-syntax-table (syntax-table) standard-output)))
 
 (defun list-processes ()
   "Display a list of all processes.
@@ -1224,57 +1272,54 @@
     (buffer-disable-undo standard-output)
     (make-local-variable 'truncate-lines)
     (setq truncate-lines t)
-    (let ((stream standard-output))
-      ;;      00000000001111111111222222222233333333334444444444
-      ;;      01234567890123456789012345678901234567890123456789
-      ;; rewritten for I18N3.  This one should stay rewritten
-      ;; so that the dashes will line up properly.
-      (princ "Proc         Status   Buffer         Tty         Command\n----         ------   ------         ---         -------\n" stream)
-      (let ((tail (process-list)))
-        (while tail
-          (let* ((p (car tail))
-                 (pid (process-id p))
-                 (s (process-status p)))
-            (setq tail (cdr tail))
-            (princ (format "%-13s" (process-name p)) stream)
-            ;(if (and (eq system-type 'vax-vms)
-            ;         (eq s 'signal)
-            ;         (< (process-exit-status p) NSIG))
-            ;    (princ (aref sys_errlist (process-exit-status p)) stream))
-            (princ s stream)
-            (if (and (eq s 'exit) (/= (process-exit-status p) 0))
-                (princ (format " %d" (process-exit-status p)) stream))
-            (if (memq s '(signal exit closed))
-                ;; Do delete-exited-processes' work
-                (delete-process p))
-            (indent-to 22 1)            ;####
-            (let ((b (process-buffer p)))
-              (cond ((not b)
-                     (princ "(none)" stream))
-                    ((not (buffer-name b))
-                     (princ "(killed)" stream))
-                    (t
-                     (princ (buffer-name b) stream))))
-            (indent-to 37 1)            ;####
-            (let ((tn (process-tty-name p)))
-              (cond ((not tn)
-                     (princ "(none)" stream))
-                    (t
-                     (princ (format "%s" tn) stream))))
-            (indent-to 49 1)            ;####
-            (if (not (integerp pid))
-                (progn
-                  (princ "network stream connection " stream)
-                  (princ (car pid) stream)
-                  (princ "@" stream)
-                  (princ (cdr pid) stream))
-	      (let ((cmd (process-command p)))
-		(while cmd
-		  (princ (car cmd) stream)
-		  (setq cmd (cdr cmd))
-		  (if cmd (princ " " stream)))))
-            (terpri stream)))))))
-
-;; `find-function' et al moved to "find-func.el"
+    ;;      00000000001111111111222222222233333333334444444444
+    ;;      01234567890123456789012345678901234567890123456789
+    ;; rewritten for I18N3.  This one should stay rewritten
+    ;; so that the dashes will line up properly.
+    (princ "Proc         Status   Buffer         Tty         Command\n----         ------   ------         ---         -------\n")
+    (let ((tail (process-list)))
+      (while tail
+	(let* ((p (car tail))
+	       (pid (process-id p))
+	       (s (process-status p)))
+	  (setq tail (cdr tail))
+	  (princ (format "%-13s" (process-name p)))
+	  ;;(if (and (eq system-type 'vax-vms)
+	  ;;         (eq s 'signal)
+	  ;;        (< (process-exit-status p) NSIG))
+	  ;;    (princ (aref sys_errlist (process-exit-status p))))
+	  (princ s)
+	  (if (and (eq s 'exit) (/= (process-exit-status p) 0))
+	      (princ (format " %d" (process-exit-status p))))
+	  (if (memq s '(signal exit closed))
+	      ;; Do delete-exited-processes' work
+	      (delete-process p))
+	  (indent-to 22 1)		;####
+	  (let ((b (process-buffer p)))
+	    (cond ((not b)
+		   (princ "(none)"))
+		  ((not (buffer-name b))
+		   (princ "(killed)"))
+		  (t
+		   (princ (buffer-name b)))))
+	  (indent-to 37 1)		;####
+	  (let ((tn (process-tty-name p)))
+	    (cond ((not tn)
+		   (princ "(none)"))
+		  (t
+		   (princ (format "%s" tn)))))
+	  (indent-to 49 1)		;####
+	  (if (not (integerp pid))
+	      (progn
+		(princ "network stream connection ")
+		(princ (car pid))
+		(princ "@")
+		(princ (cdr pid)))
+	    (let ((cmd (process-command p)))
+	      (while cmd
+		(princ (car cmd))
+		(setq cmd (cdr cmd))
+		(if cmd (princ " ")))))
+	  (terpri))))))
 
 ;;; help.el ends here