;;; 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
(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))))
+ (read-event)))
(let ((defn (key-binding key)))
(if (or (null defn) (integerp defn))
(message "%s is undefined" (key-description key))
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)
+ (memq t (mapcar '(lambda (elt)
+ (string-match elt (buffer-name standard-output)))
+ special-display-regexps)))
+ nil
+ (if (or (member (buffer-name standard-output)
+ same-window-buffer-names)
+ (memq t (mapcar '(lambda (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."
(if (documentation defn)
(princ (documentation defn))
(princ "not documented"))
+ (save-excursion
+ (set-buffer standard-output)
+ (help-mode))
(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.
+(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 (indicator%s):\n"
+ pretty-minor-mode 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))))
+(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)))
(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 ()
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)))
(princ (substitute-command-keys doc))
(princ "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.