1 ;;; find-func.el --- find the definition of the Emacs Lisp function near point
3 ;; Copyright (C) 1997, 1999, 2001 Free Software Foundation, Inc.
5 ;; Author: Jens Petersen <petersen@kurims.kyoto-u.ac.jp>
6 ;; Maintainer: petersen@kurims.kyoto-u.ac.jp
7 ;; Keywords: emacs-lisp, functions, variables
10 ;; This file is part of GNU Emacs.
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)
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.
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.
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!!
32 ;; (find-function-setup-keys)
38 ;; if you don't like the given keybindings and away you go! It does
39 ;; pretty much what you would expect, putting the cursor at the
40 ;; definition of the function or variable at point.
42 ;; The code started out from `describe-function', `describe-key'
43 ;; ("help.el") and `fff-find-loaded-emacs-lisp-function' (Noah Friedman's
52 (defgroup find-function nil
53 "Finds the definition of the Emacs Lisp symbol near point."
54 ;; :prefix "find-function"
57 (defconst find-function-space-re
"\\(?:\\s-\\|\n\\|;.*\n\\)+")
59 (defcustom find-function-regexp
60 ;; Match things like (defun foo ...), (defmacro foo ...),
61 ;; (define-skeleton foo ...), (define-generic-mode 'foo ...),
62 ;; (define-derived-mode foo ...), (define-minor-mode foo)
64 "^\\s-*(\\(def\\(ine-skeleton\\|ine-generic-mode\\|ine-derived-mode\\|\
65 \[^cgv\W]\\w+\\*?\\)\\|define-minor-mode\
66 \\|easy-mmode-define-global-mode\\)" find-function-space-re
67 "\\('\\|\(quote \\)?%s\\(\\s-\\|$\\|\(\\|\)\\)")
68 "The regexp used by `find-function' to search for a function definition.
69 Note it must contain a `%s' at the place where `format'
70 should insert the function name. The default value avoids `defconst',
73 Please send improvements and fixes to the maintainer."
78 (defcustom find-variable-regexp
79 (concat"^\\s-*(def[^umag]\\(\\w\\|\\s_\\)+\\*?" find-function-space-re
"%s\\(\\s-\\|$\\)")
80 "The regexp used by `find-variable' to search for a variable definition.
81 It should match right up to the variable name. The default value
82 avoids `defun', `defmacro', `defalias', `defadvice', `defgroup'.
84 Please send improvements and fixes to the maintainer."
89 (defcustom find-function-source-path nil
90 "The default list of directories where `find-function' searches.
92 If this variable is nil then `find-function' searches `load-path' by
94 :type
'(repeat directory
)
95 :group
'find-function
)
97 (defcustom find-function-recenter-line
1
98 "The window line-number from which to start displaying a symbol definition.
99 A value of nil implies center the beginning of the definition.
100 See `find-function' and `find-variable'."
101 :type
'(choice (const :tag
"Center" nil
)
103 :group
'find-function
106 (defcustom find-function-after-hook nil
107 "Hook run after finding symbol definition.
109 See the functions `find-function' and `find-variable'."
110 :group
'find-function
115 (defun find-library-suffixes ()
116 (let ((suffixes nil
))
117 (dolist (suffix load-suffixes
(nreverse suffixes
))
118 (unless (string-match "elc" suffix
) (push suffix suffixes
)))))
120 (defun find-library-name (library)
121 "Return the full name of the elisp source of LIBRARY."
122 ;; If the library is byte-compiled, try to find a source library by
124 (if (string-match "\\.el\\(c\\(\\..*\\)?\\)\\'" library
)
125 (setq library
(replace-match "" t t library
)))
126 (or (locate-file library
127 (or find-function-source-path load-path
)
128 (append (find-library-suffixes) '("")))
129 (error "Can't find library %s" library
)))
132 (defun find-library (library)
133 "Find the elisp source of LIBRARY."
136 (completing-read "Library name: "
137 'locate-file-completion
138 (cons (or find-function-source-path load-path
)
139 (find-library-suffixes)))))
140 (let ((buf (find-file-noselect (find-library-name library
))))
141 (condition-case nil
(switch-to-buffer buf
) (error (pop-to-buffer buf
)))))
144 (defun find-function-search-for-symbol (symbol variable-p library
)
146 If VARIABLE-P is nil, `find-function-regexp' is used, otherwise
147 `find-variable-regexp' is used. The search is done in library LIBRARY."
149 (error "Don't know where `%s' is defined" symbol
))
150 ;; Some functions are defined as part of the construct
151 ;; that defines something else.
152 (while (get symbol
'definition-name
)
153 (setq symbol
(get symbol
'definition-name
)))
155 (if (string-match "\\.el\\(c\\)\\'" library
)
156 (setq library
(substring library
0 (match-beginning 1))))
157 (let* ((filename (find-library-name library
)))
158 (with-current-buffer (find-file-noselect filename
)
159 (let ((regexp (format (if variable-p
161 find-function-regexp
)
162 (regexp-quote (symbol-name symbol
))))
164 (with-syntax-table emacs-lisp-mode-syntax-table
165 (goto-char (point-min))
166 (if (or (re-search-forward regexp nil t
)
168 (concat "^([^ ]+" find-function-space-re
"['(]"
169 (regexp-quote (symbol-name symbol
))
174 (cons (current-buffer) (point)))
175 (error "Cannot find definition of `%s' in library `%s'"
176 symbol library
))))))))
179 (defun find-function-noselect (function)
180 "Return a pair (BUFFER . POINT) pointing to the definition of FUNCTION.
182 Finds the Emacs Lisp library containing the definition of FUNCTION
183 in a buffer and the point of the definition. The buffer is
186 If the file where FUNCTION is defined is not known, then it is
187 searched for in `find-function-source-path' if non nil, otherwise
190 (error "You didn't specify a function"))
191 (and (subrp (symbol-function function
))
192 (error "%s is a primitive function" function
))
193 (let ((def (symbol-function function
))
196 (or (eq def function
)
198 (setq aliases
(concat aliases
199 (format ", which is an alias for `%s'"
201 (setq aliases
(format "`%s' an alias for `%s'"
202 function
(symbol-name def
)))))
203 (setq function
(symbol-function function
)
204 def
(symbol-function function
)))
208 (cond ((eq (car-safe def
) 'autoload
)
210 ((symbol-file function
)))))
211 (find-function-search-for-symbol function nil library
))))
213 (defalias 'function-at-point
'function-called-at-point
)
215 (defun find-function-read (&optional variable-p
)
216 "Read and return an interned symbol, defaulting to the one near point.
218 If the optional VARIABLE-P is nil, then a function is gotten
219 defaulting to the value of the function `function-at-point', otherwise
220 a variable is asked for, with the default coming from
221 `variable-at-point'."
222 (let ((symb (funcall (if variable-p
224 'function-at-point
)))
225 (enable-recursive-minibuffers t
)
229 (setq val
(if variable-p
231 (concat "Find variable"
233 (format " (default %s)" symb
))
235 obarray
'boundp t nil
)
237 (concat "Find function"
239 (format " (default %s)" symb
))
241 obarray
'fboundp t nil
)))
242 (list (if (equal val
"")
246 (defun find-function-do-it (symbol variable-p switch-fn
)
247 "Find Emacs Lisp SYMBOL in a buffer and display it.
248 If VARIABLE-P is nil, a function definition is searched for, otherwise
249 a variable definition is searched for. The start of a definition is
250 centered according to the variable `find-function-recenter-line'.
251 See also `find-function-after-hook' It is displayed with function SWITCH-FN.
253 Point is saved in the buffer if it is one of the current buffers."
254 (let* ((orig-point (point))
255 (orig-buf (window-buffer))
256 (orig-buffers (buffer-list))
257 (buffer-point (save-excursion
258 (funcall (if variable-p
259 'find-variable-noselect
260 'find-function-noselect
)
262 (new-buf (car buffer-point
))
263 (new-point (cdr buffer-point
)))
265 (when (memq new-buf orig-buffers
)
266 (push-mark orig-point
))
267 (funcall switch-fn new-buf
)
268 (goto-char new-point
)
269 (recenter find-function-recenter-line
)
270 (run-hooks 'find-function-after-hook
))))
273 (defun find-function (function)
274 "Find the definition of the FUNCTION near point.
276 Finds the Emacs Lisp library containing the definition of the function
277 near point (selected by `function-at-point') in a buffer and
278 places point before the definition. Point is saved in the buffer if
279 it is one of the current buffers.
281 The library where FUNCTION is defined is searched for in
282 `find-function-source-path', if non nil, otherwise in `load-path'.
283 See also `find-function-recenter-line' and `find-function-after-hook'."
284 (interactive (find-function-read))
285 (find-function-do-it function nil
'switch-to-buffer
))
288 (defun find-function-other-window (function)
289 "Find, in another window, the definition of FUNCTION near point.
291 See `find-function' for more details."
292 (interactive (find-function-read))
293 (find-function-do-it function nil
'switch-to-buffer-other-window
))
296 (defun find-function-other-frame (function)
297 "Find, in ananother frame, the definition of FUNCTION near point.
299 See `find-function' for more details."
300 (interactive (find-function-read))
301 (find-function-do-it function nil
'switch-to-buffer-other-frame
))
304 (defun find-variable-noselect (variable &optional file
)
305 "Return a pair `(BUFFER . POINT)' pointing to the definition of SYMBOL.
307 Finds the Emacs Lisp library containing the definition of SYMBOL
308 in a buffer and the point of the definition. The buffer is
311 The library where VARIABLE is defined is searched for in FILE or
312 `find-function-source-path', if non nil, otherwise in `load-path'."
314 (error "You didn't specify a variable"))
315 ;; Fixme: I think `symbol-file' should be fixed instead. -- fx
316 (let ((library (or file
(symbol-file (cons 'defvar variable
)))))
317 (find-function-search-for-symbol variable
'variable library
)))
320 (defun find-variable (variable)
321 "Find the definition of the VARIABLE near point.
323 Finds the Emacs Lisp library containing the definition of the variable
324 near point (selected by `variable-at-point') in a buffer and
325 places point before the definition. Point is saved in the buffer if
326 it is one of the current buffers.
328 The library where VARIABLE is defined is searched for in
329 `find-function-source-path', if non nil, otherwise in `load-path'.
330 See also `find-function-recenter-line' and `find-function-after-hook'."
331 (interactive (find-function-read 'variable
))
332 (find-function-do-it variable t
'switch-to-buffer
))
335 (defun find-variable-other-window (variable)
336 "Find, in another window, the definition of VARIABLE near point.
338 See `find-variable' for more details."
339 (interactive (find-function-read 'variable
))
340 (find-function-do-it variable t
'switch-to-buffer-other-window
))
343 (defun find-variable-other-frame (variable)
344 "Find, in annother frame, the definition of VARIABLE near point.
346 See `find-variable' for more details."
347 (interactive (find-function-read 'variable
))
348 (find-function-do-it variable t
'switch-to-buffer-other-frame
))
351 (defun find-function-on-key (key)
352 "Find the function that KEY invokes. KEY is a string.
353 Point is saved if FUNCTION is in the current buffer."
354 (interactive "kFind function on key: ")
356 (let* ((event (and (eventp key
) (aref key
0))) ; Null event OK below.
357 (start (event-start event
))
358 (modifiers (event-modifiers event
))
359 (window (and (or (memq 'click modifiers
) (memq 'down modifiers
)
360 (memq 'drag modifiers
))
361 (posn-window start
))))
362 ;; For a mouse button event, go to the button it applies to
363 ;; to get the right key bindings. And go to the right place
364 ;; in case the keymap depends on where you clicked.
365 (when (windowp window
)
366 (set-buffer (window-buffer window
))
367 (goto-char (posn-point start
)))
368 (let ((defn (key-binding key
))
369 (key-desc (key-description key
)))
370 (if (or (null defn
) (integerp defn
))
371 (message "%s is unbound" key-desc
)
373 (message "%s runs %s" key-desc
(prin1-to-string defn
))
374 (find-function-other-window defn
)))))))
377 (defun find-function-at-point ()
378 "Find directly the function at point in the other window."
380 (let ((symb (function-at-point)))
382 (find-function-other-window symb
))))
385 (defun find-variable-at-point ()
386 "Find directly the function at point in the other window."
388 (let ((symb (variable-at-point)))
389 (when (and symb
(not (equal symb
0)))
390 (find-variable-other-window symb
))))
393 (defun find-function-setup-keys ()
394 "Define some key bindings for the find-function family of functions."
395 (define-key ctl-x-map
"F" 'find-function
)
396 (define-key ctl-x-4-map
"F" 'find-function-other-window
)
397 (define-key ctl-x-5-map
"F" 'find-function-other-frame
)
398 (define-key ctl-x-map
"K" 'find-function-on-key
)
399 (define-key ctl-x-map
"V" 'find-variable
)
400 (define-key ctl-x-4-map
"V" 'find-variable-other-window
)
401 (define-key ctl-x-5-map
"V" 'find-variable-other-frame
))
405 ;;; find-func.el ends here