;;; help.el --- help commands for Emacs
-;; Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1993, 1994 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Keywords: help, internal
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
;;; Commentary:
(defvar help-map (make-sparse-keymap)
"Keymap for characters following the Help key.")
+(defvar help-mode-map (make-sparse-keymap)
+ "Keymap for help mode.")
+
(define-key global-map (char-to-string help-char) 'help-command)
+(define-key global-map [help] 'help-command)
+(define-key global-map [f1] 'help-command)
(fset 'help-command help-map)
(define-key help-map (char-to-string help-char) 'help-for-help)
+(define-key help-map [help] 'help-for-help)
+(define-key help-map [f1] 'help-for-help)
(define-key help-map "?" 'help-for-help)
(define-key help-map "\C-c" 'describe-copying)
(define-key help-map "\C-d" 'describe-distribution)
(define-key help-map "\C-w" 'describe-no-warranty)
+(define-key help-map "\C-p" 'describe-project)
(define-key help-map "a" 'command-apropos)
(define-key help-map "b" 'describe-bindings)
(define-key help-map "d" 'describe-function)
(define-key help-map "f" 'describe-function)
+(define-key help-map "F" 'view-emacs-FAQ)
+
(define-key help-map "i" 'info)
(define-key help-map "\C-f" 'Info-goto-emacs-command-node)
(define-key help-map "\C-k" 'Info-goto-emacs-key-command-node)
(define-key help-map "n" 'view-emacs-news)
(define-key help-map "p" 'finder-by-keyword)
-(autoload 'finder-by-keyword "finder")
+(autoload 'finder-by-keyword "finder"
+ "Find packages matching a given keyword." t)
(define-key help-map "s" 'describe-syntax)
(define-key help-map "v" 'describe-variable)
+(define-key help-map "q" 'help-quit)
+
+(defvar help-font-lock-keywords
+ (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 2)
+ font-lock-function-name-face
+ font-lock-variable-name-face)
+ nil t))
+ ;;
+ ;; Words inside `' which tend to be symbol names.
+ (list (concat "`\\(" sym-char sym-char "+\\)'")
+ 1 'font-lock-reference-face t)
+ ;;
+ ;; CLisp `:' keywords as references.
+ (list (concat "\\<:" sym-char "+\\>") 0 'font-lock-reference-face t)))
+ "Default expressions to highlight in Help mode.")
+
+(defun help-mode ()
+ "Major mode for viewing help text.
+Entry to this mode runs the normal hook `help-mode-hook'.
+Commands:
+\\{help-mode-map}"
+ (interactive)
+ (kill-all-local-variables)
+ (use-local-map help-mode-map)
+ (setq mode-name "Help")
+ (setq major-mode 'help-mode)
+ (make-local-variable 'font-lock-defaults)
+ (setq font-lock-defaults '(help-font-lock-keywords))
+ (view-mode)
+ (run-hooks 'help-mode-hook))
+
+(defun help-quit ()
+ (interactive)
+ nil)
+
(defun help-with-tutorial ()
"Select the Emacs learn-by-doing tutorial."
(interactive)
(search-forward "\n<<")
(beginning-of-line)
(delete-region (point) (progn (end-of-line) (point)))
- (newline (- (window-height (selected-window))
+ (let ((n (- (window-height (selected-window))
(count-lines (point-min) (point))
- 6))
+ 6)))
+ (if (< n 12)
+ (newline n)
+ ;; Some people get confused by the large gap.
+ (newline (/ n 2))
+ (insert "[Middle of page left blank for didactic purposes. "
+ "Text continues below]")
+ (newline (- n (/ n 2)))))
(goto-char (point-min))
(set-buffer-modified-p nil))))
(if (listp type) (setq type (car type)))
(and (symbolp type)
(memq 'down (event-modifiers type))
- (setq foo (read-event))))
- (let ((defn (key-binding key)))
- (if (or (null defn) (integerp defn))
- (message "%s is undefined" (key-description key))
- (message "%s runs the command %s"
- (key-description key)
- (if (symbolp defn) defn (prin1-to-string defn))))))
+ (read-event)))
+ (save-excursion
+ (let ((modifiers (event-modifiers (aref key 0)))
+ window position)
+ ;; For a mouse button event, go to the button it applies to
+ ;; to get the right key bindings. And go to the right place
+ ;; in case the keymap depends on where you clicked.
+ (if (or (memq 'click modifiers) (memq 'down modifiers)
+ (memq 'drag modifiers))
+ (setq window (posn-window (event-start (aref key 0)))
+ position (posn-point (event-start (aref key 0)))))
+ (if (windowp window)
+ (progn
+ (set-buffer (window-buffer window))
+ (goto-char position)))
+ ;; Ok, now look up the key and name the command.
+ (let ((defn (key-binding key)))
+ (if (or (null defn) (integerp defn))
+ (message "%s is undefined" (key-description key))
+ (message (if (windowp window)
+ "%s at that spot runs the command %s"
+ "%s runs the command %s")
+ (key-description key)
+ (if (symbolp defn) defn (prin1-to-string defn))))))))
(defun print-help-return-message (&optional function)
"Display or return message saying how to restore windows after help command.
Computes a message and applies the optional argument FUNCTION to it.
If FUNCTION is nil, applies `message' to it, thus printing it."
(and (not (get-buffer-window standard-output))
- (funcall (or function 'message)
- (concat
- (substitute-command-keys
- (if (one-window-p t)
- (if pop-up-windows
- "Type \\[delete-other-windows] to remove help window."
- "Type \\[switch-to-buffer] RET to remove help window.")
- "Type \\[switch-to-buffer-other-window] RET to restore the other window."))
- (substitute-command-keys
- " \\[scroll-other-window] to scroll the help.")))))
+ (let ((first-message
+ (cond ((or (member (buffer-name standard-output)
+ special-display-buffer-names)
+ (assoc (buffer-name standard-output)
+ special-display-buffer-names)
+ (let (found
+ (tail special-display-regexps)
+ (name (buffer-name standard-output)))
+ (while (and tail (not found))
+ (if (or (and (consp (car tail))
+ (string-match (car (car tail)) name))
+ (and (stringp (car tail))
+ (string-match (car tail) name)))
+ (setq found t))
+ (setq tail (cdr tail)))
+ found))
+ ;; If the help output buffer is a special display buffer,
+ ;; don't say anything about how to get rid of it.
+ ;; First of all, the user will do that with the window
+ ;; manager, not with Emacs.
+ ;; Secondly, the buffer has not been displayed yet,
+ ;; so we don't know whether its frame will be selected.
+ ;; Even the message about scrolling the help
+ ;; might be wrong, but it seems worth showing it anyway.
+ nil)
+ ((not (one-window-p t))
+ "Type \\[switch-to-buffer-other-window] RET to restore the other window.")
+ (pop-up-windows
+ "Type \\[delete-other-windows] to remove help window.")
+ (t
+ "Type \\[switch-to-buffer] RET to remove help window."))))
+ (funcall (or function 'message)
+ (concat
+ (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 (or (member (buffer-name standard-output)
+ special-display-buffer-names)
+ (assoc (buffer-name standard-output)
+ special-display-buffer-names)
+ (memq t (mapcar '(lambda (elt)
+ (if (consp elt)
+ (setq elt (car elt)))
+ (string-match elt (buffer-name standard-output)))
+ special-display-regexps)))
+ nil
+ (if (or (member (buffer-name standard-output)
+ same-window-buffer-names)
+ (assoc (buffer-name standard-output)
+ same-window-buffer-names)
+ (memq t (mapcar '(lambda (elt)
+ (if (consp elt)
+ (setq elt (car elt)))
+ (string-match elt (buffer-name standard-output)))
+ same-window-regexps)))
+ ;; Say how to scroll this window.
+ (substitute-command-keys
+ "\\[scroll-up] to scroll the help.")
+ ;; Say how to scroll some other window.
+ (substitute-command-keys
+ "\\[scroll-other-window] to scroll the help."))))))))
(defun describe-key (key)
"Display documentation of the function invoked by KEY. KEY is a string."
(and (symbolp type)
(memq 'down (event-modifiers type))
(read-event)))
- (let ((defn (key-binding key)))
- (if (or (null defn) (integerp defn))
- (message "%s is undefined" (key-description key))
- (with-output-to-temp-buffer "*Help*"
- (prin1 defn)
- (princ ":\n")
- (if (documentation defn)
- (princ (documentation defn))
- (princ "not documented"))
- (print-help-return-message)))))
-
-(defun describe-mode (&optional minor)
- "Display documentation of current major mode.
-If optional MINOR is non-nil (or prefix argument is given if interactive),
-display documentation of active minor modes as well.
+ (save-excursion
+ (let ((modifiers (event-modifiers (aref key 0)))
+ window position)
+ ;; For a mouse button event, go to the button it applies to
+ ;; to get the right key bindings. And go to the right place
+ ;; in case the keymap depends on where you clicked.
+ (if (or (memq 'click modifiers) (memq 'down modifiers)
+ (memq 'drag modifiers))
+ (setq window (posn-window (event-start (aref key 0)))
+ position (posn-point (event-start (aref key 0)))))
+ (if (windowp window)
+ (progn
+ (set-buffer (window-buffer window))
+ (goto-char position)))
+ (let ((defn (key-binding key)))
+ (if (or (null defn) (integerp defn))
+ (message "%s is undefined" (key-description key))
+ (with-output-to-temp-buffer "*Help*"
+ (princ (key-description key))
+ (if (windowp window)
+ (princ " at that spot"))
+ (princ " runs the command ")
+ (prin1 defn)
+ (princ ":\n")
+ (let ((doc (documentation defn)))
+ (if doc
+ (progn (terpri)
+ (princ doc))
+ (princ "not documented")))
+ (save-excursion
+ (set-buffer standard-output)
+ (help-mode))
+ (print-help-return-message)))))))
+
+(defun describe-mode ()
+ "Display documentation of current major mode and minor modes.
For this to work correctly for a minor mode, the mode's indicator variable
\(listed in `minor-mode-alist') must also be a function whose documentation
describes the minor mode."
(interactive)
(with-output-to-temp-buffer "*Help*"
- (princ mode-name)
- (princ " Mode:\n")
- (princ (documentation major-mode))
(let ((minor-modes minor-mode-alist)
(locals (buffer-local-variables)))
(while minor-modes
(if (and local-binding
(cdr local-binding)
(fboundp minor-mode))
- (progn
- (princ (format "\n\n\n%s minor mode (indicator%s):\n"
- minor-mode indicator))
- (princ (documentation minor-mode)))))
+ (let ((pretty-minor-mode minor-mode))
+ (if (string-match "-mode$" (symbol-name minor-mode))
+ (setq pretty-minor-mode
+ (capitalize
+ (substring (symbol-name minor-mode)
+ 0 (match-beginning 0)))))
+ (while (and indicator (symbolp indicator))
+ (setq indicator (symbol-value indicator)))
+ (princ (format "%s minor mode (%s):\n"
+ pretty-minor-mode
+ (if indicator
+ (format "indicator%s" indicator)
+ "no indicator")))
+ (princ (documentation minor-mode))
+ (princ "\n\n"))))
(setq minor-modes (cdr minor-modes))))
+ (princ mode-name)
+ (princ " mode:\n")
+ (princ (documentation major-mode))
+ (save-excursion
+ (set-buffer standard-output)
+ (help-mode))
(print-help-return-message)))
;; So keyboard macro definitions are documented correctly
(expand-file-name "COPYING" data-directory))
(goto-char (point-min)))
+(defun describe-project ()
+ "Display info on the GNU project."
+ (interactive)
+ (find-file-read-only
+ (expand-file-name "GNU" data-directory))
+ (goto-char (point-min)))
+
(defun describe-no-warranty ()
"Display info on all the kinds of warranty Emacs does NOT have."
(interactive)
The prefix described consists of all but the last event
of the key sequence that ran this command."
(interactive)
- (let* ((key (this-command-keys))
- (prefix (make-vector (1- (length key)) nil))
- i)
- (setq i 0)
- (while (< i (length prefix))
- (aset prefix i (aref key i))
- (setq i (1+ i)))
- (describe-bindings prefix)))
+ (let* ((key (this-command-keys)))
+ (describe-bindings
+ (if (stringp key)
+ (substring key 0 (1- (length key)))
+ (let ((prefix (make-vector (1- (length key)) nil))
+ (i 0))
+ (while (< i (length prefix))
+ (aset prefix i (aref key i))
+ (setq i (1+ i)))
+ prefix)))))
;; Make C-h after a prefix, when not specifically bound,
;; run describe-prefix-bindings.
(setq prefix-help-command 'describe-prefix-bindings)
(interactive)
(find-file-read-only (expand-file-name "NEWS" 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)))
+
(defun view-lossage ()
"Display last 100 input keystrokes."
(interactive)
(with-output-to-temp-buffer "*Help*"
- (princ (key-description (recent-keys)))
+ (princ (mapconcat (function (lambda (key)
+ (if (or (integerp key)
+ (symbolp key)
+ (listp key))
+ (single-key-description key)
+ (prin1-to-string key nil))))
+ (recent-keys)
+ " "))
(save-excursion
(set-buffer standard-output)
(goto-char (point-min))
(while (progn (move-to-column 50) (not (eobp)))
(search-forward " " nil t)
- (insert "\n")))
+ (insert "\n"))
+ (help-mode))
(print-help-return-message)))
+(defalias 'help 'help-for-help)
(make-help-screen help-for-help
- "a b c f i k l m n p s t v w C-c C-d C-n C-w. Type \\[help-for-help] again for more help: "
- "You have typed \\[help-for-help], the help character. Type a Help option:
+ "a b c f C-f i k C-k l m n p s t v w C-c C-d C-n C-w, or ? for more help:"
+ "You have typed \\[help-command], the help character. Type a Help option:
+\(Use SPC or DEL to scroll through this text. Type \\<help-map>\\[help-quit] to exit the Help command.)
-a command-apropos. Give a substring, and see a list of commands
- (functions interactively callable) that contain
- that substring. See also the apropos command.
+a command-apropos. Give a substring, and see a list of commands
+ (functions interactively callable) that contain
+ that substring. See also the apropos command.
b describe-bindings. Display table of all key bindings.
c describe-key-briefly. Type a command key sequence;
- it prints the function name that sequence runs.
+ it prints the function name that sequence runs.
f describe-function. Type a function name and get documentation of it.
+C-f Info-goto-emacs-command-node. Type a function name;
+ it takes you to the Info node for that command.
+F view-emacs-FAQ. Shows emacs frequently asked questions file.
i info. The info documentation reader.
k describe-key. Type a command key sequence;
- it displays the full documentation.
+ it displays the full documentation.
+C-k Info-goto-emacs-key-command-node. Type a command key sequence;
+ it takes you to the Info node for the command bound to that key.
l view-lossage. Shows last 100 characters you typed.
m describe-mode. Print documentation of current major mode,
- which describes the commands peculiar to it.
+ which describes the commands peculiar to it.
n view-emacs-news. Shows emacs news file.
p finder-by-keyword. Find packages matching a given topic keyword.
s describe-syntax. Display contents of syntax table, plus explanations
t help-with-tutorial. Select the Emacs learn-by-doing tutorial.
v describe-variable. Type name of a variable;
- it displays the variable's documentation and value.
+ it displays the variable's documentation and value.
w where-is. Type command name; it prints which keystrokes
- invoke that command.
+ invoke that command.
C-c print Emacs copying permission (General Public License).
C-d print Emacs ordering information.
C-n print news of recent Emacs changes.
+C-p print information about the GNU project.
C-w print information on absence of warranty for GNU Emacs."
help-map)
(and (symbolp obj) (fboundp obj) obj))))
(error nil))
(condition-case ()
- (save-excursion
- (forward-sexp -1)
- (skip-chars-forward "'")
- (let ((obj (read (current-buffer))))
- (and (symbolp obj) (fboundp obj) obj)))
+ (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))))
+ (and (symbolp obj) (fboundp obj) obj)))
+ (set-syntax-table stab)))
(error nil))))
+(defun describe-function-find-file (function)
+ (let ((files load-history)
+ file functions)
+ (while files
+ (if (memq function (cdr (car files)))
+ (setq file (car (car files)) files nil))
+ (setq files (cdr files)))
+ file))
+
(defun describe-function (function)
"Display the full documentation of FUNCTION (a symbol)."
(interactive
(prin1 function)
(princ ": ")
(let* ((def (symbol-function function))
+ file-name
(beg (if (commandp def) "an interactive " "a ")))
(princ (cond ((or (stringp def)
(vectorp def))
- "a keyboard macro.")
+ "a keyboard macro")
((subrp def)
- (concat beg "built-in function."))
+ (concat beg "built-in function"))
((byte-code-function-p def)
- (concat beg "compiled Lisp function."))
+ (concat beg "compiled Lisp function"))
((symbolp def)
- (format "alias for `%s'." def))
+ (format "alias for `%s'" def))
((eq (car-safe def) 'lambda)
- (concat beg "Lisp function."))
+ (concat beg "Lisp function"))
((eq (car-safe def) 'macro)
- "a Lisp macro.")
+ "a Lisp macro")
((eq (car-safe def) 'mocklisp)
- "a mocklisp function.")
+ "a mocklisp function")
((eq (car-safe def) 'autoload)
- (format "%s autoloaded Lisp %s."
+ (setq file-name (nth 1 def))
+ (format "%s autoloaded Lisp %s"
(if (commandp def) "an interactive" "an")
(if (nth 4 def) "macro" "function")
-;;; Including the file name made this line too long.
-;;; (nth 1 def)
))
(t "")))
+ (or file-name
+ (setq file-name (describe-function-find-file function)))
+ (if file-name
+ (progn
+ (princ " in `")
+ ;; We used to add .el to the file name,
+ ;; but that's completely wrong when the user used load-file.
+ (princ file-name)
+ (princ "'")))
+ (princ ".")
(terpri)
(let ((arglist (cond ((byte-code-function-p def)
(car (append def nil)))
(intern (upcase (symbol-name arg)))))
arglist)))
(terpri))))
- (if (documentation function)
- (progn (terpri)
- (princ (documentation function)))
- (princ "not documented"))
- )
+ (let ((doc (documentation function)))
+ (if doc
+ (progn (terpri)
+ (princ doc))
+ (princ "not documented"))))
(print-help-return-message)
- ;; Return the text we displayed.
- (save-excursion (set-buffer standard-output) (buffer-string))))
+ (save-excursion
+ (set-buffer standard-output)
+ (help-mode)
+ ;; Return the text we displayed.
+ (buffer-string))))
(defun variable-at-point ()
(condition-case ()
- (save-excursion
- (forward-sexp -1)
- (skip-chars-forward "'")
- (let ((obj (read (current-buffer))))
- (and (symbolp obj) (boundp obj) obj)))
+ (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))))
+ (and (symbolp obj) (boundp obj) obj)))
+ (set-syntax-table stab)))
(error nil)))
(defun describe-variable (variable)
v (intern val)))))
(with-output-to-temp-buffer "*Help*"
(prin1 variable)
- (princ "'s value is ")
(if (not (boundp variable))
- (princ "void.")
+ (princ " is void")
+ (princ "'s value is ")
(prin1 (symbol-value variable)))
- (terpri) (terpri)
+ (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 ")
+ (prin1 (default-value variable)))
+ (terpri)))
+ (terpri)
(princ "Documentation:")
(terpri)
(let ((doc (documentation-property variable 'variable-documentation)))
- (if doc
- (princ (substitute-command-keys doc))
- (princ "not documented as a variable.")))
+ (princ (or doc "not documented as a variable.")))
(print-help-return-message)
- ;; Return the text we displayed.
- (save-excursion (set-buffer standard-output) (buffer-string))))
-
-(defun command-apropos (string)
- "Like apropos but lists only symbols that are names of commands
-\(interactively callable functions). Argument REGEXP is a regular expression
-that is matched against command symbol names. Returns list of symbols and
-documentation found."
- (interactive "sCommand apropos (regexp): ")
- (let ((message
- (let ((standard-output (get-buffer-create "*Help*")))
- (print-help-return-message 'identity))))
- (if (apropos string t 'commandp)
- (and message (message message)))))
+ (save-excursion
+ (set-buffer standard-output)
+ (help-mode)
+ ;; Return the text we displayed.
+ (buffer-string))))
+
+(defun where-is (definition)
+ "Print message listing key sequences that invoke specified command.
+Argument is a command definition, usually a symbol with a function definition."
+ (interactive
+ (let ((fn (function-called-at-point))
+ (enable-recursive-minibuffers t)
+ val)
+ (setq val (completing-read (if fn
+ (format "Where is command (default %s): " fn)
+ "Where is command: ")
+ obarray 'fboundp t))
+ (list (if (equal val "")
+ fn (intern val)))))
+ (let* ((keys (where-is-internal definition overriding-local-map nil nil))
+ (keys1 (mapconcat 'key-description keys ", ")))
+ (if (> (length keys1) 0)
+ (message "%s is on %s" definition keys1)
+ (message "%s is not on any key" definition)))
+ nil)
(defun locate-library (library &optional nosuffix)
"Show the full path name of Emacs library LIBRARY.