X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/90a5604048038f3817d1c82d392374f1cd5de5d4..2e48ba1817cc8fa07cc3ea57535d854bdd349fdc:/lisp/help.el diff --git a/lisp/help.el b/lisp/help.el index b0ca05a747..fed3dd7f69 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 Free Software Foundation, Inc. +;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999, 2000 Free Software Foundation, Inc. ;; Maintainer: FSF ;; Keywords: help, internal @@ -25,13 +25,14 @@ ;;; Commentary: ;; This code implements GNU Emacs' on-line help system, the one invoked by -;;`M-x help-for-help'. +;; `M-x help-for-help'. ;;; Code: ;; Get the macro make-help-screen when this is compiled, ;; or run interpreted, but not when the compiled code is loaded. (eval-when-compile (require 'help-macro)) +(eval-when-compile (require 'view)) (defvar help-map (make-sparse-keymap) "Keymap for characters following the Help key.") @@ -82,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) @@ -101,26 +104,6 @@ ;; 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'. @@ -135,6 +118,11 @@ The format is (FUNCTION ARGS...).") (setq-default help-xref-stack nil help-xref-stack-item nil) +(defcustom help-mode-hook nil + "Hook run by `help-mode'." + :type 'hook + :group 'help) + (defun help-mode () "Major mode for viewing help text and navigating references in it. Entry to this mode runs the normal hook `help-mode-hook'. @@ -216,6 +204,19 @@ With arg, you are asked to choose which language." (goto-char (point-min)) (set-buffer-modified-p nil)))) +(defun mode-line-key-binding (key) + "Value is the binding of KEY in the mode line or nil if none." + (let (string-info defn) + (when (and (eq 'mode-line (aref key 0)) + (consp (setq string-info (nth 4 (event-start (aref key 1)))))) + (let* ((string (car string-info)) + (pos (cdr string-info)) + (local-map (and (> pos 0) + (< pos (length string)) + (get-text-property pos 'local-map string)))) + (setq defn (and local-map (lookup-key local-map key))))) + defn)) + (defun describe-key-briefly (key &optional insert) "Print the name of the function KEY invokes. KEY is a string. If INSERT (the prefix arg) is non-nil, insert the message in the buffer." @@ -236,7 +237,8 @@ If INSERT (the prefix arg) is non-nil, insert the message in the buffer." (set-buffer (window-buffer window)) (goto-char position))) ;; Ok, now look up the key and name the command. - (let ((defn (key-binding key)) + (let ((defn (or (mode-line-key-binding key) + (key-binding key))) (key-desc (key-description key))) (if (or (null defn) (integerp defn)) (princ (format "%s is undefined" key-desc)) @@ -317,7 +319,7 @@ If FUNCTION is nil, applies `message' to it, thus printing it." (progn (set-buffer (window-buffer window)) (goto-char position))) - (let ((defn (key-binding key))) + (let ((defn (or (mode-line-key-binding key) (key-binding key)))) (if (or (null defn) (integerp defn)) (message "%s is undefined" (key-description key)) (with-output-to-temp-buffer "*Help*" @@ -438,7 +440,13 @@ With numeric argument display information on correspondingly older changes." (defun view-emacs-FAQ () "Display the Emacs Frequently Asked Questions (FAQ) file." (interactive) - (find-file-read-only (expand-file-name "FAQ" data-directory))) +;;; (find-file-read-only (expand-file-name "FAQ" data-directory)) + (info "(emacs-faq)")) + +(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." @@ -632,6 +640,18 @@ It can also be nil, if the definition is not associated with any file." (if (eq (nth 4 def) 'keymap) "keymap" (if (nth 4 def) "Lisp macro" "Lisp function")) )) + ;; perhaps use keymapp here instead + ((eq (car-safe def) 'keymap) + (let ((is-full nil) + (elts (cdr-safe def))) + (while elts + (if (char-table-p (car-safe elts)) + (setq is-full t + elts nil)) + (setq elts (cdr-safe elts))) + (if is-full + "a full keymap" + "a sparse keymap"))) (t ""))) (when (and parens (not (equal string ""))) (setq need-close t) @@ -641,7 +661,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 @@ -660,7 +681,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) @@ -673,21 +695,41 @@ 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)) + (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))))) + (help-setup-xref (list #'describe-function function) + interactive-p)) (princ "not documented"))))) (defun variable-at-point () @@ -709,6 +751,29 @@ 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) + ((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." @@ -730,26 +795,34 @@ 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 + (set-syntax-table emacs-lisp-mode-syntax-table) (goto-char (point-min)) (if valvoid (forward-line 1) @@ -768,9 +841,9 @@ Returns the documentation as a string, also." ;; Note, it is not reliable to test only for a custom-type property ;; because those are only present after the var's definition ;; has been loaded. - (if (or (user-variable-p variable) - (get variable 'custom-loads) - (get variable 'custom-type)) + (if (or (get variable 'custom-type) ; after defcustom + (get variable 'custom-loads) ; from loaddefs.el + (get variable 'standard-value)) ; from cus-start.el (let ((customize-label "customize")) (terpri) (terpri) @@ -780,7 +853,9 @@ Returns the documentation as a string, also." (re-search-backward (concat "\\(" customize-label "\\)") nil t) (help-xref-button 1 #'(lambda (v) - (customize-variable v)) variable) + (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 @@ -793,12 +868,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 @@ -834,7 +910,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))) @@ -914,8 +990,7 @@ and the file name is displayed in the echo area." (defcustom help-highlight-p t "*If non-nil, `help-make-xrefs' highlight cross-references. Under a window system it highlights them with face defined by -`help-highlight-face'. On a character terminal highlighted -references look like cross-references in info mode." +`help-highlight-face'." :group 'help :version "20.3" :type 'boolean) @@ -927,22 +1002,22 @@ 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\\)\\|" + "\\(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) @@ -991,7 +1066,8 @@ 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) @@ -1002,19 +1078,29 @@ that." ((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 + 6 #'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))) + (help-xref-button + 6 #'describe-function sym + "mouse-2, RET: describe this function"))) ((match-string 5)) ; 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 + 6 #'help-xref-interned sym + "mouse-2, RET: describe this symbol")) ((boundp sym) - (help-xref-button 6 #'describe-variable sym)) - ((fboundp sym) - (help-xref-button 6 #'describe-function sym))))))) + (help-xref-button + 6 #'describe-variable sym + "mouse-2, RET: describe this variable")) + ((fboundp sym) + (help-xref-button + 6 #'describe-function sym + "mouse-2, RET: describe this function"))))))) ;; An obvious case of a key substitution: (save-excursion (while (re-search-forward @@ -1023,7 +1109,9 @@ that." "\\