comparison lisp/emacs-lisp/find-func.el @ 20183:add8b7b3a7da

Initial revision
author Dave Love <fx@gnu.org>
date Sat, 25 Oct 1997 13:18:56 +0000
parents
children c8d4024e07de
comparison
equal deleted inserted replaced
20182:9f3dd970927e 20183:add8b7b3a7da
1 ;;; find-func.el --- find the definition of the elisp function near point
2
3 ;; Copyright (C) 1997 Free Software Foundation, Inc.
4
5 ;; Author: Jens Petersen <petersen@kurims.kyoto-u.ac.jp>
6 ;; Maintainer: petersen@kurims.kyoto-u.ac.jp
7 ;; Keywords: emacs-lisp, help, functions
8 ;; Created: 97/07/25
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
26
27 ;;; Commentary:
28 ;;
29 ;; The funniest thing about this is that I can't imagine why a package
30 ;; so obviously useful as this hasn't been written before!!
31 ;; This probably belongs in "help.el" or somewhere like that.
32 ;;
33 ;; Put this file in your `load-path', byte-compile it and add the
34 ;; following code in your init file:
35 ;;
36 ;; ;;; find-func
37 ;; (load "find-function")
38 ;; (global-set-key [(control ?c) ?f] 'find-function)
39 ;; (global-set-key [(control ?c) ?4 ?f] 'find-function-other-window)
40 ;; (global-set-key [(control ?c) ?5 ?f] 'find-function-other-frame)
41 ;; (global-set-key [(control ?c) ?k] 'find-function-on-key)
42 ;;
43 ;; and away you go! It does pretty much what you would expect,
44 ;; putting the cursor at the definition of the function at point.
45 ;;
46 ;; The code is adapted from `describe-function', `describe-key'
47 ;; ("help.el") and `fff-find-loaded-emacs-lisp-function' (Noah Friedman's
48 ;; "fff.el").
49
50 ;;; To do:
51 ;;
52 ;; o custom?
53 ;;
54 ;; o improve handling of advice'd functions? (at the moment it goes to
55 ;; the advice, not the actual definition)
56
57 ;;;; Code:
58
59 ;;; User variables:
60
61 (defvar find-function-function 'function-at-point
62 "*The function used by `find-function' to select the function near
63 point.
64
65 For example `function-at-point' or `function-called-at-point'.")
66
67 (defvar find-function-source-path nil
68 "The default list of directories where find-function searches.
69
70 If this variable is `nil' then find-function searches `load-path' by
71 default.")
72
73
74 ;;; Functions:
75
76 (defun find-function-noselect (function &optional path)
77 "Returns list `(buffer point)' pointing to the definition of FUNCTION.
78
79 Finds the Emacs Lisp library containing the definition of FUNCTION
80 in a buffer and places point before the definition. The buffer is
81 not selected.
82
83 If the optional argument PATH is given, the library where FUNCTION is
84 defined is searched in PATH instead of `load-path' (see
85 `find-function-source-path')."
86 (and (subrp (symbol-function function))
87 (error "%s is a primitive function" function))
88 (if (not function)
89 (error "You didn't specify a function"))
90 (let ((def (symbol-function function))
91 library aliases)
92 (while (symbolp def)
93 (or (eq def function)
94 (if aliases
95 (setq aliases (concat aliases
96 (format ", which is an alias for %s"
97 (symbol-name def))))
98 (setq aliases (format "an alias for %s" (symbol-name
99 def)))))
100 (setq function (symbol-function function)
101 def (symbol-function function)))
102 (if aliases
103 (message aliases))
104 (setq library
105 (cond ((eq (car-safe def) 'autoload)
106 (nth 1 def))
107 ((describe-function-find-file function))))
108 (if (null library)
109 (error (format "`%s' is not in `load-history'" function)))
110 (if (string-match "\\(\\.elc?\\'\\)" library)
111 (setq library (substring library 0 (match-beginning 1))))
112 (let* ((path (or path find-function-source-path))
113 (compression (or (rassq 'jka-compr-handler file-name-handler-alist)
114 (member 'crypt-find-file-hook find-file-hooks)))
115 (filename (or (locate-library (concat library ".el")
116 t path)
117 (locate-library library t path)
118 (if compression
119 (or (locate-library (concat library ".el.gz")
120 t path)
121 (locate-library (concat library ".gz")
122 t path))))))
123 (if (not filename)
124 (error "The library \"%s\" is not in the path." library))
125 (save-excursion
126 (set-buffer (find-file-noselect filename))
127 (save-match-data
128 (let (;; avoid defconst, defgroup, defvar (any others?)
129 (regexp (format "^\\s-*(def[^cgv\W]\\w+\\s-+%s\\s-" function))
130 (syntable (syntax-table)))
131 (set-syntax-table emacs-lisp-mode-syntax-table)
132 (goto-char (point-min))
133 (if (prog1
134 (re-search-forward regexp nil t)
135 (set-syntax-table syntable))
136 (progn
137 (beginning-of-line)
138 (list (current-buffer) (point)))
139 (error "Cannot find definition of %s" function))))))))
140
141 (defun function-at-point ()
142 (or (condition-case ()
143 (let ((stab (syntax-table)))
144 (unwind-protect
145 (save-excursion
146 (set-syntax-table emacs-lisp-mode-syntax-table)
147 (or (not (zerop (skip-syntax-backward "_w")))
148 (eq (char-syntax (char-after (point))) ?w)
149 (eq (char-syntax (char-after (point))) ?_)
150 (forward-sexp -1))
151 (skip-chars-forward "`'")
152 (let ((obj (read (current-buffer))))
153 (and (symbolp obj) (fboundp obj) obj)))
154 (set-syntax-table stab)))
155 (error nil))
156 (condition-case ()
157 (save-excursion
158 (save-restriction
159 (narrow-to-region (max (point-min) (- (point) 1000)) (point-max))
160 (backward-up-list 1)
161 (forward-char 1)
162 (let (obj)
163 (setq obj (read (current-buffer)))
164 (and (symbolp obj) (fboundp obj) obj))))
165 (error nil))))
166
167 (defun find-function-read-function ()
168 "Read and return a function, defaulting to the one near point.
169
170 The function named by `find-function-function' is used to select the
171 default function."
172 (let ((fn (funcall find-function-function))
173 (enable-recursive-minibuffers t)
174 val)
175 (setq val (completing-read
176 (if fn
177 (format "Find function (default %s): " fn)
178 "Find function: ")
179 obarray 'fboundp t))
180 (list (if (equal val "")
181 fn (intern val)))))
182
183 (defun find-function-do-it (function path switch-fn)
184 "find elisp FUNCTION in PATH and display it with SWITCH-FN.
185 Point is saved if FUNCTION is in the current buffer."
186 (let ((orig-point (point))
187 (buffer-point (find-function-noselect function path)))
188 (if buffer-point
189 (progn
190 (if (eq (current-buffer) (car buffer-point))
191 (push-mark orig-point))
192 (funcall switch-fn (car buffer-point))
193 (goto-char (elt buffer-point 1))
194 (recenter 0)))))
195
196 (defun find-function (function &optional path)
197 "Find the definition of the function near point in the current window.
198
199 Finds the Emacs Lisp library containing the definition of the function
200 near point (selected by `find-function-function') and places point
201 before the definition. Point is saved if FUNCTION is in the current
202 buffer.
203
204 If the optional argument PATH is given, the library where FUNCTION is
205 defined is searched in PATH instead of `load-path'"
206 (interactive (find-function-read-function))
207 (find-function-do-it function path 'switch-to-buffer))
208
209 (defun find-function-other-window (function &optional path)
210 "Find the definition of the function near point in the other window.
211
212 Finds the Emacs Lisp package containing the definition of the function
213 near point (selected by `find-function-function') and places point
214 before the definition. Point is saved if FUNCTION is in the current
215 buffer.
216
217 If the optional argument PATH is given, the package where FUNCTION is
218 defined is searched in PATH instead of `load-path'"
219 (interactive (find-function-read-function))
220 (find-function-do-it function path 'switch-to-buffer-other-window))
221
222 (defun find-function-other-frame (function &optional path)
223 "Find the definition of the function near point in the another frame.
224
225 Finds the Emacs Lisp package containing the definition of the function
226 near point (selected by `find-function-function') and places point
227 before the definition. Point is saved if FUNCTION is in the current
228 buffer.
229
230 If the optional argument PATH is given, the package where FUNCTION is
231 defined is searched in PATH instead of `load-path'"
232 (interactive (find-function-read-function))
233 (find-function-do-it function path 'switch-to-buffer-other-frame))
234
235 (defun find-function-on-key (key)
236 "Find the function that KEY invokes. KEY is a string.
237 Point is saved if FUNCTION is in the current buffer."
238 (interactive "kFind function on key: ")
239 (let ((defn (key-binding key)))
240 (if (or (null defn) (integerp defn))
241 (message "%s is undefined" (key-description key))
242 (if (and (consp defn) (not (eq 'lambda (car-safe defn))))
243 (message "runs %s" (prin1-to-string defn))
244 (find-function-other-window defn)))))
245
246 (provide 'find-func)
247
248 ;;; find-func.el ends here
249