- (error nil)))
- (set-syntax-table stab))))
-
-(defvar symbol-file-load-history-loaded nil
- "Non-nil means we have loaded the file `fns-VERSION.el' in `exec-directory'.
-That file records the part of `load-history' for preloaded files,
-which is cleared out before dumping to make Emacs smaller.")
-
-(defun symbol-file (function)
- "Return the input source from which FUNCTION was loaded.
-The value is normally a string that was passed to `load':
-either an absolute file name, or a library name
-\(with no directory name and no `.el' or `.elc' at the end).
-It can also be nil, if the definition is not associated with any file."
- (unless symbol-file-load-history-loaded
- (load (expand-file-name
- ;; fns-XX.YY.ZZ.el does not work on DOS filesystem.
- (if (eq system-type 'ms-dos)
- "fns.el"
- (format "fns-%s.el" emacs-version))
- exec-directory)
- ;; The file name fns-%s.el already has a .el extension.
- nil nil t)
- (setq symbol-file-load-history-loaded t))
- (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
- (let ((fn (function-called-at-point))
- (enable-recursive-minibuffers t)
- val)
- (setq val (completing-read (if fn
- (format "Describe function (default %s): " fn)
- "Describe function: ")
- obarray 'fboundp t nil nil (symbol-name fn)))
- (list (if (equal val "")
- fn (intern val)))))
- (if function
- (with-output-to-temp-buffer "*Help*"
- (prin1 function)
- ;; Use " is " instead of a colon so that
- ;; it is easier to get out the function name using forward-sexp.
- (princ " is ")
- (describe-function-1 function nil (interactive-p))
- (print-help-return-message)
- (save-excursion
- (set-buffer standard-output)
- ;; Return the text we displayed.
- (buffer-string)))
- (message "You didn't specify a function")))
-
-(defun describe-function-1 (function parens interactive-p)
- (let* ((def (if (symbolp function)
- (symbol-function function)
- function))
- file-name string need-close
- (beg (if (commandp def) "an interactive " "a ")))
- (setq string
- (cond ((or (stringp def)
- (vectorp def))
- "a keyboard macro")
- ((subrp def)
- (concat beg "built-in function"))
- ((byte-code-function-p def)
- (concat beg "compiled Lisp function"))
- ((symbolp def)
- (while (symbolp (symbol-function def))
- (setq def (symbol-function def)))
- (format "an alias for `%s'" def))
- ((eq (car-safe def) 'lambda)
- (concat beg "Lisp function"))
- ((eq (car-safe def) 'macro)
- "a Lisp macro")
- ((eq (car-safe def) 'mocklisp)
- "a mocklisp function")
- ((eq (car-safe def) 'autoload)
- (setq file-name (nth 1 def))
- (format "%s autoloaded %s"
- (if (commandp def) "an interactive" "an")
- (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)
- (princ "("))
- (princ string)
- (with-current-buffer "*Help*"
- (save-excursion
- (save-match-data
- (if (re-search-backward "alias for `\\([^`']+\\)'" nil t)
- (help-xref-button 1 #'describe-function def)))))
- (or file-name
- (setq file-name (symbol-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 "'")
- ;; Make a hyperlink to the library.
- (with-current-buffer "*Help*"
- (save-excursion
- (re-search-backward "`\\([^`']+\\)'" nil t)
- (help-xref-button 1 #'(lambda (arg)
- (let ((location
- (find-function-noselect arg)))
- (pop-to-buffer (car location))
- (goto-char (cdr location))))
- function)))))
- (if need-close (princ ")"))
- (princ ".")
- (terpri)
- ;; Handle symbols aliased to other symbols.
- (setq def (indirect-function def))
- ;; If definition is a macro, find the function inside it.
- (if (eq (car-safe def) 'macro)
- (setq def (cdr def)))
- (let ((arglist (cond ((byte-code-function-p def)
- (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))))
- (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)
- (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 ()
- "Return the bound variable symbol found around point.
-Return 0 if there is no such symbol."
- (condition-case ()
- (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))))
- (or (and (symbolp obj) (boundp obj) obj)
- 0)))
- (set-syntax-table stab)))
- (error 0)))
-
-(defun describe-variable (variable)
- "Display the full documentation of VARIABLE (a symbol).
-Returns the documentation as a string, also."
- (interactive
- (let ((v (variable-at-point))
- (enable-recursive-minibuffers t)
- val)
- (setq val (completing-read (if (symbolp v)
- (format "Describe variable (default %s): " v)
- "Describe variable: ")
- obarray 'boundp t nil nil
- (if (symbolp v) (symbol-name v))))
- (list (if (equal val "")
- v (intern val)))))
- (if (symbolp variable)
- (let (valvoid)
- (with-output-to-temp-buffer "*Help*"
- (prin1 variable)
- (if (not (boundp variable))
- (progn
- (princ " is void")
- (terpri)
- (setq valvoid t))
- (princ "'s value is ")
- (terpri)
- (pp (symbol-value variable))
- (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)))
- (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)
- (forward-sexp 1)
- (delete-region (point) (progn (end-of-line) (point)))
- (insert "'s value is shown below.\n\n")
- (save-excursion
- (insert "\n\nValue:"))))))
- (princ "Documentation:")
- (terpri)
- (let ((doc (documentation-property variable 'variable-documentation)))
- (princ (or doc "not documented as a variable.")))
- (help-setup-xref (list #'describe-variable variable) (interactive-p))
-
- ;; Make a link to customize if this variable can be customized.
- ;; 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 (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)
- (princ (concat "You can " customize-label " this variable."))
- (with-current-buffer "*Help*"
- (save-excursion
- (re-search-backward
- (concat "\\(" customize-label "\\)") nil t)
- (help-xref-button 1 #'(lambda (v)
- (customize-variable v)) 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.)
- (let ((file-name (symbol-file variable)))
- (when file-name
- (princ "\n\nDefined in `")
- (princ file-name)
- (princ "'.")
- (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)))))
-
- (print-help-return-message)
- (save-excursion
- (set-buffer standard-output)
- ;; Return the text we displayed.
- (buffer-string))))
- (message "You did not specify a variable")))
+ (error nil))))
+ (let* ((str (find-tag-default))
+ (obj (if str (intern str))))
+ (and (symbolp obj) (fboundp obj) obj))))
+
+\f
+;;; `User' help functions
+
+(defun describe-distribution ()
+ "Display info on how to obtain the latest version of GNU Emacs."
+ (interactive)
+ (view-file (expand-file-name "DISTRIB" data-directory)))
+
+(defun describe-copying ()
+ "Display info on how you may redistribute copies of GNU Emacs."
+ (interactive)
+ (view-file (expand-file-name "COPYING" data-directory))
+ (goto-char (point-min)))
+
+(defun describe-project ()
+ "Display info on the GNU project."
+ (interactive)
+ (view-file (expand-file-name "THE-GNU-PROJECT" data-directory))
+ (goto-char (point-min)))
+
+(defun describe-no-warranty ()
+ "Display info on all the kinds of warranty Emacs does NOT have."
+ (interactive)
+ (describe-copying)
+ (let (case-fold-search)
+ (search-forward "NO WARRANTY")
+ (recenter 0)))
+
+(defun describe-prefix-bindings ()
+ "Describe the bindings of the prefix used to reach this command.
+The prefix described consists of all but the last event
+of the key sequence that ran this command."
+ (interactive)
+ (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)
+
+(defun view-emacs-news (&optional arg)
+ "Display info on recent changes to Emacs.
+With argument, display info only for the selected version."
+ (interactive "P")
+ (if (not arg)
+ (view-file (expand-file-name "NEWS" data-directory))
+ (let* ((map (sort
+ (delete-dups
+ (apply
+ 'nconc
+ (mapcar
+ (lambda (file)
+ (with-temp-buffer
+ (insert-file-contents
+ (expand-file-name file data-directory))
+ (let (res)
+ (while (re-search-forward
+ (if (string-match "^ONEWS\\.[0-9]+$" file)
+ "Changes in \\(?:Emacs\\|version\\)?[ \t]*\\([0-9]+\\(?:\\.[0-9]+\\)?\\)"
+ "^\* [^0-9\n]*\\([0-9]+\\.[0-9]+\\)") nil t)
+ (setq res (cons (list (match-string-no-properties 1)
+ file) res)))
+ res)))
+ (append '("NEWS" "ONEWS")
+ (directory-files data-directory nil
+ "^ONEWS\\.[0-9]+$" nil)))))
+ (lambda (a b)
+ (string< (car b) (car a)))))
+ (current (caar map))
+ (version (completing-read
+ (format "Read NEWS for the version (default %s): " current)
+ (mapcar 'car map) nil nil nil nil current))
+ (file (cadr (assoc version map)))
+ res)
+ (if (not file)
+ (error "No news is good news")
+ (view-file (expand-file-name file data-directory))
+ (widen)
+ (goto-char (point-min))
+ (when (re-search-forward
+ (concat (if (string-match "^ONEWS\\.[0-9]+$" file)
+ "Changes in \\(?:Emacs\\|version\\)?[ \t]*"
+ "^\* [^0-9\n]*") version)
+ nil t)
+ (beginning-of-line)
+ (narrow-to-region
+ (point)
+ (save-excursion
+ (while (and (setq res
+ (re-search-forward
+ (if (string-match "^ONEWS\\.[0-9]+$" file)
+ "Changes in \\(?:Emacs\\|version\\)?[ \t]*\\([0-9]+\\(?:\\.[0-9]+\\)?\\)"
+ "^\* [^0-9\n]*\\([0-9]+\\.[0-9]+\\)") nil t))
+ (equal (match-string-no-properties 1) version)))
+ (or res (goto-char (point-max)))
+ (beginning-of-line)
+ (point))))))))
+
+(defun view-todo (&optional arg)
+ "Display the Emacs TODO list."
+ (interactive "P")
+ (view-file (expand-file-name "TODO" data-directory)))
+
+(defun view-echo-area-messages ()
+ "View the log of recent echo-area messages: the `*Messages*' buffer.
+The number of messages retained in that buffer
+is specified by the variable `message-log-max'."
+ (interactive)
+ (switch-to-buffer (get-buffer-create "*Messages*")))
+
+(defun view-order-manuals ()
+ "Display the Emacs ORDERS file."
+ (interactive)
+ (view-file (expand-file-name "ORDERS" data-directory))
+ (goto-address))
+
+(defun view-emacs-FAQ ()
+ "Display the Emacs Frequently Asked Questions (FAQ) file."
+ (interactive)
+ ;; (find-file-read-only (expand-file-name "FAQ" data-directory))
+ (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.
+
+To record all your input on a file, use `open-dribble-file'."
+ (interactive)
+ (help-setup-xref (list #'view-lossage) (interactive-p))
+ (with-output-to-temp-buffer (help-buffer)
+ (princ (mapconcat (lambda (key)
+ (if (or (integerp key) (symbolp key) (listp key))
+ (single-key-description key)
+ (prin1-to-string key nil)))
+ (recent-keys)
+ " "))
+ (with-current-buffer standard-output
+ (goto-char (point-min))
+ (while (progn (move-to-column 50) (not (eobp)))
+ (search-forward " " nil t)
+ (insert "\n")))
+ (print-help-return-message)))
+
+\f
+;; Key bindings