X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/73ea6d945d4af5352122e3a1470c4533187e9dcc..c6fa13e32703f8b0634401778a758e76f2798f97:/lisp/help.el diff --git a/lisp/help.el b/lisp/help.el index 387c4cdd73..c3dfc518aa 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 @@ -83,6 +83,8 @@ (autoload 'finder-by-keyword "finder" "Find packages matching a given keyword." t) +(define-key help-map "P" 'view-emacs-problems) + (define-key help-map "s" 'describe-syntax) (define-key help-map "t" 'help-with-tutorial) @@ -102,31 +104,13 @@ ;; Documentation only, since we use minor-mode-overriding-map-alist. (define-key help-mode-map "\r" 'help-follow) -;; Font-locking is incompatible with the new xref stuff. -;(defvar help-font-lock-keywords -; (eval-when-compile -; (let ((name-char "[-+a-zA-Z0-9_*]") (sym-char "[-+a-zA-Z0-9_:*]")) -; (list -; ;; -; ;; The symbol itself. -; (list (concat "\\`\\(" name-char "+\\)\\(\\(:\\)\\|\\('\\)\\)") -; '(1 (if (match-beginning 3) -; font-lock-function-name-face -; font-lock-variable-name-face))) -; ;; -; ;; Words inside `' which tend to be symbol names. -; (list (concat "`\\(" sym-char sym-char "+\\)'") -; 1 'font-lock-constant-face t) -; ;; -; ;; CLisp `:' keywords as references. -; (list (concat "\\<:" sym-char "+\\>") 0 'font-lock-builtin-face t)))) -; "Default expressions to highlight in Help mode.") - (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 @@ -305,9 +289,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)) @@ -459,7 +442,12 @@ 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." + (interactive) + (view-file (expand-file-name "PROBLEMS" data-directory))) (defun view-lossage () "Display last 100 input keystrokes." @@ -633,7 +621,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) @@ -674,7 +664,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 @@ -693,7 +684,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) @@ -706,21 +698,57 @@ It can also be nil, if the definition is not associated with any file." (car (append def nil))) ((eq (car-safe def) 'lambda) (nth 1 def)) + ((and (eq (car-safe def) 'autoload) + (not (eq (nth 4 def) 'keymap))) + (concat "[Arg list not available until " + "function definition is loaded.]")) (t t)))) - (if (listp arglist) - (progn - (princ (cons (if (symbolp function) function "anonymous") - (mapcar (lambda (arg) - (if (memq arg '(&optional &rest)) - arg - (intern (upcase (symbol-name arg))))) - arglist))) - (terpri)))) + (cond ((listp arglist) + (princ (cons (if (symbolp function) function "anonymous") + (mapcar (lambda (arg) + (if (memq arg '(&optional &rest)) + arg + (intern (upcase (symbol-name arg))))) + arglist))) + (terpri)) + ((stringp arglist) + (princ arglist) + (terpri)))) (let ((doc (documentation function))) (if doc (progn (terpri) (princ doc) - (help-setup-xref (list #'describe-function function) interactive-p)) + (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"))))) (defun variable-at-point () @@ -742,6 +770,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." @@ -750,7 +806,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)))) @@ -763,32 +820,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:") @@ -812,9 +880,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.) @@ -826,12 +897,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 @@ -867,7 +939,7 @@ If INSERT (the prefix arg) is non-nil, insert the message in the buffer." (setq val (completing-read (if fn (format "Where is command (default %s): " fn) "Where is command: ") - obarray 'fboundp t)) + obarray 'commandp t)) (list (if (equal val "") fn (intern val)) current-prefix-arg))) @@ -901,9 +973,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) @@ -959,22 +1031,23 @@ Must be previously-defined." :version "20.3" :type 'face) -(defvar help-back-label "[back]" +(defvar help-back-label (purecopy "[back]") "Label to use by `help-make-xrefs' for the go-back reference.") -(defvar help-xref-symbol-regexp - (concat "\\(\\<\\(\\(variable\\|option\\)\\|" - "\\(function\\|command\\)\\|" - "\\(symbol\\)\\)\\s-+\\)?" - ;; Note starting with word-syntax character: - "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'") +(defconst help-xref-symbol-regexp + (purecopy (concat "\\(\\<\\(\\(variable\\|option\\)\\|" + "\\(function\\|command\\)\\|" + "\\(face\\)\\|" + "\\(symbol\\)\\)\\s-+\\)?" + ;; Note starting with word-syntax character: + "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'")) "Regexp matching doc string references to symbols. The words preceding the quoted symbol can be used in doc strings to distinguish references to variables, functions and symbols.") -(defvar help-xref-info-regexp - "\\<[Ii]nfo[ \t\n]+node[ \t\n]+`\\([^']+\\)'" +(defconst help-xref-info-regexp + (purecopy "\\<[Ii]nfo[ \t\n]+node[ \t\n]+`\\([^']+\\)'") "Regexp matching doc string references to an Info node.") (defun help-setup-xref (item interactive-p) @@ -988,6 +1061,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. @@ -1023,26 +1099,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 @@ -1051,7 +1149,9 @@ that." "\\