aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard M. Stallman1998-04-05 19:10:02 +0000
committerRichard M. Stallman1998-04-05 19:10:02 +0000
commit400a1b1f841ff44e197d530f9871cfa5843c428e (patch)
tree242ba609c5818a4268ac3db4c8615c2e4c3ab561
parent421f0bfe8e2a798dc6605a439f9a1f268ef15f8d (diff)
downloademacs-400a1b1f841ff44e197d530f9871cfa5843c428e.tar.gz
emacs-400a1b1f841ff44e197d530f9871cfa5843c428e.zip
(help-highlight-face): Use underline.
(help-mode-maybe): Ensure read-only. (help-xref-button): Obey help-highlight-p. (help-follow): Remove check for args being a list. (help-mode): Doc fix. (help-highlight-p): Put in help group. (help-make-xrefs): Insert button label in scope of inhibit-read-only binding. (help-mode-map, help-make-xrefs): Define TAB, RET correctly. Make hyperlinks for cross-reference info intuited from *Help* buffer. (help-font-lock-keywords): Removed. (help-mode-map): Define keys for navigating hyperlinks. (help-xref-stack, help-xref-stack-item): New permanent-local variables. (help-mode): Set font-lock-defaults to nil. (help-mode-maybe): Invoke help-make-xrefs in Help mode. (help-setup-xref): New function. (describe-key, describe-mode, describe-function, describe-variable): Call it. (view-lossage, describe-bindings): Nullify help-xref-stack, help-xref-stack-item. (help-highlight-p): New option. (help-highlight-face): New variable. (help-back-label, help-xref-symbol-regexp, help-xref-info-regexp): New variables. (help-setup-xref, help-make-xrefs, help-xref-button, help-xref-interned, help-xref-mode, help-follow-mouse, help-xref-go-back, help-go-back, help-follow, help-next-ref): New functions.
-rw-r--r--lisp/help.el332
1 files changed, 309 insertions, 23 deletions
diff --git a/lisp/help.el b/lisp/help.el
index b16adbdd8e2..bef91749235 100644
--- a/lisp/help.el
+++ b/lisp/help.el
@@ -1,6 +1,6 @@
1;;; help.el --- help commands for Emacs 1;;; help.el --- help commands for Emacs
2 2
3;; Copyright (C) 1985, 1986, 1993, 1994 Free Software Foundation, Inc. 3;; Copyright (C) 1985, 1986, 1993, 1994, 1998 Free Software Foundation, Inc.
4 4
5;; Maintainer: FSF 5;; Maintainer: FSF
6;; Keywords: help, internal 6;; Keywords: help, internal
@@ -91,27 +91,47 @@
91 91
92(define-key help-map "q" 'help-quit) 92(define-key help-map "q" 'help-quit)
93 93
94(defvar help-font-lock-keywords 94(define-key help-mode-map [mouse-2] 'help-follow-mouse)
95 (eval-when-compile 95(define-key help-mode-map "\C-c\C-b" 'help-go-back)
96 (let ((name-char "[-+a-zA-Z0-9_*]") (sym-char "[-+a-zA-Z0-9_:*]")) 96(define-key help-mode-map "\C-c\C-c" 'help-follow)
97 (list 97(define-key help-mode-map "\t" 'help-next-ref)
98 ;; 98(define-key help-mode-map [backtab] 'help-previous-ref)
99 ;; The symbol itself. 99;; Documentation only, since we use minor-mode-overriding-map-alist.
100 (list (concat "\\`\\(" name-char "+\\)\\(\\(:\\)\\|\\('\\)\\)") 100(define-key help-mode-map "\r" 'help-follow)
101 '(1 (if (match-beginning 3) 101
102 font-lock-function-name-face 102;; Font-locking is incompatible with the new xref stuff.
103 font-lock-variable-name-face))) 103;(defvar help-font-lock-keywords
104 ;; 104; (eval-when-compile
105 ;; Words inside `' which tend to be symbol names. 105; (let ((name-char "[-+a-zA-Z0-9_*]") (sym-char "[-+a-zA-Z0-9_:*]"))
106 (list (concat "`\\(" sym-char sym-char "+\\)'") 106; (list
107 1 'font-lock-constant-face t) 107; ;;
108 ;; 108; ;; The symbol itself.
109 ;; CLisp `:' keywords as builtins. 109; (list (concat "\\`\\(" name-char "+\\)\\(\\(:\\)\\|\\('\\)\\)")
110 (list (concat "\\<:" sym-char "+\\>") 0 'font-lock-builtin-face t)))) 110; '(1 (if (match-beginning 3)
111 "Default expressions to highlight in Help mode.") 111; font-lock-function-name-face
112; font-lock-variable-name-face)))
113; ;;
114; ;; Words inside `' which tend to be symbol names.
115; (list (concat "`\\(" sym-char sym-char "+\\)'")
116; 1 'font-lock-constant-face t)
117; ;;
118; ;; CLisp `:' keywords as references.
119; (list (concat "\\<:" sym-char "+\\>") 0 'font-lock-builtin-face t))))
120; "Default expressions to highlight in Help mode.")
121
122(defvar help-xref-stack nil
123 "A stack of ways by which to return to help buffers after following xrefs.
124Used by `help-follow' and `help-xref-go-back'.")
125(put 'help-xref-stack 'permanent-local t)
126
127(defvar help-xref-stack-item nil
128 "An item for `help-follow' in this buffer to push onto `help-xref-stack'.")
129(put 'help-xref-stack-item 'permanent-local t)
130
131(setq-default help-xref-stack nil help-xref-stack-item nil)
112 132
113(defun help-mode () 133(defun help-mode ()
114 "Major mode for viewing help text. 134 "Major mode for viewing help text and navigating references in it.
115Entry to this mode runs the normal hook `help-mode-hook'. 135Entry to this mode runs the normal hook `help-mode-hook'.
116Commands: 136Commands:
117\\{help-mode-map}" 137\\{help-mode-map}"
@@ -121,15 +141,22 @@ Commands:
121 (setq mode-name "Help") 141 (setq mode-name "Help")
122 (setq major-mode 'help-mode) 142 (setq major-mode 'help-mode)
123 (make-local-variable 'font-lock-defaults) 143 (make-local-variable 'font-lock-defaults)
124 (setq font-lock-defaults '(help-font-lock-keywords)) 144 (setq font-lock-defaults nil) ; font-lock would defeat xref
125 (view-mode) 145 (view-mode)
126 (make-local-variable 'view-no-disable-on-exit) 146 (make-local-variable 'view-no-disable-on-exit)
127 (setq view-no-disable-on-exit t) 147 (setq view-no-disable-on-exit t)
148 ;; `help-make-xrefs' would be run here if not invoked from
149 ;; `help-mode-maybe'.
128 (run-hooks 'help-mode-hook)) 150 (run-hooks 'help-mode-hook))
129 151
130(defun help-mode-maybe () 152(defun help-mode-maybe ()
131 (if (eq major-mode 'fundamental-mode) 153 (if (eq major-mode 'fundamental-mode)
132 (help-mode)) 154 (help-mode))
155 (when (eq major-mode 'help-mode)
156 ;; View mode's read-only status of existing *Help* buffer is lost
157 ;; by with-output-to-temp-buffer.
158 (toggle-read-only 1)
159 (help-make-xrefs (current-buffer)))
133 (setq view-return-to-alist 160 (setq view-return-to-alist
134 (list (cons (selected-window) help-return-method)))) 161 (list (cons (selected-window) help-return-method))))
135 162
@@ -320,7 +347,8 @@ If FUNCTION is nil, applies `message' to it, thus printing it."
320 (let ((doc (documentation defn))) 347 (let ((doc (documentation defn)))
321 (if doc 348 (if doc
322 (progn (terpri) 349 (progn (terpri)
323 (princ doc)) 350 (princ doc)
351 (help-setup-xref (cons #'describe-key key) (interactive-p)))
324 (princ "not documented"))) 352 (princ "not documented")))
325 (print-help-return-message))))))) 353 (print-help-return-message)))))))
326 354
@@ -364,6 +392,7 @@ followed by the major mode, which is described on the last page.\n\f\n"))
364 (princ mode-name) 392 (princ mode-name)
365 (princ " mode:\n") 393 (princ " mode:\n")
366 (princ (documentation major-mode)) 394 (princ (documentation major-mode))
395 (help-setup-xref (cons #'help-xref-mode (current-buffer)) (interactive-p))
367 (print-help-return-message))) 396 (print-help-return-message)))
368 397
369;; So keyboard macro definitions are documented correctly 398;; So keyboard macro definitions are documented correctly
@@ -448,6 +477,8 @@ With numeric argument display information on correspondingly older changes."
448 (while (progn (move-to-column 50) (not (eobp))) 477 (while (progn (move-to-column 50) (not (eobp)))
449 (search-forward " " nil t) 478 (search-forward " " nil t)
450 (insert "\n"))) 479 (insert "\n")))
480 (setq help-xref-stack nil
481 help-xref-stack-item nil)
451 (print-help-return-message))) 482 (print-help-return-message)))
452 483
453(defalias 'help 'help-for-help) 484(defalias 'help 'help-for-help)
@@ -616,7 +647,8 @@ C-w Display information on absence of warranty for GNU Emacs."
616 (let ((doc (documentation function))) 647 (let ((doc (documentation function)))
617 (if doc 648 (if doc
618 (progn (terpri) 649 (progn (terpri)
619 (princ doc)) 650 (princ doc)
651 (help-setup-xref (cons #'describe-function function) (interactive-p)))
620 (princ "not documented")))) 652 (princ "not documented"))))
621 (print-help-return-message) 653 (print-help-return-message)
622 (save-excursion 654 (save-excursion
@@ -696,6 +728,7 @@ Returns the documentation as a string, also."
696 (terpri) 728 (terpri)
697 (let ((doc (documentation-property variable 'variable-documentation))) 729 (let ((doc (documentation-property variable 'variable-documentation)))
698 (princ (or doc "not documented as a variable."))) 730 (princ (or doc "not documented as a variable.")))
731 (help-setup-xref (cons #'describe-variable variable) (interactive-p))
699 (print-help-return-message) 732 (print-help-return-message)
700 (save-excursion 733 (save-excursion
701 (set-buffer standard-output) 734 (set-buffer standard-output)
@@ -710,6 +743,8 @@ We put that list in a buffer, and display the buffer.
710The optional argument PREFIX, if non-nil, should be a key sequence; 743The optional argument PREFIX, if non-nil, should be a key sequence;
711then we display only bindings that start with that prefix." 744then we display only bindings that start with that prefix."
712 (interactive "P") 745 (interactive "P")
746 (setq help-xref-stack nil
747 help-xref-stack-item nil)
713 (describe-bindings-internal nil prefix)) 748 (describe-bindings-internal nil prefix))
714 749
715(defun where-is (definition &optional insert) 750(defun where-is (definition &optional insert)
@@ -788,4 +823,255 @@ is used instead of `load-path'."
788 (message "No library %s in search path" library))) 823 (message "No library %s in search path" library)))
789 result)) 824 result))
790 825
826
827;;; Grokking cross-reference information in doc strings and
828;;; hyperlinking it.
829
830;; This may have some scope for extension and the same or something
831;; similar should be done for widget doc strings, which currently use
832;; another mechanism.
833
834(defcustom help-highlight-p t
835 "*If non-nil, `help-make-xrefs' highlight cross-references.
836Under a window system it highlights them with face defined by
837`help-highlight-face'. On a character terminal highlighted
838references look like cross-references in info mode."
839 :group 'help
840 :version "20.3"
841 :type 'boolean)
842
843(defcustom help-highlight-face 'underline
844 "Face used by `help-make-xrefs' to highlight cross-references.
845Must be previously-defined."
846 :group 'help
847 :version "20.3"
848 :type 'symbol)
849
850(defvar help-back-label "[back]"
851 "Label to use by `help-make-xrefs' for the go-back reference.")
852
853(defvar help-xref-symbol-regexp
854 (concat "\\(\\<\\(\\(variable\\|option\\)\\|"
855 "\\(function\\|command\\)\\|"
856 "\\(symbol\\)\\)\\s-+\\)?"
857 ;; Note starting with word-syntax character:
858 "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'")
859 "Regexp matching doc string references to symbols.
860
861The words preceding the quoted symbol can be used in doc strings to
862distinguish references to variables, functions and symbols.")
863
864(defvar help-xref-info-regexp
865 "\\<info\\s-+node\\s-`\\([^']+\\)'"
866 "Regexp matching doc string references to an Info node.")
867
868(defun help-setup-xref (item interactive-p)
869 "Invoked from commands using the \"*Help*\" buffer to install some xref info.
870
871ITEM is a (function . args) pair appropriate for recreating the help
872buffer after following a reference. INTERACTIVE-P is non-nil if the
873calling command was invoked interactively. In this case the stack of
874items for help buffer \"back\" buttons is cleared."
875 (if interactive-p
876 (setq help-xref-stack nil))
877 (setq help-xref-stack-item item))
878
879(defun help-make-xrefs (&optional buffer)
880 "Parse and hyperlink documentation cross-references in the given BUFFER.
881
882Find cross-reference information in a buffer and, if
883`help-highlight-p' is non-nil, highlight it with face defined by
884`help-highlight-face'; activate such cross references for selection
885with `help-follow'. Cross-references have the canonical form `...'
886and the type of reference may be disambiguated by the preceding
887word(s) used in `help-xref-symbol-regexp'.
888
889A special reference `back' is made to return back through a stack of
890help buffers. Variable `help-back-label' specifies the text for
891that."
892 (interactive "b")
893 (save-excursion
894 (set-buffer (or buffer (current-buffer)))
895 (goto-char (point-min))
896 ;; Skip the header-type info, though it might be useful to parse
897 ;; it at some stage (e.g. "function in `library'").
898 (forward-paragraph)
899 (let ((old-modified (buffer-modified-p)))
900 (let ((stab (syntax-table))
901 (case-fold-search t)
902 (inhibit-read-only t))
903 (set-syntax-table emacs-lisp-mode-syntax-table)
904 ;; The following should probably be abstracted out.
905 (unwind-protect
906 (progn
907 ;; Quoted symbols
908 (save-excursion
909 (while (re-search-forward help-xref-symbol-regexp nil t)
910 (let* ((data (match-string 6))
911 (sym (intern-soft data)))
912 (if sym
913 (cond
914 ((match-string 3) ; `variable' &c
915 (and (boundp sym) ; `variable' doesn't ensure
916 ; it's actually bound
917 (help-xref-button 6 #'describe-variable sym)))
918 ((match-string 4) ; `function' &c
919 (and (fboundp sym) ; similarly
920 (help-xref-button 6 #'describe-function sym)))
921 ((match-string 5)) ; nothing for symbol
922 ((and (boundp sym) (fboundp sym))
923 ;; We can't intuit whether to use the
924 ;; variable or function doc -- supply both.
925 (help-xref-button 6 #'help-xref-interned sym))
926 ((boundp sym)
927 (help-xref-button 6 #'describe-variable sym))
928 ((fboundp sym)
929 (help-xref-button 6 #'describe-function sym)))))))
930 ;; Info references
931 (save-excursion
932 (while (re-search-forward help-xref-info-regexp nil t)
933 (help-xref-button 1 #'Info-goto-node (list (match-data 1)))))
934 ;; An obvious case of a key substitution:
935 (save-excursion
936 (while (re-search-forward
937 "\\<M-x\\s-+\\(\\sw\\(\\sw\\|\\s_\\)+\\)" nil t)
938 (let ((sym (intern-soft (match-string 1))))
939 (if (fboundp sym)
940 (help-xref-button 1 #'describe-function sym))))))
941 (set-syntax-table stab))
942 ;; Make a back-reference in this buffer if appropriate.
943 (when help-xref-stack
944 (goto-char (point-max))
945 (save-excursion
946 (insert "\n\n" help-back-label))
947 ;; Just to provide the match data:
948 (looking-at (concat "\n\n\\(" (regexp-quote help-back-label) "\\)"))
949 (help-xref-button 1 #'help-xref-go-back nil)))
950 ;; View mode steals RET from us.
951 (set (make-local-variable 'minor-mode-overriding-map-alist)
952 (list (cons 'view-mode
953 (let ((map (make-sparse-keymap)))
954 (define-key map "\r" 'help-follow)
955 map))))
956 (set-buffer-modified-p old-modified))))
957
958(defun help-xref-button (match-number function data)
959 "Make a hyperlink for cross-reference text previously matched.
960
961MATCH-NUMBER is the subexpression of interest in the last matched
962regexp. FUNCTION is a function to invoke when the button is
963activated, applied to DATA. DATA may be a single value or a list.
964See `help-make-xrefs'."
965 (put-text-property (match-beginning match-number)
966 (match-end match-number)
967 'mouse-face 'highlight)
968 (if help-highlight-p
969 (put-text-property (match-beginning match-number)
970 (match-end match-number)
971 'face help-highlight-face))
972 (put-text-property (match-beginning match-number)
973 (match-end match-number)
974 'help-xref (cons function
975 (if (listp data)
976 data
977 (list data)))))
978
979
980;; Additional functions for (re-)creating types of help buffers.
981(defun help-xref-interned (symbol)
982 "Follow a hyperlink which appeared to be an arbitrary interned SYMBOL.
983
984Both variable and function documentation are extracted into a single
985help buffer."
986 (let ((fdoc (describe-function symbol)))
987 (describe-variable symbol)
988 ;; We now have a help buffer on the variable. Insert the function
989 ;; text after it.
990 (goto-char (point-max))
991 (insert "\n\n" fdoc))
992 (goto-char (point-min))
993 (help-setup-xref (cons #'help-xref-interned symbol) nil))
994
995(defun help-xref-mode (buffer)
996 "Do a `describe-mode' for the specified BUFFER."
997 (save-excursion
998 (set-buffer buffer)
999 (describe-mode)))
1000
1001;;; Navigation/hyperlinking with xrefs
1002
1003(defun help-follow-mouse (click)
1004 "Follow the cross-reference that you click on."
1005 (interactive "e")
1006 (save-excursion
1007 (let* ((start (event-start click))
1008 (window (car start))
1009 (pos (car (cdr start))))
1010 (set-buffer (window-buffer window))
1011 (help-follow pos))))
1012
1013(defun help-xref-go-back ()
1014 "Go back to the previous help buffer using info on `help-xref-stack'."
1015 (interactive)
1016 (when help-xref-stack
1017 (setq help-xref-stack (cdr help-xref-stack)) ; due to help-follow
1018 (let* ((item (car help-xref-stack))
1019 (method (car item))
1020 (args (cdr item)))
1021 (setq help-xref-stack (cdr help-xref-stack))
1022 (if (listp args)
1023 (apply method args)
1024 (funcall method args)))))
1025
1026(defun help-go-back ()
1027 (interactive)
1028 (help-follow (1- (point-max))))
1029
1030(defun help-follow (&optional pos)
1031 "Follow cross-reference at POS, defaulting to point.
1032
1033For the cross-reference format, see `help-make-xrefs'."
1034 (interactive "d")
1035 (let* ((help-data (get-text-property pos 'help-xref))
1036 (method (car help-data))
1037 (args (cdr help-data)))
1038 (setq help-xref-stack (cons help-xref-stack-item help-xref-stack))
1039 (setq help-xref-stack-item nil)
1040 (when help-data
1041 ;; There is a reference at point. Follow it.
1042 (apply method args))))
1043
1044;; For tabbing through buffer.
1045(defun help-next-ref ()
1046 "Find the next help cross-reference in the buffer."
1047 (interactive)
1048 (let (pos)
1049 (while (not pos)
1050 (if (get-text-property (point) 'help-xref) ; move off reference
1051 (or (goto-char (next-single-property-change (point) 'help-xref))
1052 (point)))
1053 (cond ((setq pos (next-single-property-change (point) 'help-xref))
1054 (if pos (goto-char pos)))
1055 ((bobp)
1056 (message "No cross references in the buffer.")
1057 (setq pos t))
1058 (t ; be circular
1059 (goto-char (point-min)))))))
1060
1061(defun help-previous-ref ()
1062 "Find the previous help cross-reference in the buffer."
1063 (interactive)
1064 (let (pos)
1065 (while (not pos)
1066 (if (get-text-property (point) 'help-xref) ; move off reference
1067 (goto-char (or (previous-single-property-change (point) 'help-xref)
1068 (point))))
1069 (cond ((setq pos (previous-single-property-change (point) 'help-xref))
1070 (if pos (goto-char pos)))
1071 ((bobp)
1072 (message "No cross references in the buffer.")
1073 (setq pos t))
1074 (t ; be circular
1075 (goto-char (point-max)))))))
1076
791;;; help.el ends here 1077;;; help.el ends here