changeset 39651:444f50200adc

(help-mode-map): Make button-buffer-map our parent. Don't bind mouse events or tab/backtab. (help-function, help-variable, help-face, help-coding-system) (help-input-method, help-character-set, help-back, help-info) (help-customize-variable, help-function-def, help-variable-def): New button types. (help-button-action): New function. (describe-function-1): Pass help button-types to `help-xref-button' rather than help function and help-echo string. Don't put multiple help-function args in a list to pass them to help-xref-button, just pass them as multiple arguments. Use `help-insert-xref-button' to make [back]-button, rather than `help-xref-button'. (help-xref-button): Take a button-type TYPE as a parameter rather than a function. Remove HELP-ECHO parameter. Remove DATA parameter and add a &rest parameter ARGS to serve the same purpose. Use `make-text-button' to add the button. (help-insert-xref-button): Use `insert-text-button' to add the button. (help-follow-mouse, help-next-ref, help-previous-ref): Functions removed. (help-do-xref): New function. (help-follow): Use `push-button' and `help-do-xref' to do most of the work.
author Miles Bader <miles@gnu.org>
date Sun, 07 Oct 2001 12:05:22 +0000
parents 85be22a1994b
children cd4ae2af5d87
files lisp/help.el
diffstat 1 files changed, 141 insertions(+), 194 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/help.el	Sun Oct 07 11:38:15 2001 +0000
+++ b/lisp/help.el	Sun Oct 07 12:05:22 2001 +0000
@@ -41,6 +41,8 @@
 (defvar help-mode-map (make-sparse-keymap)
   "Keymap for help mode.")
 
+(set-keymap-parent help-mode-map button-buffer-map)
+
 (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)
@@ -97,12 +99,8 @@
 
 (define-key help-map "q" 'help-quit)
 
-(define-key help-mode-map [mouse-2] 'help-follow-mouse)
 (define-key help-mode-map "\C-c\C-b" 'help-go-back)
 (define-key help-mode-map "\C-c\C-c" 'help-follow)
-(define-key help-mode-map "\t" 'help-next-ref)
-(define-key help-mode-map [backtab] 'help-previous-ref)
-(define-key help-mode-map [(shift tab)] 'help-previous-ref)
 ;; Documentation only, since we use minor-mode-overriding-map-alist.
 (define-key help-mode-map "\r" 'help-follow)
 
@@ -127,6 +125,70 @@
   :type 'hook
   :group 'help)
 
+
+;; Button types used by help
+
+;; Make some button types that all use the same naming conventions
+(dolist (help-type '("function" "variable" "face"
+		     "coding-system" "input-method" "character-set"))
+  (define-button-type (intern (purecopy (concat "help-" help-type)))
+    'help-function (intern (concat "describe-" help-type))
+    'help-echo (purecopy (concat "mouse-2, RET: describe this " help-type))
+    'action #'help-button-action))
+
+;; make some more ideosyncratic button types
+
+(define-button-type 'help-symbol
+  'help-function #'help-xref-interned
+  'help-echo (purecopy "mouse-2, RET: describe this symbol")
+  'action #'help-button-action)
+
+(define-button-type 'help-back
+  'help-function #'help-xref-go-back
+  'help-echo (purecopy "mouse-2, RET: go back to previous help buffer")
+  'action #'help-button-action)
+
+(define-button-type 'help-info
+  'help-function #'info
+  'help-echo (purecopy"mouse-2, RET: read this Info node")
+  'action #'help-button-action)
+
+(define-button-type 'help-customize-variable
+  'help-function (lambda (v)
+		   (if help-xref-stack
+		       (pop help-xref-stack))
+		   (customize-variable v))
+  'help-echo (purecopy "mouse-2, RET: customize variable")
+  'action #'help-button-action)
+
+(define-button-type 'help-function-def
+  'help-function (lambda (fun file)
+		   (require 'find-func)
+		  ;; Don't use find-function-noselect because it follows
+		   ;; aliases (which fails for built-in functions).
+		   (let* ((location (find-function-search-for-symbol
+				     fun nil file)))
+		     (pop-to-buffer (car location))
+		     (goto-char (cdr location))))
+  'help-echo (purecopy "mouse-2, RET: find function's definition")
+  'action #'help-button-action)
+
+(define-button-type 'help-variable-def
+  'help-function (lambda (arg)
+		   (let ((location
+			  (find-variable-noselect arg)))
+		     (pop-to-buffer (car location))
+		     (goto-char (cdr location))))
+  'help-echo (purecopy"mouse-2, RET: find variable's definition")
+  'action #'help-button-action)
+
+(defun help-button-action (button)
+  "Call this button's help function."
+  (help-do-xref (button-start button)
+		(button-get button 'help-function)
+		(button-get button 'help-args)))
+
+
 (defun help-mode ()
   "Major mode for viewing help text and navigating references in it.
 Entry to this mode runs the normal hook `help-mode-hook'.
@@ -695,8 +757,7 @@
       (save-excursion
 	(save-match-data
 	  (if (re-search-backward "alias for `\\([^`']+\\)'" nil t)
-	      (help-xref-button 1 #'describe-function def
-				"mouse-2, RET: describe this function")))))
+	      (help-xref-button 1 'help-function def)))))
     (or file-name
 	(setq file-name (symbol-file function)))
     (if file-name
@@ -710,18 +771,7 @@
 	  (with-current-buffer "*Help*"
 	    (save-excursion
 	      (re-search-backward "`\\([^`']+\\)'" nil t)
-	      (help-xref-button
-	       1
-	       #'(lambda (fun file)
-		   (require 'find-func)
-		   ;; Don't use find-function-noselect because it follows
-		   ;; aliases (which fails for built-in functions).
-		   (let* ((location (find-function-search-for-symbol
-				     fun nil file)))
-		     (pop-to-buffer (car location))
-		     (goto-char (cdr location))))
-	       (list function file-name)
-	       "mouse-2, RET: find function's definition")))))
+	      (help-xref-button 1 'help-function-def function file-name)))))
     (if need-close (princ ")"))
     (princ ".")
     (terpri)
@@ -818,13 +868,13 @@
 	       ((looking-at "#<") (search-forward ">" nil 'move))
 	       ((looking-at "\\(\\(\\sw\\|\\s_\\)+\\)")
 		(let* ((sym (intern-soft (match-string 1)))
-		       (fn (cond ((fboundp sym) #'describe-function)
+		       (type (cond ((fboundp sym) 'help-function)
 				 ((or (memq sym '(t nil))
 				      (keywordp sym))
 				  nil)
 				 ((and sym (boundp sym))
-				  #'describe-variable))))
-		  (when fn (help-xref-button 1 fn sym)))
+				  'help-variable))))
+		  (when type (help-xref-button 1 type sym)))
 		(goto-char (match-end 1)))
 	       (t (forward-char 1))))))
       (set-syntax-table ost))))
@@ -928,12 +978,7 @@
 		  (save-excursion
 		    (re-search-backward
 		     (concat "\\(" customize-label "\\)") nil t)
-		    (help-xref-button 1 (lambda (v)
-					  (if help-xref-stack
-					      (pop help-xref-stack))
-					  (customize-variable v))
-				      variable
-				      "mouse-2, RET: customize variable")))))
+		    (help-xref-button 1 'help-customize-variable 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.)
@@ -945,13 +990,7 @@
 	      (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 "mouse-2, RET: find variable's definition")))))
+		  (help-xref-button 1 'help-variable-def variable)))))
 
 	  (print-help-return-message)
 	  (save-excursion
@@ -1158,8 +1197,7 @@
 		    (save-match-data
 		      (unless (string-match "^([^)]+)" data)
 			(setq data (concat "(emacs)" data))))
-		    (help-xref-button 1 #'info data
-				      "mouse-2, RET: read this Info node"))))
+		    (help-xref-button 1 'help-info data))))
 	      ;; Mule related keywords.  Do this before trying
 	      ;; `help-xref-symbol-regexp' because some of Mule
 	      ;; keywords have variable or function definitions.
@@ -1171,31 +1209,19 @@
 			(cond
 			 ((match-string 3) ; coding system
 			  (and sym (coding-system-p sym)
-			       (help-xref-button
-				7 #'describe-coding-system sym
-				"mouse-2, RET: describe this coding system")))
+			       (help-xref-button 6 'help-coding-system sym)))
 			 ((match-string 4) ; input method
 			  (and (assoc data input-method-alist)
-			       (help-xref-button
-				7 #'describe-input-method data
-				"mouse-2, RET: describe this input method")))
+			       (help-xref-button 7 'help-input-method data)))
 			 ((or (match-string 5) (match-string 6)) ; charset
 			  (and sym (charsetp sym)
-			       (help-xref-button
-				7 #'describe-character-set sym
-				"mouse-2, RET: describe this character set")))
+			       (help-xref-button 7 'help-character-set sym)))
 			 ((assoc data input-method-alist)
-			  (help-xref-button
-			   7 #'describe-input-method data
-			   "mouse-2, RET: describe this input method"))
+			  (help-xref-button 7 'help-character-set data))
 			 ((and sym (coding-system-p sym))
-			  (help-xref-button
-			   7 #'describe-coding-system sym
-			   "mouse-2, RET: describe this coding system"))
+			  (help-xref-button 7 'help-coding-system sym))
 			 ((and sym (charsetp sym))
-			  (help-xref-button
-			   7 #'describe-character-set sym
-			   "mouse-2, RET: describe this character set")))))))
+			  (help-xref-button 7 'help-character-set sym)))))))
               ;; Quoted symbols
               (save-excursion
                 (while (re-search-forward help-xref-symbol-regexp nil t)
@@ -1206,46 +1232,32 @@
                          ((match-string 3) ; `variable' &c
                           (and (boundp sym) ; `variable' doesn't ensure
                                         ; it's actually bound
-                               (help-xref-button
-				8 #'describe-variable sym
-				"mouse-2, RET: describe this variable")))
+                               (help-xref-button 8 'help-variable sym)))
                          ((match-string 4) ; `function' &c
                           (and (fboundp sym) ; similarly
-                               (help-xref-button
-				8 #'describe-function sym
-				"mouse-2, RET: describe this function")))
+                               (help-xref-button 8 'help-function sym)))
 			 ((match-string 5) ; `face'
 			  (and (facep sym)
-			       (help-xref-button 8 #'describe-face sym
-				"mouse-2, RET: describe this face")))
+			       (help-xref-button 8 'help-face sym)))
                          ((match-string 6)) ; nothing for `symbol'
 			 ((match-string 7)
-			  (help-xref-button
-			   8
-			   #'(lambda (arg)
-			       (let ((location
-				      (find-function-noselect arg)))
-				 (pop-to-buffer (car location))
-				 (goto-char (cdr location))))
-			   sym
-			   "mouse-2, RET: find function's definition"))
+;; 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 (boundp sym) (fboundp sym))
                           ;; We can't intuit whether to use the
                           ;; variable or function doc -- supply both.
-                          (help-xref-button
-			   8 #'help-xref-interned sym
-			   "mouse-2, RET: describe this symbol"))
+                          (help-xref-button 8 'help-symbol sym))
                          ((boundp sym)
-			  (help-xref-button
-			   8 #'describe-variable sym
-			   "mouse-2, RET: describe this variable"))
+			  (help-xref-button 8 'help-variable sym))
 			 ((fboundp sym)
-			  (help-xref-button
-			   8 #'describe-function sym
-			   "mouse-2, RET: describe this function"))
+			  (help-xref-button 8 'help-function sym))
 			 ((facep sym)
-			  (help-xref-button
-			   8 #'describe-face sym)))))))
+			  (help-xref-button 8 'help-face sym)))))))
               ;; An obvious case of a key substitution:
               (save-excursion
                 (while (re-search-forward
@@ -1254,9 +1266,7 @@
                         "\\<M-x\\s-+\\(\\sw\\(\\sw\\|-\\)+\\)" nil t)
                   (let ((sym (intern-soft (match-string 1))))
                     (if (fboundp sym)
-                        (help-xref-button
-			 1 #'describe-function sym
-			 "mouse-2, RET: describe this command")))))
+                        (help-xref-button 1 'help-function sym)))))
               ;; Look for commands in whole keymap substitutions:
               (save-excursion
 		;; Make sure to find the first keymap.
@@ -1278,9 +1288,7 @@
 					(looking-at "\\(\\sw\\|-\\)+$"))
                                    (let ((sym (intern-soft (match-string 0))))
                                      (if (fboundp sym)
-                                         (help-xref-button
-                                          0 #'describe-function sym
-					  "mouse-2, RET: describe this function"))))
+                                         (help-xref-button 0 'help-function sym))))
 			       (zerop (forward-line)))))))))
           (set-syntax-table stab))
 	;; Delete extraneous newlines at the end of the docstring
@@ -1289,11 +1297,9 @@
 	  (delete-char -1))
         ;; Make a back-reference in this buffer if appropriate.
         (when (and help-xref-following help-xref-stack)
-          (save-excursion
-            (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 (current-buffer))))
+	  (insert "\n\n")
+	  (help-insert-xref-button help-back-label 'help-back
+				   (current-buffer))))
       ;; View mode steals RET from us.
       (set (make-local-variable 'minor-mode-overriding-map-alist)
            (list (cons 'view-mode
@@ -1303,44 +1309,25 @@
                          map))))
       (set-buffer-modified-p old-modified))))
 
-(defun help-xref-button (match-number function data &optional help-echo)
+(defun help-xref-button (match-number type &rest args)
   "Make a hyperlink for cross-reference text previously matched.
-
 MATCH-NUMBER is the subexpression of interest in the last matched
-regexp.  FUNCTION is a function to invoke when the button is
-activated, applied to DATA.  DATA may be a single value or a list.
-See `help-make-xrefs'.
-If optional arg HELP-ECHO is supplied, it is used as a help string."
+regexp.  TYPE is the type of button to use.  Any remaining arguments are
+passed to the button's help-function when it is invoked.
+See `help-make-xrefs'."
   ;; Don't mung properties we've added specially in some instances.
-  (unless (get-text-property (match-beginning match-number) 'help-xref)
-    (add-text-properties (match-beginning match-number)
-			 (match-end match-number)
-			 (list 'mouse-face 'highlight  
-			       'help-xref (cons function
-						(if (listp data)
-						    data
-						  (list data)))))
-    (if help-echo
-	(put-text-property (match-beginning match-number)
-			   (match-end match-number)
-			   'help-echo help-echo))
-    (if help-highlight-p
-	(put-text-property (match-beginning match-number)
-			   (match-end match-number)
-			   'face help-highlight-face))))
+  (unless (button-at (match-beginning match-number))
+    (make-text-button (match-beginning match-number)
+		      (match-end match-number)
+		      'type type 'help-args args)))
 
-(defun help-insert-xref-button (string function data &optional help-echo)
+(defun help-insert-xref-button (string type &rest args)
   "Insert STRING and make a hyperlink from cross-reference text on it.
-
-FUNCTION is a function to invoke when the button is activated, applied
-to DATA.  DATA may be a single value or a list.  See `help-make-xrefs'.
-If optional arg HELP-ECHO is supplied, it is used as a help string."
-  (let ((pos (point)))
-    (insert string)
-    (goto-char pos)
-    (search-forward string)
-    (help-xref-button 0 function data help-echo)))
-
+TYPE is the type of button to use.  Any remaining arguments are passed
+to the button's help-function when it is invoked.
+See `help-make-xrefs'."
+  (unless (button-at (point))
+    (insert-text-button string 'type type 'help-args args)))
 
 
 ;; Additional functions for (re-)creating types of help buffers.
@@ -1373,18 +1360,10 @@
   (save-excursion
     (set-buffer buffer)
     (describe-mode)))
+
 
 ;;; Navigation/hyperlinking with xrefs
 
-(defun help-follow-mouse (click)
-  "Follow the cross-reference that you click on."
-  (interactive "e")
-  (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 (buffer)
   "From BUFFER, go back to previous help buffer text using `help-xref-stack'."
   (let (item position method args)
@@ -1405,7 +1384,22 @@
 (defun help-go-back ()
   "Invoke the [back] button (if any) in the Help mode buffer."
   (interactive)
-  (help-follow (1- (point-max))))
+  (let ((back-button (button-at (1- (point-max)))))
+    (if back-button
+	(button-activate back-button)
+      (error "No [back] button"))))
+
+(defun help-do-xref (pos function args)
+  "Call the help cross-reference function FUNCTION with args ARGS.
+Things are set up properly so that the resulting help-buffer has
+a proper [back] button."
+  (setq help-xref-stack (cons (cons (cons pos (buffer-name))
+				    help-xref-stack-item)
+			      help-xref-stack))
+  (setq help-xref-stack-item nil)
+  ;; There is a reference at point.  Follow it.
+  (let ((help-xref-following t))
+    (apply function args)))
 
 (defun help-follow (&optional pos)
   "Follow cross-reference at POS, defaulting to point.
@@ -1414,64 +1408,17 @@
   (interactive "d")
   (unless pos
     (setq pos (point)))
-  (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))
-	      ;; check if the symbol under point is a function or variable
-	      (let ((sym
-		     (intern
-		      (save-excursion
-			(goto-char pos) (skip-syntax-backward "w_")
-			(buffer-substring (point)
-					  (progn (skip-syntax-forward "w_")
-						 (point)))))))
-		(when (or (boundp sym) (fboundp sym))
-		  (list #'help-xref-interned sym)))))
-         (method (car help-data))
-         (args (cdr help-data)))
-    (when help-data
-      (setq help-xref-stack (cons (cons (cons pos (buffer-name))
-					help-xref-stack-item)
-				  help-xref-stack))
-      (setq help-xref-stack-item nil)
-      ;; There is a reference at point.  Follow it.
-      (let ((help-xref-following t))
-	(apply method args)))))
-
-;; For tabbing through buffer.
-(defun help-next-ref ()
-  "Find the next help cross-reference in the buffer."
-  (interactive)
-  (let (pos)
-    (while (not pos) 
-      (if (get-text-property (point) 'help-xref) ; move off reference
-	   (goto-char (or (next-single-property-change (point) 'help-xref)
-                          (point))))
-      (cond ((setq pos (next-single-property-change (point) 'help-xref))
-	     (if pos (goto-char pos)))
-	    ((bobp)
-	     (message "No cross references in the buffer.")
-	     (setq pos t))
-	    (t				; be circular
-	     (goto-char (point-min)))))))
-
-(defun help-previous-ref ()
-  "Find the previous help cross-reference in the buffer."
-  (interactive)
-  (let (pos)
-    (while (not pos) 
-      (if (get-text-property (point) 'help-xref) ; move off reference
-	  (goto-char (or (previous-single-property-change (point) 'help-xref)
-                         (point))))
-      (cond ((setq pos (previous-single-property-change (point) 'help-xref))
-	     (if pos (goto-char pos)))
-	    ((bobp)
-	     (message "No cross references in the buffer.")
-	     (setq pos t))
-	    (t				; be circular
-	     (goto-char (point-max)))))))
+  (unless (push-button pos)
+    ;; check if the symbol under point is a function or variable
+    (let ((sym
+	   (intern
+	    (save-excursion
+	      (goto-char pos) (skip-syntax-backward "w_")
+	      (buffer-substring (point)
+				(progn (skip-syntax-forward "w_")
+				       (point)))))))
+      (when (or (boundp sym) (fboundp sym))
+	(help-do-xref pos #'help-xref-interned (list sym))))))
 
 
 ;;; Automatic resizing of temporary buffers.