(define-key help-map "F" 'view-emacs-FAQ)
(define-key help-map "i" 'info)
+(define-key help-map "4i" 'info-other-window)
(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 "\C-i" 'info-lookup-symbol)
(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'.")
+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).")
(put 'help-xref-stack 'permanent-local t)
(defvar help-xref-stack-item nil
- "An item for `help-follow' in this buffer to push onto `help-xref-stack'.")
+ "An item for `help-follow' in this buffer to push onto `help-xref-stack'.
+The format is (FUNCTION ARGS...).")
(put 'help-xref-stack-item 'permanent-local t)
(setq-default help-xref-stack nil help-xref-stack-item nil)
"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."
(interactive "kDescribe key briefly: \nP")
- ;; If this key seq ends with a down event, discard the
- ;; following click or drag event. Otherwise that would
- ;; erase the message.
- (let ((type (aref key (1- (length key)))))
- (if (listp type) (setq type (car type)))
- (and (symbolp type)
- (memq 'down (event-modifiers type))
- (read-event)))
(save-excursion
(let ((modifiers (event-modifiers (aref key 0)))
(standard-output (if insert (current-buffer) t))
(if (or (null defn) (integerp defn))
(princ (format "%s is undefined" key-desc))
(princ (format (if insert
- "%s (%s)"
+ "`%s' (`%s')"
(if (windowp window)
"%s at that spot runs the command %s"
"%s runs the command %s"))
(defun describe-key (key)
"Display documentation of the function invoked by KEY. KEY is a string."
(interactive "kDescribe key: ")
- ;; If this key seq ends with a down event, discard the
- ;; following click or drag event. Otherwise that would
- ;; erase the message.
- (let ((type (aref key (1- (length key)))))
- (if (listp type) (setq type (car type)))
- (and (symbolp type)
- (memq 'down (event-modifiers type))
- (read-event)))
(save-excursion
(let ((modifiers (event-modifiers (aref key 0)))
window position)
(princ mode-name)
(princ " mode:\n")
(princ (documentation major-mode))
- (help-setup-xref (cons #'help-xref-mode (current-buffer)) (interactive-p))
+ (help-setup-xref (list #'help-xref-mode (current-buffer)) (interactive-p))
(print-help-return-message)))
;; So keyboard macro definitions are documented correctly
(goto-char (point-min))
(while (progn (move-to-column 50) (not (eobp)))
(search-forward " " nil t)
- (insert "\n")))
- (setq help-xref-stack nil
- help-xref-stack-item nil)
+ (insert "\n"))
+ (setq help-xref-stack nil
+ help-xref-stack-item nil))
(print-help-return-message)))
(defalias 'help 'help-for-help)
((byte-code-function-p def)
(concat beg "compiled Lisp function"))
((symbolp def)
+ (while (symbolp (symbol-function def))
+ (setq def (symbol-function def)))
(format "alias for `%s'" def))
((eq (car-safe def) 'lambda)
(concat beg "Lisp function"))
(with-current-buffer "*Help*"
(save-excursion
(re-search-backward "`\\([^`']+\\)'" nil t)
- (help-xref-button 1 #'find-function function)))))
+ (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)
- (let* ((inner-function (if (and (listp def) 'macro)
- (cdr def)
- def))
- (arglist (cond ((byte-code-function-p inner-function)
- (car (append inner-function nil)))
- ((eq (car-safe inner-function) 'lambda)
- (nth 1 inner-function))
- (t t))))
+ ;; 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))
+ (t t))))
(if (listp arglist)
(progn
(princ (cons function
(if doc
(progn (terpri)
(princ doc)
- (help-setup-xref (cons #'describe-function function) (interactive-p)))
+ (help-setup-xref (list #'describe-function function) (interactive-p)))
(princ "not documented")))))
;; We return 0 if we can't find a variable to return.
(terpri)
(let ((doc (documentation-property variable 'variable-documentation)))
(princ (or doc "not documented as a variable.")))
- (help-setup-xref (cons #'describe-variable variable) (interactive-p))
+ (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 for a custom-type property
+ ;; because those are only present after the var's definition
+ ;; has been loaded.
+ (if (user-variable-p variable)
+ (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)
+ ))))
+
(print-help-return-message)
(save-excursion
(set-buffer standard-output)
(buffer-string))))
(message "You did not specify a variable")))
-(defun describe-bindings (&optional prefix)
+(defun describe-bindings (&optional prefix buffer)
"Show a list of all defined keys, and their definitions.
We put that list in a buffer, and display the buffer.
The optional argument PREFIX, if non-nil, should be a key sequence;
-then we display only bindings that start with that prefix."
+then we display only bindings that start with that prefix.
+The optional argument BUFFER specifies which buffer's bindings
+to display (default, the current buffer)."
(interactive "P")
- (setq help-xref-stack nil
- help-xref-stack-item nil)
- (describe-bindings-internal nil prefix))
+ (or buffer (setq buffer (current-buffer)))
+ (with-current-buffer buffer
+ (describe-bindings-internal nil prefix))
+ (with-current-buffer "*Help*"
+ (help-setup-xref (list #'describe-bindings prefix buffer)
+ (interactive-p))))
(defun where-is (definition &optional insert)
"Print message listing key sequences that invoke specified command.
(defun help-setup-xref (item interactive-p)
"Invoked from commands using the \"*Help*\" buffer to install some xref info.
-ITEM is a (function . args) pair appropriate for recreating the help
+ITEM is a (FUNCTION . ARGS) pair appropriate for recreating the help
buffer after following a reference. INTERACTIVE-P is non-nil if the
calling command was invoked interactively. In this case the stack of
items for help buffer \"back\" buttons is cleared."
(help-xref-button 1 #'describe-function sym)))))
;; Look for commands in whole keymap substitutions:
(save-excursion
+ ;; Make sure to find the first keymap.
+ (goto-char (point-min))
;; Find a header and the column at which the command
;; name will be found.
(while (re-search-forward "^key +binding\n\\(-+ +\\)-+\n\n"
(insert "\n\n" help-back-label))
;; Just to provide the match data:
(looking-at (concat "\n\n\\(" (regexp-quote help-back-label) "\\)"))
- (help-xref-button 1 #'help-xref-go-back nil)))
+ (help-xref-button 1 #'help-xref-go-back (current-buffer))))
;; View mode steals RET from us.
(set (make-local-variable 'minor-mode-overriding-map-alist)
(list (cons 'view-mode
(goto-char (point-max))
(insert "\n\n" fdoc))
(goto-char (point-min))
- (help-setup-xref (cons #'help-xref-interned symbol) nil))
+ (help-setup-xref (list #'help-xref-interned symbol) nil))
(defun help-xref-mode (buffer)
"Do a `describe-mode' for the specified BUFFER."
(defun help-follow-mouse (click)
"Follow the cross-reference that you click on."
(interactive "e")
- (save-excursion
- (let* ((start (event-start click))
- (window (car start))
- (pos (car (cdr start))))
- (set-buffer (window-buffer window))
+ (let* ((start (event-start click))
+ (window (car start))
+ (pos (car (cdr start))))
+ (with-current-buffer (window-buffer window)
(help-follow pos))))
-(defun help-xref-go-back ()
- "Go back to the previous help buffer using info on `help-xref-stack'."
+(defun help-xref-go-back (buffer)
+ "Go back to the previous help buffer text using info on `help-xref-stack'."
(interactive)
- (when help-xref-stack
- (setq help-xref-stack (cdr help-xref-stack)) ; due to help-follow
- (let* ((item (car help-xref-stack))
- (method (car item))
- (args (cdr item)))
- (setq help-xref-stack (cdr help-xref-stack))
- (if (listp args)
- (apply method args)
- (funcall method args)))))
+ (let (item position method args)
+ (with-current-buffer buffer
+ (when help-xref-stack
+ (setq help-xref-stack (cdr help-xref-stack)) ; due to help-follow
+ (setq item (car help-xref-stack)
+ position (car item)
+ method (cadr item)
+ args (cddr item))
+ (setq help-xref-stack (cdr help-xref-stack))))
+ (apply method args)
+ (goto-char position)))
(defun help-go-back ()
(interactive)
For the cross-reference format, see `help-make-xrefs'."
(interactive "d")
- (let* ((help-data (get-text-property pos 'help-xref))
+ (let* ((help-data (or (and (not (= pos (point-max)))
+ (get-text-property pos 'help-xref))
+ (and (not (= pos (point-min)))
+ (get-text-property (1- pos) 'help-xref))))
(method (car help-data))
(args (cdr help-data)))
- (setq help-xref-stack (cons help-xref-stack-item help-xref-stack))
+ (setq help-xref-stack (cons (cons (point) help-xref-stack-item)
+ help-xref-stack))
(setq help-xref-stack-item nil)
(when help-data
;; There is a reference at point. Follow it.