X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/b3843c61858aa78d450bdaaa2e597f0a1f7b39e4..e24ad6dd2b3499a367fff0dfd9c9c8a4bdaeb4fd:/lisp/help-mode.el diff --git a/lisp/help-mode.el b/lisp/help-mode.el index 1435eb019e..9d10d5170b 100644 --- a/lisp/help-mode.el +++ b/lisp/help-mode.el @@ -1,17 +1,18 @@ ;;; help-mode.el --- `help-mode' used by *Help* buffers ;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999, 2000, 2001, 2002, -;; 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +;; 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. ;; Maintainer: FSF ;; Keywords: help, internal +;; Package: emacs ;; This file is part of GNU Emacs. -;; GNU Emacs is free software; you can redistribute it and/or modify +;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 3, or (at your option) -;; any later version. +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -19,9 +20,7 @@ ;; 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, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs. If not, see . ;;; Commentary: @@ -32,6 +31,7 @@ (require 'button) (require 'view) +(eval-when-compile (require 'easymenu)) (defvar help-mode-map (make-sparse-keymap) "Keymap for help mode.") @@ -45,6 +45,20 @@ ;; Documentation only, since we use minor-mode-overriding-map-alist. (define-key help-mode-map "\r" 'help-follow) +(easy-menu-define help-mode-menu help-mode-map + "Menu for Help Mode." + '("Help-Mode" + ["Show Help for Symbol" help-follow-symbol + :help "Show the docs for the symbol at point"] + ["Previous Topic" help-go-back + :help "Go back to previous topic in this help buffer"] + ["Next Topic" help-go-forward + :help "Go back to next topic in this help buffer"] + ["Move to Previous Button" backward-button + :help "Move to the Next Button in the help buffer"] + ["Move to Next Button" forward-button + :help "Move to the Next Button in the help buffer"])) + (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'. @@ -54,7 +68,7 @@ To use the element, do (apply FUNCTION ARGS) then goto the point.") (make-variable-buffer-local 'help-xref-stack) (defvar help-xref-forward-stack nil - "The stack of used to navigate help forwards after using the back button. + "A stack used to navigate help forwards after using the back button. Used by `help-follow' and `help-xref-go-forward'. An element looks like (POSITION FUNCTION ARGS...). To use the element, do (apply FUNCTION ARGS) then goto the point.") @@ -144,6 +158,12 @@ The format is (FUNCTION ARGS...).") 'help-function #'help-xref-go-forward 'help-echo (purecopy "mouse-2, RET: move forward to next help buffer")) +(define-button-type 'help-info-variable + :supertype 'help-xref + ;; the name of the variable is put before the argument to Info + 'help-function (lambda (a v) (info v)) + 'help-echo (purecopy "mouse-2, RET: read this Info node")) + (define-button-type 'help-info :supertype 'help-xref 'help-function #'info @@ -183,6 +203,22 @@ The format is (FUNCTION ARGS...).") (message "Unable to find location in file")))) 'help-echo (purecopy "mouse-2, RET: find function's definition")) +(define-button-type 'help-function-cmacro + :supertype 'help-xref + 'help-function (lambda (fun file) + (setq file (locate-library file t)) + (if (and file (file-readable-p file)) + (progn + (pop-to-buffer (find-file-noselect file)) + (goto-char (point-min)) + (if (re-search-forward + (format "^[ \t]*(define-compiler-macro[ \t]+%s" + (regexp-quote (symbol-name fun))) nil t) + (forward-line 0) + (message "Unable to find location in file"))) + (message "Unable to find file"))) + 'help-echo (purecopy "mouse-2, RET: find function's compiler macro")) + (define-button-type 'help-variable-def :supertype 'help-xref 'help-function (lambda (var &optional file) @@ -209,6 +245,16 @@ The format is (FUNCTION ARGS...).") (message "Unable to find location in file")))) 'help-echo (purecopy "mouse-2, RET: find face's definition")) +(define-button-type 'help-package + :supertype 'help-xref + 'help-function 'describe-package + 'help-echo (purecopy "mouse-2, RET: Describe package")) + +(define-button-type 'help-package-def + :supertype 'help-xref + 'help-function (lambda (file) (dired file)) + 'help-echo (purecopy "mouse-2, RET: visit package directory")) + ;;;###autoload (defun help-mode () @@ -221,13 +267,25 @@ Commands: (use-local-map help-mode-map) (setq mode-name "Help") (setq major-mode 'help-mode) + (view-mode) - (make-local-variable 'view-no-disable-on-exit) - (setq view-no-disable-on-exit t) - (setq view-exit-action (lambda (buffer) - (or (window-minibuffer-p (selected-window)) - (one-window-p t) - (delete-window)))) + (set (make-local-variable 'view-no-disable-on-exit) t) + ;; With Emacs 22 `view-exit-action' could delete the selected window + ;; disregarding whether the help buffer was shown in that window at + ;; all. Since `view-exit-action' is called with the help buffer as + ;; argument it seems more appropriate to have it work on the buffer + ;; only and leave it to `view-mode-exit' to delete any associated + ;; window(s). + (setq view-exit-action + (lambda (buffer) + ;; Use `with-current-buffer' to make sure that `bury-buffer' + ;; also removes BUFFER from the selected window. + (with-current-buffer buffer + (bury-buffer)))) + + (set (make-local-variable 'revert-buffer-function) + 'help-mode-revert-buffer) + (run-mode-hooks 'help-mode-hook)) ;;;###autoload @@ -237,16 +295,23 @@ Commands: ;;;###autoload (defun help-mode-finish () - (let ((entry (assq (selected-window) view-return-to-alist))) - (if entry - ;; When entering Help mode from the Help window, - ;; such as by following a link, preserve the same - ;; meaning for the q command. - ;; (setcdr entry (cons (selected-window) help-return-method)) - nil - (setq view-return-to-alist - (cons (cons (selected-window) help-return-method) - view-return-to-alist)))) + (if (eq help-window t) + ;; If `help-window' is t, `view-return-to-alist' is handled by + ;; `with-help-window'. In this case set `help-window' to the + ;; selected window since now is the only moment where we can + ;; unambiguously identify it. + (setq help-window (selected-window)) + (let ((entry (assq (selected-window) view-return-to-alist))) + (if entry + ;; When entering Help mode from the Help window, + ;; such as by following a link, preserve the same + ;; meaning for the q command. + ;; (setcdr entry (cons (selected-window) help-return-method)) + nil + (setq view-return-to-alist + (cons (cons (selected-window) help-return-method) + view-return-to-alist))))) + (when (eq major-mode 'help-mode) ;; View mode's read-only status of existing *Help* buffer is lost ;; by with-output-to-temp-buffer. @@ -321,7 +386,13 @@ restore it properly when going back." (defvar help-xref-following nil "Non-nil when following a help cross-reference.") +;;;###autoload (defun help-buffer () + "Return the name of a buffer for inserting help. +If `help-xref-following' is non-nil, this is the name of the +current buffer. +Otherwise, it is *Help*; if no buffer with that name currently +exists, it is created." (buffer-name ;for with-output-to-temp-buffer (if help-xref-following (current-buffer) @@ -356,170 +427,172 @@ A special reference `back' is made to return back through a stack of help buffers. Variable `help-back-label' specifies the text for that." (interactive "b") - (save-excursion - (set-buffer (or buffer (current-buffer))) - (goto-char (point-min)) - ;; Skip the header-type info, though it might be useful to parse - ;; it at some stage (e.g. "function in `library'"). - (forward-paragraph) - (let ((old-modified (buffer-modified-p))) - (let ((stab (syntax-table)) - (case-fold-search t) - (inhibit-read-only t)) - (set-syntax-table emacs-lisp-mode-syntax-table) - ;; The following should probably be abstracted out. - (unwind-protect - (progn - ;; Info references - (save-excursion - (while (re-search-forward help-xref-info-regexp nil t) - (let ((data (match-string 2))) - (save-match-data - (unless (string-match "^([^)]+)" data) - (setq data (concat "(emacs)" data)))) - (help-xref-button 2 'help-info data)))) - ;; URLs - (save-excursion - (while (re-search-forward help-xref-url-regexp nil t) - (let ((data (match-string 1))) - (help-xref-button 1 'help-url data)))) - ;; Mule related keywords. Do this before trying - ;; `help-xref-symbol-regexp' because some of Mule - ;; keywords have variable or function definitions. - (if help-xref-mule-regexp - (save-excursion - (while (re-search-forward help-xref-mule-regexp nil t) - (let* ((data (match-string 7)) - (sym (intern-soft data))) - (cond - ((match-string 3) ; coding system - (and sym (coding-system-p sym) - (help-xref-button 6 'help-coding-system sym))) - ((match-string 4) ; input method - (and (assoc data input-method-alist) - (help-xref-button 7 'help-input-method data))) - ((or (match-string 5) (match-string 6)) ; charset - (and sym (charsetp sym) - (help-xref-button 7 'help-character-set sym))) - ((assoc data input-method-alist) - (help-xref-button 7 'help-character-set data)) - ((and sym (coding-system-p sym)) - (help-xref-button 7 'help-coding-system sym)) - ((and sym (charsetp sym)) - (help-xref-button 7 'help-character-set sym))))))) - ;; Quoted symbols - (save-excursion - (while (re-search-forward help-xref-symbol-regexp nil t) - (let* ((data (match-string 8)) - (sym (intern-soft data))) - (if sym - (cond - ((match-string 3) ; `variable' &c - (and (or (boundp sym) ; `variable' doesn't ensure + (with-current-buffer (or buffer (current-buffer)) + (save-excursion + (goto-char (point-min)) + ;; Skip the header-type info, though it might be useful to parse + ;; it at some stage (e.g. "function in `library'"). + (forward-paragraph) + (let ((old-modified (buffer-modified-p))) + (let ((stab (syntax-table)) + (case-fold-search t) + (inhibit-read-only t)) + (set-syntax-table emacs-lisp-mode-syntax-table) + ;; The following should probably be abstracted out. + (unwind-protect + (progn + ;; Info references + (save-excursion + (while (re-search-forward help-xref-info-regexp nil t) + (let ((data (match-string 2))) + (save-match-data + (unless (string-match "^([^)]+)" data) + (setq data (concat "(emacs)" data))) + (setq data ;; possible newlines if para filled + (replace-regexp-in-string "[ \t\n]+" " " data t t))) + (help-xref-button 2 'help-info data)))) + ;; URLs + (save-excursion + (while (re-search-forward help-xref-url-regexp nil t) + (let ((data (match-string 1))) + (help-xref-button 1 'help-url data)))) + ;; Mule related keywords. Do this before trying + ;; `help-xref-symbol-regexp' because some of Mule + ;; keywords have variable or function definitions. + (if help-xref-mule-regexp + (save-excursion + (while (re-search-forward help-xref-mule-regexp nil t) + (let* ((data (match-string 7)) + (sym (intern-soft data))) + (cond + ((match-string 3) ; coding system + (and sym (coding-system-p sym) + (help-xref-button 6 'help-coding-system sym))) + ((match-string 4) ; input method + (and (assoc data input-method-alist) + (help-xref-button 7 'help-input-method data))) + ((or (match-string 5) (match-string 6)) ; charset + (and sym (charsetp sym) + (help-xref-button 7 'help-character-set sym))) + ((assoc data input-method-alist) + (help-xref-button 7 'help-character-set data)) + ((and sym (coding-system-p sym)) + (help-xref-button 7 'help-coding-system sym)) + ((and sym (charsetp sym)) + (help-xref-button 7 'help-character-set sym))))))) + ;; Quoted symbols + (save-excursion + (while (re-search-forward help-xref-symbol-regexp nil t) + (let* ((data (match-string 8)) + (sym (intern-soft data))) + (if sym + (cond + ((match-string 3) ; `variable' &c + (and (or (boundp sym) ; `variable' doesn't ensure ; it's actually bound - (get sym 'variable-documentation)) - (help-xref-button 8 'help-variable sym))) - ((match-string 4) ; `function' &c - (and (fboundp sym) ; similarly - (help-xref-button 8 'help-function sym))) - ((match-string 5) ; `face' - (and (facep sym) - (help-xref-button 8 'help-face sym))) - ((match-string 6)) ; nothing for `symbol' - ((match-string 7) -;;; this used: -;;; #'(lambda (arg) -;;; (let ((location -;;; (find-function-noselect arg))) -;;; (pop-to-buffer (car location)) -;;; (goto-char (cdr location)))) - (help-xref-button 8 'help-function-def sym)) - ((and - (facep sym) - (save-match-data (looking-at "[ \t\n]+face\\W"))) - (help-xref-button 8 'help-face sym)) - ((and (or (boundp sym) - (get sym 'variable-documentation)) - (fboundp sym)) - ;; We can't intuit whether to use the - ;; variable or function doc -- supply both. - (help-xref-button 8 'help-symbol sym)) - ((and - (or (boundp sym) - (get sym 'variable-documentation)) - (or - (documentation-property - sym 'variable-documentation) - (condition-case nil - (documentation-property - (indirect-variable sym) - 'variable-documentation) - (cyclic-variable-indirection nil)))) - (help-xref-button 8 'help-variable sym)) - ((fboundp sym) - (help-xref-button 8 'help-function sym))))))) - ;; An obvious case of a key substitution: - (save-excursion - (while (re-search-forward - ;; Assume command name is only word and symbol - ;; characters to get things like `use M-x foo->bar'. - ;; Command required to end with word constituent - ;; to avoid `.' at end of a sentence. - "\\= (current-column) col) - (looking-at "\\(\\sw\\|\\s_\\)+$")) - (let ((sym (intern-soft (match-string 0)))) - (if (fboundp sym) - (help-xref-button 0 'help-function sym)))) - (forward-line)))))) - (set-syntax-table stab)) - ;; Delete extraneous newlines at the end of the docstring - (goto-char (point-max)) - (while (and (not (bobp)) (bolp)) - (delete-char -1)) - (insert "\n") - (when (or help-xref-stack help-xref-forward-stack) - (insert "\n")) - ;; Make a back-reference in this buffer if appropriate. - (when help-xref-stack - (help-insert-xref-button help-back-label 'help-back - (current-buffer))) - ;; Make a forward-reference in this buffer if appropriate. - (when help-xref-forward-stack - (when help-xref-stack - (insert "\t")) - (help-insert-xref-button help-forward-label 'help-forward - (current-buffer))) - (when (or help-xref-stack help-xref-forward-stack) - (insert "\n"))) - ;; View mode steals RET from us. - (set (make-local-variable 'minor-mode-overriding-map-alist) - (list (cons 'view-mode help-xref-override-view-map))) - (set-buffer-modified-p old-modified)))) + (get sym 'variable-documentation)) + (help-xref-button 8 'help-variable sym))) + ((match-string 4) ; `function' &c + (and (fboundp sym) ; similarly + (help-xref-button 8 'help-function sym))) + ((match-string 5) ; `face' + (and (facep sym) + (help-xref-button 8 'help-face sym))) + ((match-string 6)) ; nothing for `symbol' + ((match-string 7) + ;; this used: + ;; #'(lambda (arg) + ;; (let ((location + ;; (find-function-noselect arg))) + ;; (pop-to-buffer (car location)) + ;; (goto-char (cdr location)))) + (help-xref-button 8 'help-function-def sym)) + ((and + (facep sym) + (save-match-data (looking-at "[ \t\n]+face\\W"))) + (help-xref-button 8 'help-face sym)) + ((and (or (boundp sym) + (get sym 'variable-documentation)) + (fboundp sym)) + ;; We can't intuit whether to use the + ;; variable or function doc -- supply both. + (help-xref-button 8 'help-symbol sym)) + ((and + (or (boundp sym) + (get sym 'variable-documentation)) + (or + (documentation-property + sym 'variable-documentation) + (condition-case nil + (documentation-property + (indirect-variable sym) + 'variable-documentation) + (cyclic-variable-indirection nil)))) + (help-xref-button 8 'help-variable sym)) + ((fboundp sym) + (help-xref-button 8 'help-function sym))))))) + ;; An obvious case of a key substitution: + (save-excursion + (while (re-search-forward + ;; Assume command name is only word and symbol + ;; characters to get things like `use M-x foo->bar'. + ;; Command required to end with word constituent + ;; to avoid `.' at end of a sentence. + "\\= (current-column) col) + (looking-at "\\(\\sw\\|\\s_\\)+$")) + (let ((sym (intern-soft (match-string 0)))) + (if (fboundp sym) + (help-xref-button 0 'help-function sym)))) + (forward-line)))))) + (set-syntax-table stab)) + ;; Delete extraneous newlines at the end of the docstring + (goto-char (point-max)) + (while (and (not (bobp)) (bolp)) + (delete-char -1)) + (insert "\n") + (when (or help-xref-stack help-xref-forward-stack) + (insert "\n")) + ;; Make a back-reference in this buffer if appropriate. + (when help-xref-stack + (help-insert-xref-button help-back-label 'help-back + (current-buffer))) + ;; Make a forward-reference in this buffer if appropriate. + (when help-xref-forward-stack + (when help-xref-stack + (insert "\t")) + (help-insert-xref-button help-forward-label 'help-forward + (current-buffer))) + (when (or help-xref-stack help-xref-forward-stack) + (insert "\n"))) + ;; View mode steals RET from us. + (set (make-local-variable 'minor-mode-overriding-map-alist) + (list (cons 'view-mode help-xref-override-view-map))) + (set-buffer-modified-p old-modified))))) ;;;###autoload (defun help-xref-button (match-number type &rest args) @@ -668,14 +741,14 @@ help buffer." (if (get-buffer-window buffer) (set-window-point (get-buffer-window buffer) position) (goto-char position))))) - + (defun help-go-back () "Go back to previous topic in this help buffer." (interactive) (if help-xref-stack (help-xref-go-back (current-buffer)) (error "No previous help buffer"))) - + (defun help-go-forward () "Go back to next topic in this help buffer." (interactive) @@ -724,6 +797,17 @@ Show all docs for that symbol as either a variable, function or face." (fboundp sym) (facep sym)) (help-do-xref pos #'help-xref-interned (list sym))))) +(defun help-mode-revert-buffer (ignore-auto noconfirm) + (when (or noconfirm (yes-or-no-p "Revert help buffer? ")) + (let ((pos (point)) + (item help-xref-stack-item) + ;; Pretend there is no current item to add to the history. + (help-xref-stack-item nil) + ;; Use the current buffer. + (help-xref-following t)) + (apply (car item) (cdr item)) + (goto-char pos)))) + (defun help-insert-string (string) "Insert STRING to the help buffer and install xref info for it. This function can be used to restore the old contents of the help buffer