]> code.delx.au - gnu-emacs/blobdiff - lisp/help.el
Missing paren.
[gnu-emacs] / lisp / help.el
index 672933d42f77205397a07806032b421d0606dfb0..22f5a82032edb31354e1d62ca5d25b4fcb6ad8f5 100644 (file)
@@ -1,6 +1,6 @@
 ;;; help.el --- help commands for Emacs
 
 ;;; help.el --- help commands for Emacs
 
-;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: help, internal
 
 ;; Maintainer: FSF
 ;; Keywords: help, internal
 (defvar help-xref-stack nil
   "A stack of ways by which to return to help buffers after following xrefs.
 Used by `help-follow' and `help-xref-go-back'.
 (defvar help-xref-stack nil
   "A stack of ways by which to return to help buffers after following xrefs.
 Used by `help-follow' and `help-xref-go-back'.
-An element looks like (POSITION FUNCTION ARGS...).
-To use the element, do (apply FUNCTION ARGS) then (goto-char POSITION).")
+An element looks like (POSITION FUNCTION ARGS...), where POSITION is
+`(POINT . BUFFER-NAME)'.
+To use the element, do (apply FUNCTION ARGS) then goto the point in
+the named buffer.")
 (put 'help-xref-stack 'permanent-local t)
 
 (defvar help-xref-stack-item nil
 (put 'help-xref-stack 'permanent-local t)
 
 (defvar help-xref-stack-item nil
@@ -149,7 +151,7 @@ Commands:
 (add-hook 'temp-buffer-setup-hook 'help-mode-setup)
 
 (defun help-mode-finish ()
 (add-hook 'temp-buffer-setup-hook 'help-mode-setup)
 
 (defun help-mode-finish ()
-  (when (eq major-mode 'help-mode) 
+  (when (eq major-mode 'help-mode)
     ;; View mode's read-only status of existing *Help* buffer is lost
     ;; by with-output-to-temp-buffer.
     (toggle-read-only 1)
     ;; View mode's read-only status of existing *Help* buffer is lost
     ;; by with-output-to-temp-buffer.
     (toggle-read-only 1)
@@ -272,6 +274,10 @@ If FUNCTION is nil, applies `message' to it, thus printing it."
                     ;; Secondly, the buffer has not been displayed yet,
                     ;; so we don't know whether its frame will be selected.
                     nil)
                     ;; Secondly, the buffer has not been displayed yet,
                     ;; so we don't know whether its frame will be selected.
                     nil)
+                   (display-buffer-reuse-frames
+                    (setq help-return-method (cons (selected-window)
+                                                   'quit-window))
+                    nil)
                    ((not (one-window-p t))
                     (setq help-return-method
                           (cons (selected-window) 'quit-window))
                    ((not (one-window-p t))
                     (setq help-return-method
                           (cons (selected-window) 'quit-window))
@@ -287,9 +293,8 @@ If FUNCTION is nil, applies `message' to it, thus printing it."
         (funcall (or function 'message)
                  (concat
                   (if first-message
         (funcall (or function 'message)
                  (concat
                   (if first-message
-                      (substitute-command-keys first-message)
-                    "")
-                  (if first-message "  " "")
+                      (substitute-command-keys first-message))
+                  (if first-message "  ")
                   ;; If the help buffer will go in a separate frame,
                   ;; it's no use mentioning a command to scroll, so don't.
                   (if (special-display-p (buffer-name standard-output))
                   ;; If the help buffer will go in a separate frame,
                   ;; it's no use mentioning a command to scroll, so don't.
                   (if (special-display-p (buffer-name standard-output))
@@ -356,7 +361,8 @@ For minor modes, see following pages.\n\n"))
          ;; Document a minor mode if it is listed in minor-mode-alist,
          ;; bound locally in this buffer, non-nil, and has a function
          ;; definition.
          ;; 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 (symbol-value minor-mode)
+         (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))
                   (fboundp minor-mode))
              (let ((pretty-minor-mode minor-mode))
                (if (string-match "-mode$" (symbol-name minor-mode))
@@ -430,18 +436,25 @@ of the key sequence that ran this command."
 
 (defun view-emacs-news (&optional arg)
   "Display info on recent changes to Emacs.
 
 (defun view-emacs-news (&optional arg)
   "Display info on recent changes to Emacs.
-With numeric argument display information on correspondingly older changes."
+With numeric argument, display information on correspondingly older changes."
   (interactive "P")
   (interactive "P")
-  (let* ((arg (if arg (prefix-numeric-value arg) 0)))
-    (find-file-read-only
-     (expand-file-name (concat (make-string arg ?O) "NEWS")
-                      data-directory))))
+  (let* ((arg (if arg (prefix-numeric-value arg) 0))
+        (file (cond ((eq arg 0) "NEWS")
+                    ((eq arg 1) "ONEWS")
+                    (t
+                     (nth (- arg 2)
+                          (nreverse (directory-files data-directory
+                                                     nil "^NEWS\\.[0-9]+$"
+                                                     nil)))))))
+    (if file
+       (find-file-read-only (expand-file-name file data-directory))
+      (error "No such old news"))))
 
 (defun view-emacs-FAQ ()
   "Display the Emacs Frequently Asked Questions (FAQ) file."
   (interactive)
 ;;;  (find-file-read-only (expand-file-name "FAQ" data-directory))
 
 (defun view-emacs-FAQ ()
   "Display the Emacs Frequently Asked Questions (FAQ) file."
   (interactive)
 ;;;  (find-file-read-only (expand-file-name "FAQ" data-directory))
-  (info "(emacs-faq)"))
+  (info "(efaq)"))
 
 (defun view-emacs-problems ()
   "Display info on known problems with Emacs and possible workarounds."
 
 (defun view-emacs-problems ()
   "Display info on known problems with Emacs and possible workarounds."
@@ -524,35 +537,32 @@ C-w Display information on absence of warranty for GNU Emacs."
 (defun function-called-at-point ()
   "Return a function around point or else called by the list containing point.
 If that doesn't give a function, return nil."
 (defun function-called-at-point ()
   "Return a function around point or else called by the list containing point.
 If that doesn't give a function, return nil."
-  (let ((stab (syntax-table)))
-    (set-syntax-table emacs-lisp-mode-syntax-table)
-    (unwind-protect
-       (or (condition-case ()
-               (save-excursion
-                 (or (not (zerop (skip-syntax-backward "_w")))
-                     (eq (char-syntax (following-char)) ?w)
-                     (eq (char-syntax (following-char)) ?_)
-                     (forward-sexp -1))
-                 (skip-chars-forward "'")
-                 (let ((obj (read (current-buffer))))
-                   (and (symbolp obj) (fboundp obj) obj)))
-             (error nil))
-           (condition-case ()
-               (save-excursion
-                 (save-restriction
-                   (narrow-to-region (max (point-min) (- (point) 1000)) (point-max))
-                   ;; Move up to surrounding paren, then after the open.
-                   (backward-up-list 1)
-                   (forward-char 1)
-                   ;; If there is space here, this is probably something
-                   ;; other than a real Lisp function call, so ignore it.
-                   (if (looking-at "[ \t]")
-                       (error "Probably not a Lisp function call"))
-                   (let (obj)
-                     (setq obj (read (current-buffer)))
-                     (and (symbolp obj) (fboundp obj) obj))))
-             (error nil)))
-      (set-syntax-table stab))))
+  (with-syntax-table emacs-lisp-mode-syntax-table
+    (or (condition-case ()
+           (save-excursion
+             (or (not (zerop (skip-syntax-backward "_w")))
+                 (eq (char-syntax (following-char)) ?w)
+                 (eq (char-syntax (following-char)) ?_)
+                 (forward-sexp -1))
+             (skip-chars-forward "'")
+             (let ((obj (read (current-buffer))))
+               (and (symbolp obj) (fboundp obj) obj)))
+         (error nil))
+       (condition-case ()
+           (save-excursion
+             (save-restriction
+               (narrow-to-region (max (point-min)
+                                      (- (point) 1000)) (point-max))
+               ;; Move up to surrounding paren, then after the open.
+               (backward-up-list 1)
+               (forward-char 1)
+               ;; If there is space here, this is probably something
+               ;; other than a real Lisp function call, so ignore it.
+               (if (looking-at "[ \t]")
+                   (error "Probably not a Lisp function call"))
+               (let ((obj (read (current-buffer))))
+                 (and (symbolp obj) (fboundp obj) obj))))
+         (error nil)))))
 
 (defvar symbol-file-load-history-loaded nil
   "Non-nil means we have loaded the file `fns-VERSION.el' in `exec-directory'.
 
 (defvar symbol-file-load-history-loaded nil
   "Non-nil means we have loaded the file `fns-VERSION.el' in `exec-directory'.
@@ -620,7 +630,9 @@ It can also be nil, if the definition is not associated with any file."
                     (vectorp def))
                 "a keyboard macro")
                ((subrp def)
                     (vectorp def))
                 "a keyboard macro")
                ((subrp def)
-                (concat beg "built-in function"))
+                (if (eq 'unevalled (cdr (subr-arity def)))
+                    (concat beg "special form")
+                  (concat beg "built-in function")))
                ((byte-code-function-p def)
                 (concat beg "compiled Lisp function"))
                ((symbolp def)
                ((byte-code-function-p def)
                 (concat beg "compiled Lisp function"))
                ((symbolp def)
@@ -661,7 +673,8 @@ It can also be nil, if the definition is not associated with any file."
       (save-excursion
        (save-match-data
          (if (re-search-backward "alias for `\\([^`']+\\)'" nil t)
       (save-excursion
        (save-match-data
          (if (re-search-backward "alias for `\\([^`']+\\)'" nil t)
-             (help-xref-button 1 #'describe-function def)))))
+             (help-xref-button 1 #'describe-function def
+                               "mouse-2, RET: describe this function")))))
     (or file-name
        (setq file-name (symbol-file function)))
     (if file-name
     (or file-name
        (setq file-name (symbol-file function)))
     (if file-name
@@ -680,7 +693,8 @@ It can also be nil, if the definition is not associated with any file."
                                             (find-function-noselect arg)))
                                        (pop-to-buffer (car location))
                                        (goto-char (cdr location))))
                                             (find-function-noselect arg)))
                                        (pop-to-buffer (car location))
                                        (goto-char (cdr location))))
-                               function)))))
+                               function
+                               "mouse-2, RET: find function's definition")))))
     (if need-close (princ ")"))
     (princ ".")
     (terpri)
     (if need-close (princ ")"))
     (princ ".")
     (terpri)
@@ -713,19 +727,35 @@ It can also be nil, if the definition is not associated with any file."
       (if doc
          (progn (terpri)
                 (princ doc)
       (if doc
          (progn (terpri)
                 (princ doc)
-                (with-current-buffer standard-output
-                  (beginning-of-line)
-                  ;; Builtins get the calling sequence at the end of
-                  ;; the doc string.  Move it to the same place as
-                  ;; for other functions.
-                  (when (looking-at (format "(%S[ )]" function))
-                    (let ((start (point-marker)))
-                      (goto-char (point-min))
-                      (forward-paragraph)
-                      (insert-buffer-substring (current-buffer) start)
-                      (insert ?\n)
-                      (delete-region (1- start) (point-max))
-                      (goto-char (point-max)))))
+                (if (subrp (symbol-function function))
+                    (with-current-buffer standard-output
+                      (beginning-of-line)
+                      ;; Builtins get the calling sequence at the end of
+                      ;; the doc string.  Move it to the same place as
+                      ;; for other functions.
+
+                      ;; In cases where `function' has been fset to a
+                      ;; subr we can't search for function's name in
+                      ;; the doc string.  Kluge round that using the
+                      ;; printed representation.  The arg list then
+                      ;; shows the wrong function name, but that
+                      ;; might be a useful hint.
+                      (let* ((rep (prin1-to-string def))
+                             (name (progn
+                                     (string-match " \\([^ ]+\\)>$" rep)
+                                     (match-string 1 rep))))
+                        (if (looking-at (format "(%s[ )]" name))
+                            (let ((start (point-marker)))
+                              (goto-char (point-min))
+                              (forward-paragraph)
+                              (insert-buffer-substring (current-buffer) start)
+                              (insert ?\n)
+                              (delete-region (1- start) (point-max)))
+                          (goto-char (point-min))
+                          (forward-paragraph)
+                          (insert
+                           "[Missing arglist.  Please make a bug report.]\n")))
+                      (goto-char (point-max))))
                 (help-setup-xref (list #'describe-function function)
                                  interactive-p))
        (princ "not documented")))))
                 (help-setup-xref (list #'describe-function function)
                                  interactive-p))
        (princ "not documented")))))
@@ -734,77 +764,120 @@ It can also be nil, if the definition is not associated with any file."
   "Return the bound variable symbol found around point.
 Return 0 if there is no such symbol."
   (condition-case ()
   "Return the bound variable symbol found around point.
 Return 0 if there is no such symbol."
   (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 (following-char)) ?w)
-                 (eq (char-syntax (following-char)) ?_)
-                 (forward-sexp -1))
-             (skip-chars-forward "'")
-             (let ((obj (read (current-buffer))))
-               (or (and (symbolp obj) (boundp obj) obj)
-                   0)))
-         (set-syntax-table stab)))
+      (with-syntax-table emacs-lisp-mode-syntax-table
+       (save-excursion
+         (or (not (zerop (skip-syntax-backward "_w")))
+             (eq (char-syntax (following-char)) ?w)
+             (eq (char-syntax (following-char)) ?_)
+             (forward-sexp -1))
+         (skip-chars-forward "'")
+         (let ((obj (read (current-buffer))))
+           (or (and (symbolp obj) (boundp obj) obj)
+               0))))
     (error 0)))
 
     (error 0)))
 
-(defun describe-variable (variable)
+(defun help-xref-on-pp (from to)
+  "Add xrefs for symbols in `pp's output between FROM and TO."
+  (let ((ost (syntax-table)))
+    (unwind-protect
+       (save-excursion
+         (save-restriction
+           (set-syntax-table emacs-lisp-mode-syntax-table)
+           (narrow-to-region from to)
+           (goto-char (point-min))
+           (while (not (eobp))
+             (cond
+              ((looking-at "\"") (forward-sexp 1))
+              ((looking-at "#<") (search-forward ">" nil 'move))
+              ((looking-at "\\(\\(\\sw\\|\\s_\\)+\\)")
+               (let* ((sym (intern-soft (match-string 1)))
+                      (fn (cond ((fboundp sym) #'describe-function)
+                                ((or (memq sym '(t nil))
+                                     (keywordp sym))
+                                 nil)
+                                ((and sym (boundp sym))
+                                 #'describe-variable))))
+                 (when fn (help-xref-button 1 fn sym)))
+               (goto-char (match-end 1)))
+              (t (forward-char 1))))))
+      (set-syntax-table ost))))
+
+(defun describe-variable (variable &optional buffer)
   "Display the full documentation of VARIABLE (a symbol).
   "Display the full documentation of VARIABLE (a symbol).
-Returns the documentation as a string, also."
-  (interactive 
+Returns the documentation as a string, also.
+If VARIABLE has a buffer-local value in BUFFER (default to the current buffer),
+it is displayed along with the global value."
+  (interactive
    (let ((v (variable-at-point))
         (enable-recursive-minibuffers t)
         val)
      (setq val (completing-read (if (symbolp v)
    (let ((v (variable-at-point))
         (enable-recursive-minibuffers t)
         val)
      (setq val (completing-read (if (symbolp v)
-                                   (format "Describe variable (default %s): " v)
+                                   (format
+                                    "Describe variable (default %s): " v)
                                  "Describe variable: ")
                                obarray 'boundp t nil nil
                                (if (symbolp v) (symbol-name v))))
      (list (if (equal val "")
               v (intern val)))))
                                  "Describe variable: ")
                                obarray 'boundp t nil nil
                                (if (symbolp v) (symbol-name v))))
      (list (if (equal val "")
               v (intern val)))))
-  (if (symbolp variable)
-      (let (valvoid)
+  (unless (bufferp buffer) (setq buffer (current-buffer)))
+  (if (not (symbolp variable))
+      (message "You did not specify a variable")
+    (let (valvoid)
+      (with-current-buffer buffer
        (with-output-to-temp-buffer "*Help*"
          (prin1 variable)
          (if (not (boundp variable))
              (progn
                (princ " is void")
        (with-output-to-temp-buffer "*Help*"
          (prin1 variable)
          (if (not (boundp variable))
              (progn
                (princ " is void")
-               (terpri)
                (setq valvoid t))
                (setq valvoid t))
-           (princ "'s value is ")
-           (terpri)
-           (pp (symbol-value variable))
-           (terpri))
+           (let ((val (symbol-value variable)))
+             (with-current-buffer standard-output
+               (princ "'s value is ")
+               (terpri)
+               (let ((from (point)))
+                 (pp val)
+                 (help-xref-on-pp from (point))))))
+         (terpri)
          (if (local-variable-p variable)
              (progn
                (princ (format "Local in buffer %s; " (buffer-name)))
                (if (not (default-boundp variable))
                    (princ "globally void")
          (if (local-variable-p variable)
              (progn
                (princ (format "Local in buffer %s; " (buffer-name)))
                (if (not (default-boundp variable))
                    (princ "globally void")
-                 (princ "global value is ")
-                 (terpri)
-                 (pp (default-value variable)))
+                 (let ((val (default-value variable)))
+                   (with-current-buffer standard-output
+                     (princ "global value is ")
+                     (terpri)
+                     ;; Fixme: pp can take an age if you happen to
+                     ;; ask for a very large expression.  We should
+                     ;; probably print it raw once and check it's a
+                     ;; sensible size before prettyprinting.  -- fx
+                     (let ((from (point)))
+                       (pp val)
+                       (help-xref-on-pp from (point))))))
                (terpri)))
          (terpri)
                (terpri)))
          (terpri)
-         (save-current-buffer
-           (set-buffer standard-output)
+         (with-current-buffer standard-output
            (if (> (count-lines (point-min) (point-max)) 10)
                (progn
            (if (> (count-lines (point-min) (point-max)) 10)
                (progn
+                 ;; Note that setting the syntax table like below
+                 ;; makes forward-sexp move over a `'s' at the end
+                 ;; of a symbol.
                  (set-syntax-table emacs-lisp-mode-syntax-table)
                  (goto-char (point-min))
                  (if valvoid
                      (forward-line 1)
                    (forward-sexp 1)
                    (delete-region (point) (progn (end-of-line) (point)))
                  (set-syntax-table emacs-lisp-mode-syntax-table)
                  (goto-char (point-min))
                  (if valvoid
                      (forward-line 1)
                    (forward-sexp 1)
                    (delete-region (point) (progn (end-of-line) (point)))
-                   (insert "'s value is shown below.\n\n")
+                   (insert " value is shown below.\n\n")
                    (save-excursion
                      (insert "\n\nValue:"))))))
          (princ "Documentation:")
          (terpri)
          (let ((doc (documentation-property variable 'variable-documentation)))
            (princ (or doc "not documented as a variable.")))
                    (save-excursion
                      (insert "\n\nValue:"))))))
          (princ "Documentation:")
          (terpri)
          (let ((doc (documentation-property variable 'variable-documentation)))
            (princ (or doc "not documented as a variable.")))
-          (help-setup-xref (list #'describe-variable variable) (interactive-p))
-
+          (help-setup-xref (list #'describe-variable variable (current-buffer))
+                          (interactive-p))
+         
          ;; Make a link to customize if this variable can be customized.
          ;; Note, it is not reliable to test only for a custom-type property
          ;; because those are only present after the var's definition
          ;; Make a link to customize if this variable can be customized.
          ;; Note, it is not reliable to test only for a custom-type property
          ;; because those are only present after the var's definition
@@ -818,11 +891,14 @@ Returns the documentation as a string, also."
                (princ (concat "You can " customize-label " this variable."))
                (with-current-buffer "*Help*"
                  (save-excursion
                (princ (concat "You can " customize-label " this variable."))
                (with-current-buffer "*Help*"
                  (save-excursion
-                   (re-search-backward 
+                   (re-search-backward
                     (concat "\\(" customize-label "\\)") nil t)
                     (concat "\\(" customize-label "\\)") nil t)
-                   (help-xref-button 1 #'(lambda (v)
-                                           (customize-variable v)) variable)
-                   ))))
+                   (help-xref-button 1 (lambda (v)
+                                         (if help-xref-stack
+                                             (pop help-xref-stack))
+                                         (customize-variable v))
+                                     variable
+                                     "mouse-2, RET: customize variable")))))
          ;; Make a hyperlink to the library if appropriate.  (Don't
          ;; change the format of the buffer's initial line in case
          ;; anything expects the current format.)
          ;; Make a hyperlink to the library if appropriate.  (Don't
          ;; change the format of the buffer's initial line in case
          ;; anything expects the current format.)
@@ -834,19 +910,19 @@ Returns the documentation as a string, also."
              (with-current-buffer "*Help*"
                (save-excursion
                  (re-search-backward "`\\([^`']+\\)'" nil t)
              (with-current-buffer "*Help*"
                (save-excursion
                  (re-search-backward "`\\([^`']+\\)'" nil t)
-                 (help-xref-button 1 (lambda (arg)
-                                       (let ((location
-                                              (find-variable-noselect arg)))
-                                         (pop-to-buffer (car location))
-                                         (goto-char (cdr location))))
-                                   variable)))))
+                 (help-xref-button
+                  1 (lambda (arg)
+                      (let ((location
+                             (find-variable-noselect arg)))
+                        (pop-to-buffer (car location))
+                        (goto-char (cdr location))))
+                  variable "mouse-2, RET: find variable's definition")))))
 
          (print-help-return-message)
          (save-excursion
            (set-buffer standard-output)
            ;; Return the text we displayed.
 
          (print-help-return-message)
          (save-excursion
            (set-buffer standard-output)
            ;; Return the text we displayed.
-           (buffer-string))))
-    (message "You did not specify a variable")))
+           (buffer-string)))))))
 
 (defun describe-bindings (&optional prefix buffer)
   "Show a list of all defined keys, and their definitions.
 
 (defun describe-bindings (&optional prefix buffer)
   "Show a list of all defined keys, and their definitions.
@@ -909,9 +985,9 @@ and the file name is displayed in the echo area."
                     t))
   (let (result)
     (catch 'answer
                     t))
   (let (result)
     (catch 'answer
-      (mapcar
+      (mapc
        (lambda (dir)
        (lambda (dir)
-        (mapcar
+        (mapc
          (lambda (suf)
            (let ((try (expand-file-name (concat library suf) dir)))
              (and (file-readable-p try)
          (lambda (suf)
            (let ((try (expand-file-name (concat library suf) dir)))
              (and (file-readable-p try)
@@ -973,6 +1049,7 @@ Must be previously-defined."
 (defconst help-xref-symbol-regexp
   (purecopy (concat "\\(\\<\\(\\(variable\\|option\\)\\|"
                    "\\(function\\|command\\)\\|"
 (defconst help-xref-symbol-regexp
   (purecopy (concat "\\(\\<\\(\\(variable\\|option\\)\\|"
                    "\\(function\\|command\\)\\|"
+                   "\\(face\\)\\|"
                    "\\(symbol\\)\\)\\s-+\\)?"
                    ;; Note starting with word-syntax character:
                    "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'"))
                    "\\(symbol\\)\\)\\s-+\\)?"
                    ;; Note starting with word-syntax character:
                    "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'"))
@@ -981,6 +1058,14 @@ Must be previously-defined."
 The words preceding the quoted symbol can be used in doc strings to
 distinguish references to variables, functions and symbols.")
 
 The words preceding the quoted symbol can be used in doc strings to
 distinguish references to variables, functions and symbols.")
 
+(defconst help-xref-mule-regexp nil
+  "Regexp matching doc string references to MULE-related keywords.
+
+It is usually nil, and is temporarily bound to an appropriate regexp
+when help commands related to multilingual environment (e.g.,
+`describe-coding-system') are invoked.")
+
+
 (defconst help-xref-info-regexp
   (purecopy "\\<[Ii]nfo[ \t\n]+node[ \t\n]+`\\([^']+\\)'")
   "Regexp matching doc string references to an Info node.")
 (defconst help-xref-info-regexp
   (purecopy "\\<[Ii]nfo[ \t\n]+node[ \t\n]+`\\([^']+\\)'")
   "Regexp matching doc string references to an Info node.")
@@ -996,6 +1081,9 @@ items for help buffer \"back\" buttons is cleared."
       (setq help-xref-stack nil))
   (setq help-xref-stack-item item))
 
       (setq help-xref-stack nil))
   (setq help-xref-stack-item item))
 
+(defvar help-xref-following nil
+  "Non-nil when following a help cross-reference.")
+
 (defun help-make-xrefs (&optional buffer)
   "Parse and hyperlink documentation cross-references in the given BUFFER.
 
 (defun help-make-xrefs (&optional buffer)
   "Parse and hyperlink documentation cross-references in the given BUFFER.
 
@@ -1006,6 +1094,11 @@ with `help-follow'.  Cross-references have the canonical form `...'
 and the type of reference may be disambiguated by the preceding
 word(s) used in `help-xref-symbol-regexp'.
 
 and the type of reference may be disambiguated by the preceding
 word(s) used in `help-xref-symbol-regexp'.
 
+If the variable `help-xref-mule-regexp' is non-nil, find also
+cross-reference information related to multilingual environment
+\(e.g., coding-systems).  This variable is also used to disambiguate
+the type of reference as the same way as `help-xref-symbol-regexp'.
+
 A special reference `back' is made to return back through a stack of
 help buffers.  Variable `help-back-label' specifies the text for
 that."
 A special reference `back' is made to return back through a stack of
 help buffers.  Variable `help-back-label' specifies the text for
 that."
@@ -1031,42 +1124,102 @@ that."
                    (save-match-data
                      (unless (string-match "^([^)]+)" data)
                        (setq data (concat "(emacs)" data))))
                    (save-match-data
                      (unless (string-match "^([^)]+)" data)
                        (setq data (concat "(emacs)" data))))
-                   (help-xref-button 1 #'info data))))
+                   (help-xref-button 1 #'info data
+                                     "mouse-2, RET: read this Info node"))))
+             ;; Mule related keywords.  Do this before trying
+             ;; `help-xref-symbol-regexp' because some of Mule
+             ;; keywords have variable or function definitions.
+             (if help-xref-mule-regexp
+                 (save-excursion
+                   (while (re-search-forward help-xref-mule-regexp nil t)
+                     (let* ((data (match-string 7))
+                            (sym (intern-soft data)))
+                       (cond
+                        ((match-string 3) ; coding system
+                         (and sym (coding-system-p sym)
+                              (help-xref-button
+                               7 #'describe-coding-system sym
+                               "mouse-2, RET: describe this coding system")))
+                        ((match-string 4) ; input method
+                         (and (assoc data input-method-alist)
+                              (help-xref-button
+                               7 #'describe-input-method data
+                               "mouse-2, RET: describe this input method")))
+                        ((or (match-string 5) (match-string 6)) ; charset
+                         (and sym (charsetp sym)
+                              (help-xref-button
+                               7 #'describe-character-set sym
+                               "mouse-2, RET: describe this character set")))
+                        ((assoc data input-method-alist)
+                         (help-xref-button
+                          7 #'describe-input-method data
+                          "mouse-2, RET: describe this input method"))
+                        ((and sym (coding-system-p sym))
+                         (help-xref-button
+                          7 #'describe-coding-system sym
+                          "mouse-2, RET: describe this coding system"))
+                        ((and sym (charsetp sym))
+                         (help-xref-button
+                          7 #'describe-character-set sym
+                          "mouse-2, RET: describe this character set")))))))
               ;; Quoted symbols
               (save-excursion
                 (while (re-search-forward help-xref-symbol-regexp nil t)
               ;; Quoted symbols
               (save-excursion
                 (while (re-search-forward help-xref-symbol-regexp nil t)
-                  (let* ((data (match-string 6))
+                  (let* ((data (match-string 7))
                          (sym (intern-soft data)))
                     (if sym
                         (cond
                          ((match-string 3) ; `variable' &c
                           (and (boundp sym) ; `variable' doesn't ensure
                                         ; it's actually bound
                          (sym (intern-soft data)))
                     (if sym
                         (cond
                          ((match-string 3) ; `variable' &c
                           (and (boundp sym) ; `variable' doesn't ensure
                                         ; it's actually bound
-                               (help-xref-button 6 #'describe-variable sym)))
+                               (help-xref-button
+                               7 #'describe-variable sym
+                               "mouse-2, RET: describe this variable")))
                          ((match-string 4) ; `function' &c
                           (and (fboundp sym) ; similarly
                          ((match-string 4) ; `function' &c
                           (and (fboundp sym) ; similarly
-                               (help-xref-button 6 #'describe-function sym)))
-                         ((match-string 5)) ; nothing for symbol
-                         ((or (boundp sym) (fboundp sym))
+                               (help-xref-button
+                               7 #'describe-function sym
+                               "mouse-2, RET: describe this function")))
+                        ((match-string 5) ; `face'
+                         (and (facep sym)
+                              (help-xref-button 7 #'describe-face sym
+                               "mouse-2, RET: describe this face")))
+                         ((match-string 6)) ; nothing for symbol
+                         ((and (boundp sym) (fboundp sym))
                           ;; We can't intuit whether to use the
                           ;; variable or function doc -- supply both.
                           ;; We can't intuit whether to use the
                           ;; variable or function doc -- supply both.
-                          (help-xref-button 6 #'help-xref-interned sym)))))))
+                          (help-xref-button
+                          7 #'help-xref-interned sym
+                          "mouse-2, RET: describe this symbol"))
+                         ((boundp sym)
+                         (help-xref-button
+                          7 #'describe-variable sym
+                          "mouse-2, RET: describe this variable"))
+                        ((fboundp sym)
+                         (help-xref-button
+                          7 #'describe-function sym
+                          "mouse-2, RET: describe this function"))
+                        ((facep sym)
+                         (help-xref-button
+                          7 #'describe-face sym)))))))
               ;; An obvious case of a key substitution:
               ;; An obvious case of a key substitution:
-              (save-excursion              
+              (save-excursion
                 (while (re-search-forward
                        ;; Assume command name is only word characters
                        ;; and dashes to get things like `use M-x foo.'.
                         "\\<M-x\\s-+\\(\\sw\\(\\sw\\|-\\)+\\)" nil t)
                   (let ((sym (intern-soft (match-string 1))))
                     (if (fboundp sym)
                 (while (re-search-forward
                        ;; Assume command name is only word characters
                        ;; and dashes to get things like `use M-x foo.'.
                         "\\<M-x\\s-+\\(\\sw\\(\\sw\\|-\\)+\\)" nil t)
                   (let ((sym (intern-soft (match-string 1))))
                     (if (fboundp sym)
-                        (help-xref-button 1 #'describe-function sym)))))
+                        (help-xref-button
+                        1 #'describe-function sym
+                        "mouse-2, RET: describe this command")))))
               ;; Look for commands in whole keymap substitutions:
               (save-excursion
                ;; Make sure to find the first keymap.
                (goto-char (point-min))
                 ;; Find a header and the column at which the command
                 ;; name will be found.
               ;; Look for commands in whole keymap substitutions:
               (save-excursion
                ;; Make sure to find the first keymap.
                (goto-char (point-min))
                 ;; Find a header and the column at which the command
                 ;; name will be found.
-                (while (re-search-forward "^key +binding\n\\(-+ +\\)-+\n\n" 
+                (while (re-search-forward "^key +binding\n\\(-+ +\\)-+\n\n"
                                           nil t)
                   (let ((col (- (match-end 1) (match-beginning 1))))
                     (while
                                           nil t)
                   (let ((col (- (match-end 1) (match-beginning 1))))
                     (while
@@ -1081,12 +1234,13 @@ that."
                                        (looking-at "\\(\\sw\\|-\\)+$"))
                                    (let ((sym (intern-soft (match-string 0))))
                                      (if (fboundp sym)
                                        (looking-at "\\(\\sw\\|-\\)+$"))
                                    (let ((sym (intern-soft (match-string 0))))
                                      (if (fboundp sym)
-                                         (help-xref-button 
-                                          0 #'describe-function sym))))
+                                         (help-xref-button
+                                          0 #'describe-function sym
+                                         "mouse-2, RET: describe this function"))))
                               (zerop (forward-line)))))))))
           (set-syntax-table stab))
         ;; Make a back-reference in this buffer if appropriate.
                               (zerop (forward-line)))))))))
           (set-syntax-table stab))
         ;; Make a back-reference in this buffer if appropriate.
-        (when help-xref-stack
+        (when (and help-xref-following help-xref-stack)
           (goto-char (point-max))
           (save-excursion
             (insert "\n\n" help-back-label))
           (goto-char (point-max))
           (save-excursion
             (insert "\n\n" help-back-label))
@@ -1102,13 +1256,14 @@ that."
                          map))))
       (set-buffer-modified-p old-modified))))
 
                          map))))
       (set-buffer-modified-p old-modified))))
 
-(defun help-xref-button (match-number function data)
+(defun help-xref-button (match-number function data &optional help-echo)
   "Make a hyperlink for cross-reference text previously matched.
 
 MATCH-NUMBER is the subexpression of interest in the last matched
 regexp.  FUNCTION is a function to invoke when the button is
 activated, applied to DATA.  DATA may be a single value or a list.
   "Make a hyperlink for cross-reference text previously matched.
 
 MATCH-NUMBER is the subexpression of interest in the last matched
 regexp.  FUNCTION is a function to invoke when the button is
 activated, applied to DATA.  DATA may be a single value or a list.
-See `help-make-xrefs'."
+See `help-make-xrefs'.
+If optional arg HELP-ECHO is supplied, it is used as a help string."
   ;; Don't mung properties we've added specially in some instances.
   (unless (get-text-property (match-beginning match-number) 'help-xref)
     (add-text-properties (match-beginning match-number)
   ;; Don't mung properties we've added specially in some instances.
   (unless (get-text-property (match-beginning match-number) 'help-xref)
     (add-text-properties (match-beginning match-number)
@@ -1118,11 +1273,28 @@ See `help-make-xrefs'."
                                                (if (listp data)
                                                    data
                                                  (list data)))))
                                                (if (listp data)
                                                    data
                                                  (list data)))))
+    (if help-echo
+       (put-text-property (match-beginning match-number)
+                          (match-end match-number)
+                          'help-echo help-echo))
     (if help-highlight-p
        (put-text-property (match-beginning match-number)
                           (match-end match-number)
                           'face help-highlight-face))))
 
     (if help-highlight-p
        (put-text-property (match-beginning match-number)
                           (match-end match-number)
                           'face help-highlight-face))))
 
+(defun help-insert-xref-button (string function data &optional help-echo)
+  "Insert STRING and make a hyperlink from cross-reference text on it.
+
+FUNCTION is a function to invoke when the button is activated, applied
+to DATA.  DATA may be a single value or a list.  See `help-make-xrefs'.
+If optional arg HELP-ECHO is supplied, it is used as a help string."
+  (let ((pos (point)))
+    (insert string)
+    (goto-char pos)
+    (search-forward string)
+    (help-xref-button 0 function data help-echo)))
+
+
 \f
 ;; Additional functions for (re-)creating types of help buffers.
 (defun help-xref-interned (symbol)
 \f
 ;; Additional functions for (re-)creating types of help buffers.
 (defun help-xref-interned (symbol)
@@ -1130,16 +1302,23 @@ See `help-make-xrefs'."
 
 Both variable and function documentation are extracted into a single
 help buffer."
 
 Both variable and function documentation are extracted into a single
 help buffer."
-  (let ((fdoc (when (fboundp symbol) (describe-function symbol))))
+  (let ((fdoc (when (fboundp symbol) (describe-function symbol)))
+       (facedoc (when (facep symbol) (describe-face symbol))))
     (when (or (boundp symbol) (not fdoc))
       (describe-variable symbol)
       ;; We now have a help buffer on the variable.  Insert the function
       ;; text before it.
     (when (or (boundp symbol) (not fdoc))
       (describe-variable symbol)
       ;; We now have a help buffer on the variable.  Insert the function
       ;; text before it.
-      (when fdoc
+      (when (or fdoc facedoc)
        (with-current-buffer "*Help*"
          (goto-char (point-min))
          (let ((inhibit-read-only t))
        (with-current-buffer "*Help*"
          (goto-char (point-min))
          (let ((inhibit-read-only t))
-           (insert fdoc "\n\n" (symbol-name symbol) " is also a variable.\n\n"))
+           (when fdoc
+             (insert fdoc "\n\n"))
+           (when facedoc
+             (insert (make-string 30 ?-) "\n\n" (symbol-name symbol)
+                     " is also a " "face." "\n\n" facedoc "\n\n"))
+           (insert (make-string 30 ?-) "\n\n" (symbol-name symbol)
+                   " is also a " "variable." "\n\n"))
          (help-setup-xref (list #'help-xref-interned symbol) nil))))))
 
 (defun help-xref-mode (buffer)
          (help-setup-xref (list #'help-xref-interned symbol) nil))))))
 
 (defun help-xref-mode (buffer)
@@ -1165,13 +1344,16 @@ help buffer."
     (with-current-buffer buffer
       (when help-xref-stack
        (setq help-xref-stack (cdr help-xref-stack)) ; due to help-follow
     (with-current-buffer buffer
       (when help-xref-stack
        (setq help-xref-stack (cdr help-xref-stack)) ; due to help-follow
-       (setq item (car help-xref-stack)
+       (setq item (pop help-xref-stack)
              position (car item)
              method (cadr item)
              position (car item)
              method (cadr item)
-             args (cddr item))
-       (setq help-xref-stack (cdr help-xref-stack))))
+             args (cddr item))))
     (apply method args)
     (apply method args)
-    (goto-char position)))
+    ;; We assume that the buffer we just recreated has the saved name,
+    ;; which might not always be true.
+    (when (get-buffer (cdr position))
+      (with-current-buffer (cdr position)
+       (goto-char (car position))))))
 
 (defun help-go-back ()
   "Invoke the [back] button (if any) in the Help mode buffer."
 
 (defun help-go-back ()
   "Invoke the [back] button (if any) in the Help mode buffer."
@@ -1203,11 +1385,13 @@ For the cross-reference format, see `help-make-xrefs'."
          (method (car help-data))
          (args (cdr help-data)))
     (when help-data
          (method (car help-data))
          (args (cdr help-data)))
     (when help-data
-      (setq help-xref-stack (cons (cons (point) help-xref-stack-item)
+      (setq help-xref-stack (cons (cons (cons pos (buffer-name))
+                                       help-xref-stack-item)
                                  help-xref-stack))
       (setq help-xref-stack-item nil)
       ;; There is a reference at point.  Follow it.
                                  help-xref-stack))
       (setq help-xref-stack-item nil)
       ;; There is a reference at point.  Follow it.
-      (apply method args))))
+      (let ((help-xref-following t))
+       (apply method args)))))
 
 ;; For tabbing through buffer.
 (defun help-next-ref ()
 
 ;; For tabbing through buffer.
 (defun help-next-ref ()
@@ -1245,23 +1429,6 @@ For the cross-reference format, see `help-make-xrefs'."
 \f
 ;;; Automatic resizing of temporary buffers.
 
 \f
 ;;; Automatic resizing of temporary buffers.
 
-(defcustom temp-buffer-resize-mode nil
-  "Non-nil means resize windows displaying temporary buffers.
-This makes the window the right height for its contents, but never
-more than `temp-buffer-max-height' nor less than `window-min-height'.
-This applies to `help', `apropos' and `completion' buffers, and some others.
-
-Setting this variable directly does not take effect;
-use either \\[customize] or the function `temp-buffer-resize-mode'."
-  :get (lambda (symbol)
-         (and (memq 'resize-temp-buffer-window temp-buffer-show-hook) t))
-  :set (lambda (symbol value)
-         (temp-buffer-resize-mode (if value 1 -1)))
-  :initialize 'custom-initialize-default
-  :type 'boolean
-  :group 'help
-  :version "20.4")
-
 (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'
 (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'
@@ -1273,25 +1440,19 @@ positive number."
   :group 'help
   :version "20.4")
 
   :group 'help
   :version "20.4")
 
-(defun temp-buffer-resize-mode (arg)
-  "Toggle the mode which that makes windows smaller for temporary buffers.
+(define-minor-mode temp-buffer-resize-mode
+  "Toggle the mode which makes windows smaller for temporary buffers.
 With prefix argument ARG, turn the resizing of windows displaying temporary
 buffers on if ARG is positive or off otherwise.
 With prefix argument ARG, turn the resizing of windows displaying temporary
 buffers on if ARG is positive or off otherwise.
-See the documentation of the variable `temp-buffer-resize-mode' for
-more information."
-  (interactive "P")
-  (let ((turn-it-on
-         (if (null arg)
-             (not (memq 'resize-temp-buffer-window temp-buffer-show-hook))
-           (> (prefix-numeric-value arg) 0))))
-    (if turn-it-on
-        (progn
-          ;; `help-mode-maybe' may add a `back' button and thus increase the
-          ;; text size, so `resize-temp-buffer-window' must be run *after* it.
-          (add-hook 'temp-buffer-show-hook 'resize-temp-buffer-window 'append)
-          (setq temp-buffer-resize-mode t))
-      (remove-hook 'temp-buffer-show-hook 'resize-temp-buffer-window)
-      (setq temp-buffer-resize-mode nil))))
+This makes the window the right height for its contents, but never
+more than `temp-buffer-max-height' nor less than `window-min-height'.
+This applies to `help', `apropos' and `completion' buffers, and some others."
+  nil nil nil :global t :group 'help
+  (if temp-buffer-resize-mode
+      ;; `help-mode-maybe' may add a `back' button and thus increase the
+      ;; text size, so `resize-temp-buffer-window' must be run *after* it.
+      (add-hook 'temp-buffer-show-hook 'resize-temp-buffer-window 'append)
+    (remove-hook 'temp-buffer-show-hook 'resize-temp-buffer-window)))
 
 (defun resize-temp-buffer-window ()
   "Resize the current window to fit its contents.
 
 (defun resize-temp-buffer-window ()
   "Resize the current window to fit its contents.
@@ -1307,7 +1468,7 @@ out of view."
                          temp-buffer-max-height))
            (win-height (1- (window-height)))
            (min-height (1- window-min-height))
                          temp-buffer-max-height))
            (win-height (1- (window-height)))
            (min-height (1- window-min-height))
-           (text-height (window-buffer-height(selected-window)))
+           (text-height (count-screen-lines))
            (new-height (max (min text-height max-height) min-height)))
       (enlarge-window (- new-height win-height)))))
 
            (new-height (max (min text-height max-height) min-height)))
       (enlarge-window (- new-height win-height)))))
 
@@ -1316,6 +1477,16 @@ out of view."
 ;; to this alist.
 ;; The parens and function name are redundant, but it's messy to add
 ;; them in `documentation'.
 ;; to this alist.
 ;; The parens and function name are redundant, but it's messy to add
 ;; them in `documentation'.
+
+;; This will find any missing items:
+;; (let (l)
+;;   (mapatoms (lambda (x)
+;;           (if (and (fboundp x)
+;;                    (subrp (symbol-function x))
+;;                    (not (numberp (cdr (subr-arity (symbol-function x)))))
+;;                    (not (assq x help-manyarg-func-alist)))
+;;               (push x l))))
+;;   l)
 (defconst help-manyarg-func-alist
   (purecopy
    '((list . "(list &rest OBJECTS)")
 (defconst help-manyarg-func-alist
   (purecopy
    '((list . "(list &rest OBJECTS)")
@@ -1323,6 +1494,8 @@ out of view."
      (make-byte-code . "(make-byte-code &rest ELEMENTS)")
      (call-process
       . "(call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)")
      (make-byte-code . "(make-byte-code &rest ELEMENTS)")
      (call-process
       . "(call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)")
+     (call-process-region
+      . "(call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &rest ARGS)")
      (string . "(string &rest CHARACTERS)")
      (+ . "(+ &rest NUMBERS-OR-MARKERS)")
      (- . "(- &optional NUMBER-OR-MARKER &rest MORE-NUMBERS-OR-MARKERS)")
      (string . "(string &rest CHARACTERS)")
      (+ . "(+ &rest NUMBERS-OR-MARKERS)")
      (- . "(- &optional NUMBER-OR-MARKER &rest MORE-NUMBERS-OR-MARKERS)")
@@ -1336,6 +1509,7 @@ out of view."
      (encode-time
       . "(encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE)")
      (insert . "(insert &rest ARGS)")
      (encode-time
       . "(encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE)")
      (insert . "(insert &rest ARGS)")
+     (insert-and-inherit . "(insert-and-inherit &rest ARGS)")
      (insert-before-markers . "(insert-before-markers &rest ARGS)")
      (message . "(message STRING &rest ARGUMENTS)")
      (message-box . "(message-box STRING &rest ARGUMENTS)")
      (insert-before-markers . "(insert-before-markers &rest ARGS)")
      (message . "(message STRING &rest ARGUMENTS)")
      (message-box . "(message-box STRING &rest ARGUMENTS)")
@@ -1344,6 +1518,11 @@ out of view."
      (format . "(format STRING &rest OBJECTS)")
      (apply . "(apply FUNCTION &rest ARGUMENTS)")
      (run-hooks . "(run-hooks &rest HOOKS)")
      (format . "(format STRING &rest OBJECTS)")
      (apply . "(apply FUNCTION &rest ARGUMENTS)")
      (run-hooks . "(run-hooks &rest HOOKS)")
+     (run-hook-with-args . "(run-hook-with-args HOOK &rest ARGS)")
+     (run-hook-with-args-until-failure
+      . "(run-hook-with-args-until-failure HOOK &rest ARGS)")
+     (run-hook-with-args-until-success
+      . "(run-hook-with-args-until-success HOOK &rest ARGS)")
      (funcall . "(funcall FUNCTION &rest ARGUMENTS)")
      (append . "(append &rest SEQUENCES)")
      (concat . "(concat &rest SEQUENCES)")
      (funcall . "(funcall FUNCTION &rest ARGUMENTS)")
      (append . "(append &rest SEQUENCES)")
      (concat . "(concat &rest SEQUENCES)")
@@ -1377,7 +1556,16 @@ out of view."
      (catch . "(catch TAG BODY...)")
      (unwind-protect . "(unwind-protect BODYFORM UNWINDFORMS...)")
      (condition-case . "(condition-case VAR BODYFORM HANDLERS...)")
      (catch . "(catch TAG BODY...)")
      (unwind-protect . "(unwind-protect BODYFORM UNWINDFORMS...)")
      (condition-case . "(condition-case VAR BODYFORM HANDLERS...)")
-     (track-mouse . "(track-mouse BOFY ...)")
-     (ml-if . "(ml-if COND THEN ELSE...)"))))
+     (track-mouse . "(track-mouse BODY ...)")
+     (ml-if . "(ml-if COND THEN ELSE...)")
+     (ml-provide-prefix-argument . "(ml-provide-prefix-argument ARG1 ARG2)")
+     (ml-prefix-argument-loop . "(ml-prefix-argument-loop ...)")
+     (with-output-to-temp-buffer
+        . "(with-output-to-temp-buffer BUFFNAME BODY ...)")
+     (save-window-excursion . "(save-window-excursion BODY ...)")
+     (find-operation-coding-system
+      . "(find-operation-coding-system OPERATION ARGUMENTS ...)")
+     (insert-before-markers-and-inherit
+      . "(insert-before-markers-and-inherit &rest ARGS)"))))
 
 ;;; help.el ends here
 
 ;;; help.el ends here