X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/f0d0fb1990f5af0e1f63ad8068ebf8eaed6ffbfd..f3ad2fc8d0206ad806d6dafffe7cb3b01d9729c4:/lisp/help.el diff --git a/lisp/help.el b/lisp/help.el index 4beca0a8ec..67a8858473 100644 --- a/lisp/help.el +++ b/lisp/help.el @@ -1,6 +1,6 @@ ;;; 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 @@ -107,8 +107,10 @@ (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 @@ -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) + (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)) @@ -287,9 +293,8 @@ If FUNCTION is nil, applies `message' to it, thus printing it." (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)) @@ -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. - (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)) @@ -441,7 +447,7 @@ With numeric argument display information on correspondingly older changes." "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." @@ -620,7 +626,9 @@ It can also be nil, if the definition is not associated with any file." (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) @@ -661,7 +669,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) - (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 @@ -680,7 +689,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)))) - function))))) + function + "mouse-2, RET: find function's definition"))))) (if need-close (princ ")")) (princ ".") (terpri) @@ -713,19 +723,35 @@ It can also be nil, if the definition is not associated with any file." (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"))))) @@ -749,6 +775,34 @@ Return 0 if there is no such symbol." (set-syntax-table stab))) (error 0))) +(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 + (buffer-substring (match-beginning 1) + (match-end 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) "Display the full documentation of VARIABLE (a symbol). Returns the documentation as a string, also." @@ -757,7 +811,8 @@ Returns the documentation as a string, also." (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)))) @@ -770,32 +825,43 @@ Returns the documentation as a string, also." (if (not (boundp variable)) (progn (princ " is void") - (terpri) (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") - (princ "global value is ") - (terpri) - (pp (default-value variable))) + (let ((val (default-value variable))) + (with-current-buffer standard-output + (princ "global value is ") + (terpri) + (let ((from (point))) + (pp val) + (help-xref-on-pp from (point)))))) (terpri))) (terpri) (save-current-buffer (set-buffer standard-output) (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))) - (insert "'s value is shown below.\n\n") + (insert " value is shown below.\n\n") (save-excursion (insert "\n\nValue:")))))) (princ "Documentation:") @@ -819,9 +885,12 @@ Returns the documentation as a string, also." (save-excursion (re-search-backward (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.) @@ -833,12 +902,13 @@ Returns the documentation as a string, also." (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 @@ -908,9 +978,9 @@ and the file name is displayed in the echo area." t)) (let (result) (catch 'answer - (mapcar + (mapc (lambda (dir) - (mapcar + (mapc (lambda (suf) (let ((try (expand-file-name (concat library suf) dir))) (and (file-readable-p try) @@ -972,6 +1042,7 @@ Must be previously-defined." (defconst help-xref-symbol-regexp (purecopy (concat "\\(\\<\\(\\(variable\\|option\\)\\|" "\\(function\\|command\\)\\|" + "\\(face\\)\\|" "\\(symbol\\)\\)\\s-+\\)?" ;; Note starting with word-syntax character: "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'")) @@ -995,6 +1066,9 @@ items for help buffer \"back\" buttons is cleared." (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. @@ -1030,26 +1104,48 @@ that." (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")))) ;; 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 - (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 - (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. - (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: (save-excursion (while (re-search-forward @@ -1058,7 +1154,9 @@ that." "\\