diff lisp/prim/help.el @ 179:9ad43877534d r20-3b16

Import from CVS: tag r20-3b16
author cvs
date Mon, 13 Aug 2007 09:52:19 +0200
parents 6075d714658b
children e121b013d1f0
line wrap: on
line diff
--- a/lisp/prim/help.el	Mon Aug 13 09:51:18 2007 +0200
+++ b/lisp/prim/help.el	Mon Aug 13 09:52:19 2007 +0200
@@ -1292,3 +1292,161 @@
                     (setq cmd (cdr cmd))
                     (if cmd (princ " " stream)))))
             (terpri stream)))))))
+
+(defvar find-function-function 'ff-function-at-point
+  "The function used by `find-function' to select the function near
+point.
+
+For example `ff-function-at-point' or `function-called-at-point'.")
+
+(defvar find-function-source-path nil
+  "The default list of directories where find-function searches.
+
+If this variable is `nil' then find-function searches `load-path' by
+default.")
+
+;;; Code:
+
+(defun find-function-noselect (function &optional path)
+  "Put point at the definition of the function at point and return the buffer.
+
+Finds the emacs-lisp package containing the definition of FUNCTION
+into a buffer and place point before the definition.  The buffer is
+not selected.
+
+If the optional argument PATH is given, the package where FUNCTION is
+defined is searched in PATH instead of `load-path' (see
+`find-function-source-path')."
+  (and (subrp (symbol-function function))
+       (error "%s is a primitive function" function))
+  (if (not function)
+      (error "You didn't specify a function"))
+  (let ((def (symbol-function function))
+	package aliases)
+    (while (symbolp def)
+      (or (eq def function)
+	  (if aliases
+	      (setq aliases (concat aliases 
+				    (format ", which is an alias for %s"
+					    (symbol-name def))))
+	    (setq aliases (format "an alias for %s" (symbol-name
+						       def)))))
+      (setq function (symbol-function function)
+	    def (symbol-function function)))
+    (if aliases
+	(message aliases))
+    (setq package
+	  (cond ((eq (car-safe def) 'autoload)
+		 (nth 1 def))
+		((describe-function-find-file function))
+		((and (compiled-function-p def)
+		      (fboundp 'compiled-function-annotation))
+		 (substring (compiled-function-annotation def) 0 -4))))
+    (if (null package)
+	(error "Can't find package"))
+    (if (string-match "\\(\\.elc?\\'\\)" package)
+	(setq package (substring package 0 (match-beginning 1))))
+    (setq package (concat package ".el"))
+    (let ((filename (locate-library package t
+				    (if path
+					path
+				      find-function-source-path)))
+	  (calling-buffer (current-buffer)))
+      (if (not filename)
+	  (error "The package \"%s\" is not in the path." package))
+      (set-buffer (find-file-noselect filename))
+      (save-match-data
+	(let ((p (point))
+	      ;; avoid defconst, defgroup, defvar (any others?)
+	      (re (format "^(def[^cgv\W]\\w+\\s-+%s\\s-" function))
+	      (syntable (syntax-table)))
+	  (set-syntax-table emacs-lisp-mode-syntax-table)
+	  (goto-char (point-min))
+	  (if (prog1
+		  (re-search-forward re nil t)
+		(set-syntax-table syntable))
+	      (prog2
+		  (beginning-of-line)
+		  (current-buffer)
+		(set-buffer calling-buffer))
+	    (goto-char p)
+	    (set-buffer calling-buffer)
+	    (error "Cannot find definition of %s" function)))))))
+
+(defun ff-function-at-point ()
+  (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 (char-after (point))) ?w)
+		  (eq (char-syntax (char-after (point))) ?_)
+		  (forward-sexp -1))
+	      (skip-chars-forward "'")
+	      (let ((obj (read (current-buffer))))
+		(and (symbolp obj) (fboundp obj) obj)))
+	  (set-syntax-table stab)))
+    (error nil)))
+
+(defun ff-read-function ()
+  "Read and return a function, defaulting to the one near point.
+
+The function named by `find-function-function' is used to select the
+default function."
+  (let ((fn (funcall find-function-function))
+	(enable-recursive-minibuffers t)	     
+	val)
+    (setq val (completing-read
+	       (if fn
+		   (format "Find function (default %s): " fn)
+		 "Find function: ")
+	       obarray 'fboundp t))
+    (list (if (equal val "")
+	      fn (intern val)))))
+
+
+(defun find-function (function &optional path)
+  "Find the definition of the function near point in the current window.
+
+Finds the emacs-lisp package containing the definition of the function
+near point (selected by `find-function-function') and places point
+before the definition.
+
+If the optional argument PATH is given, the package where FUNCTION is
+defined is searched in PATH instead of `load-path'"
+  (interactive (ff-read-function))
+  (switch-to-buffer
+   (find-function-noselect function path)))
+
+(defun find-function-other-window (function &optional path)
+  "Find the definition of the function near point in the other window.
+
+Finds the emacs-lisp package containing the definition of the function
+near point (selected by `find-function-function') and places point
+before the definition.
+
+If the optional argument PATH is given, the package where FUNCTION is
+defined is searched in PATH instead of `load-path'"
+  (interactive (ff-read-function))
+  (switch-to-buffer-other-window
+   (find-function-noselect function path)))
+
+(defun find-function-other-frame (function &optional path)
+  "Find the definition of the function near point in the another frame.
+
+Finds the emacs-lisp package containing the definition of the function
+near point (selected by `find-function-function') and places point
+before the definition.
+
+If the optional argument PATH is given, the package where FUNCTION is
+defined is searched in PATH instead of `load-path'"
+  (interactive (ff-read-function))
+  (switch-to-buffer-other-frame
+   (find-function-noselect function path)))
+
+(define-key mode-specific-map "f" 'find-function)
+(define-key ctl-x-4-map "F" 'find-function-other-window)
+(define-key ctl-x-5-map "F" 'find-function-other-frame)
+
+;;; help.el ends here