Trailing whitepace deleted.
[bpt/emacs.git] / lisp / emacs-lisp / find-func.el
CommitLineData
2cd6a032 1;;; find-func.el --- find the definition of the Emacs Lisp function near point
fffee8be 2
d2922337 3;; Copyright (C) 1997, 1999, 2001 Free Software Foundation, Inc.
fffee8be
DL
4
5;; Author: Jens Petersen <petersen@kurims.kyoto-u.ac.jp>
6;; Maintainer: petersen@kurims.kyoto-u.ac.jp
2cd6a032 7;; Keywords: emacs-lisp, functions, variables
fffee8be
DL
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!!
fffee8be 31;; ;;; find-func
86f28125
RS
32;; (find-function-setup-keys)
33;;
34;; or just:
35;;
2cd6a032 36;; (load "find-func")
fffee8be 37;;
86f28125 38;; if you don't like the given keybindings and away you go! It does
2cd6a032
RS
39;; pretty much what you would expect, putting the cursor at the
40;; definition of the function or variable at point.
fffee8be 41;;
2cd6a032 42;; The code started out from `describe-function', `describe-key'
fffee8be
DL
43;; ("help.el") and `fff-find-loaded-emacs-lisp-function' (Noah Friedman's
44;; "fff.el").
45
e8af40ee 46;;; Code:
fffee8be 47
2cd6a032
RS
48(require 'loadhist)
49
fffee8be 50;;; User variables:
2cd6a032 51
0b5bb3ec 52(defgroup find-function nil
2cd6a032
RS
53 "Finds the definition of the Emacs Lisp symbol near point."
54;; :prefix "find-function"
0b5bb3ec 55 :group 'lisp)
fffee8be 56
54cabb1b
SM
57(defconst find-function-space-re "\\(?:\\s-\\|\n\\|;.*\n\\)+")
58
2cd6a032 59(defcustom find-function-regexp
d3d4fb62
RS
60 ;; Match things like (defun foo ...), (defmacro foo ...),
61 ;; (define-skeleton foo ...), (define-generic-mode 'foo ...),
d8f479c6 62 ;; (define-derived-mode foo ...), (define-minor-mode foo)
54cabb1b
SM
63 (concat
64 "^\\s-*(\\(def\\(ine-skeleton\\|ine-generic-mode\\|ine-derived-mode\\|\
d2922337 65\[^cgv\W]\\w+\\*?\\)\\|define-minor-mode\
54cabb1b
SM
66\\|easy-mmode-define-global-mode\\)" find-function-space-re
67 "\\('\\|\(quote \\)?%s\\(\\s-\\|$\\|\(\\|\)\\)")
d3d4fb62
RS
68 "The regexp used by `find-function' to search for a function definition.
69Note it must contain a `%s' at the place where `format'
2cd6a032
RS
70should insert the function name. The default value avoids `defconst',
71`defgroup', `defvar'.
fffee8be 72
2cd6a032
RS
73Please send improvements and fixes to the maintainer."
74 :type 'regexp
86f28125 75 :group 'find-function
d8f479c6 76 :version "21.1")
2cd6a032
RS
77
78(defcustom find-variable-regexp
54cabb1b 79 (concat"^\\s-*(def[^umag]\\(\\w\\|\\s_\\)+\\*?" find-function-space-re "%s\\(\\s-\\|$\\)")
2cd6a032
RS
80 "The regexp used by `find-variable' to search for a variable definition.
81It should match right up to the variable name. The default value
f35a7618 82avoids `defun', `defmacro', `defalias', `defadvice', `defgroup'.
2cd6a032
RS
83
84Please send improvements and fixes to the maintainer."
85 :type 'regexp
86f28125 86 :group 'find-function
a469e8ba 87 :version "21.1")
fffee8be 88
0b5bb3ec 89(defcustom find-function-source-path nil
d3d4fb62 90 "The default list of directories where `find-function' searches.
fffee8be 91
d3d4fb62 92If this variable is nil then `find-function' searches `load-path' by
0b5bb3ec
SE
93default."
94 :type '(repeat directory)
95 :group 'find-function)
fffee8be 96
2cd6a032
RS
97(defcustom find-function-recenter-line 1
98 "The window line-number from which to start displaying a symbol definition.
99A value of nil implies center the beginning of the definition.
cb0fd101
JPW
100See `find-function' and `find-variable'."
101 :type '(choice (const :tag "Center" nil)
102 integer)
86f28125 103 :group 'find-function
a6223467 104 :version "20.3")
2cd6a032
RS
105
106(defcustom find-function-after-hook nil
107 "Hook run after finding symbol definition.
108
109See the functions `find-function' and `find-variable'."
86f28125 110 :group 'find-function
a6223467 111 :version "20.3")
2cd6a032
RS
112
113;;; Functions:
114
f77a6050
SM
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)))))
119
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
123 ;; the same name.
1a40d81d
SM
124 (if (string-match "\\.el\\(c\\(\\..*\\)?\\)\\'" library)
125 (setq library (replace-match "" t t library)))
f77a6050
SM
126 (or (locate-file library
127 (or find-function-source-path load-path)
43ce8949 128 (append (find-library-suffixes) '("")))
4dbf594b 129 (error "Can't find library %s" library)))
f77a6050
SM
130
131;;;###autoload
132(defun find-library (library)
133 "Find the elisp source of LIBRARY."
134 (interactive
135 (list
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)))))
142
a4f43048 143;;;###autoload
2cd6a032 144(defun find-function-search-for-symbol (symbol variable-p library)
d3d4fb62 145 "Search for SYMBOL.
2cd6a032 146If VARIABLE-P is nil, `find-function-regexp' is used, otherwise
2251e3ed 147`find-variable-regexp' is used. The search is done in library LIBRARY."
2cd6a032
RS
148 (if (null library)
149 (error "Don't know where `%s' is defined" symbol))
2bef95e5
RS
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)))
78b6524e
DL
154 (save-match-data
155 (if (string-match "\\.el\\(c\\)\\'" library)
156 (setq library (substring library 0 (match-beginning 1))))
f77a6050 157 (let* ((filename (find-library-name library)))
78b6524e 158 (with-current-buffer (find-file-noselect filename)
2cd6a032
RS
159 (let ((regexp (format (if variable-p
160 find-variable-regexp
161 find-function-regexp)
162 (regexp-quote (symbol-name symbol))))
77186c62 163 (case-fold-search))
fe75e6d0
MR
164 (with-syntax-table emacs-lisp-mode-syntax-table
165 (goto-char (point-min))
166 (if (or (re-search-forward regexp nil t)
167 (re-search-forward
54cabb1b 168 (concat "^([^ ]+" find-function-space-re "['(]"
fe75e6d0
MR
169 (regexp-quote (symbol-name symbol))
170 "\\>")
171 nil t))
172 (progn
173 (beginning-of-line)
174 (cons (current-buffer) (point)))
175 (error "Cannot find definition of `%s' in library `%s'"
176 symbol library))))))))
2cd6a032 177
8a8a9abe 178;;;###autoload
2cd6a032 179(defun find-function-noselect (function)
d3d4fb62 180 "Return a pair (BUFFER . POINT) pointing to the definition of FUNCTION.
fffee8be
DL
181
182Finds the Emacs Lisp library containing the definition of FUNCTION
2cd6a032 183in a buffer and the point of the definition. The buffer is
fffee8be
DL
184not selected.
185
2cd6a032 186If the file where FUNCTION is defined is not known, then it is
d3d4fb62 187searched for in `find-function-source-path' if non nil, otherwise
2cd6a032 188in `load-path'."
fffee8be
DL
189 (if (not function)
190 (error "You didn't specify a function"))
2cd6a032
RS
191 (and (subrp (symbol-function function))
192 (error "%s is a primitive function" function))
fffee8be 193 (let ((def (symbol-function function))
2cd6a032 194 aliases)
fffee8be
DL
195 (while (symbolp def)
196 (or (eq def function)
197 (if aliases
198 (setq aliases (concat aliases
2cd6a032 199 (format ", which is an alias for `%s'"
fffee8be 200 (symbol-name def))))
2cd6a032
RS
201 (setq aliases (format "`%s' an alias for `%s'"
202 function (symbol-name def)))))
fffee8be
DL
203 (setq function (symbol-function function)
204 def (symbol-function function)))
205 (if aliases
206 (message aliases))
2cd6a032
RS
207 (let ((library
208 (cond ((eq (car-safe def) 'autoload)
209 (nth 1 def))
210 ((symbol-file function)))))
211 (find-function-search-for-symbol function nil library))))
fffee8be 212
a469e8ba 213(defalias 'function-at-point 'function-called-at-point)
fffee8be 214
2cd6a032
RS
215(defun find-function-read (&optional variable-p)
216 "Read and return an interned symbol, defaulting to the one near point.
fffee8be 217
2cd6a032 218If the optional VARIABLE-P is nil, then a function is gotten
d3d4fb62 219defaulting to the value of the function `function-at-point', otherwise
2cd6a032
RS
220a variable is asked for, with the default coming from
221`variable-at-point'."
222 (let ((symb (funcall (if variable-p
223 'variable-at-point
224 'function-at-point)))
fffee8be
DL
225 (enable-recursive-minibuffers t)
226 val)
2cd6a032
RS
227 (if (equal symb 0)
228 (setq symb nil))
229 (setq val (if variable-p
230 (completing-read
231 (concat "Find variable"
232 (if symb
233 (format " (default %s)" symb))
234 ": ")
235 obarray 'boundp t nil)
236 (completing-read
237 (concat "Find function"
238 (if symb
239 (format " (default %s)" symb))
240 ": ")
241 obarray 'fboundp t nil)))
fffee8be 242 (list (if (equal val "")
2cd6a032
RS
243 symb
244 (intern val)))))
fffee8be 245
2cd6a032 246(defun find-function-do-it (symbol variable-p switch-fn)
d3d4fb62
RS
247 "Find Emacs Lisp SYMBOL in a buffer and display it.
248If VARIABLE-P is nil, a function definition is searched for, otherwise
2cd6a032
RS
249a variable definition is searched for. The start of a definition is
250centered according to the variable `find-function-recenter-line'.
d3d4fb62 251See also `find-function-after-hook' It is displayed with function SWITCH-FN.
2cd6a032
RS
252
253Point is saved in the buffer if it is one of the current buffers."
86f28125
RS
254 (let* ((orig-point (point))
255 (orig-buf (window-buffer))
2cd6a032 256 (orig-buffers (buffer-list))
86f28125
RS
257 (buffer-point (save-excursion
258 (funcall (if variable-p
259 'find-variable-noselect
260 'find-function-noselect)
261 symbol)))
262 (new-buf (car buffer-point))
263 (new-point (cdr buffer-point)))
2cd6a032 264 (when buffer-point
86f28125 265 (when (memq new-buf orig-buffers)
2cd6a032 266 (push-mark orig-point))
86f28125
RS
267 (funcall switch-fn new-buf)
268 (goto-char new-point)
2cd6a032 269 (recenter find-function-recenter-line)
8d8ca3cf 270 (run-hooks 'find-function-after-hook))))
fffee8be 271
b07745ec 272;;;###autoload
2cd6a032 273(defun find-function (function)
c7efc289 274 "Find the definition of the FUNCTION near point.
fffee8be
DL
275
276Finds the Emacs Lisp library containing the definition of the function
2cd6a032
RS
277near point (selected by `function-at-point') in a buffer and
278places point before the definition. Point is saved in the buffer if
279it is one of the current buffers.
fffee8be 280
2cd6a032 281The library where FUNCTION is defined is searched for in
d3d4fb62 282`find-function-source-path', if non nil, otherwise in `load-path'.
2cd6a032
RS
283See 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))
fffee8be 286
b07745ec 287;;;###autoload
2cd6a032 288(defun find-function-other-window (function)
c7efc289 289 "Find, in another window, the definition of FUNCTION near point.
fffee8be 290
2cd6a032
RS
291See `find-function' for more details."
292 (interactive (find-function-read))
293 (find-function-do-it function nil 'switch-to-buffer-other-window))
fffee8be 294
b07745ec 295;;;###autoload
2cd6a032 296(defun find-function-other-frame (function)
c7efc289 297 "Find, in ananother frame, the definition of FUNCTION near point.
fffee8be 298
2cd6a032
RS
299See `find-function' for more details."
300 (interactive (find-function-read))
301 (find-function-do-it function nil 'switch-to-buffer-other-frame))
302
e1acbda2 303;;;###autoload
1c787e34
SM
304(defun find-variable-noselect (variable &optional file)
305 "Return a pair `(BUFFER . POINT)' pointing to the definition of SYMBOL.
2cd6a032
RS
306
307Finds the Emacs Lisp library containing the definition of SYMBOL
308in a buffer and the point of the definition. The buffer is
309not selected.
310
1c787e34 311The library where VARIABLE is defined is searched for in FILE or
d3d4fb62 312`find-function-source-path', if non nil, otherwise in `load-path'."
2cd6a032
RS
313 (if (not variable)
314 (error "You didn't specify a variable"))
a1506d29 315 ;; Fixme: I think `symbol-file' should be fixed instead. -- fx
7b1824c2 316 (let ((library (or file (symbol-file (cons 'defvar variable)))))
2cd6a032
RS
317 (find-function-search-for-symbol variable 'variable library)))
318
319;;;###autoload
320(defun find-variable (variable)
c7efc289 321 "Find the definition of the VARIABLE near point.
2cd6a032
RS
322
323Finds the Emacs Lisp library containing the definition of the variable
324near point (selected by `variable-at-point') in a buffer and
325places point before the definition. Point is saved in the buffer if
326it is one of the current buffers.
327
328The library where VARIABLE is defined is searched for in
d3d4fb62 329`find-function-source-path', if non nil, otherwise in `load-path'.
2cd6a032
RS
330See 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))
fffee8be 333
2cd6a032
RS
334;;;###autoload
335(defun find-variable-other-window (variable)
c7efc289 336 "Find, in another window, the definition of VARIABLE near point.
2cd6a032
RS
337
338See `find-variable' for more details."
339 (interactive (find-function-read 'variable))
340 (find-function-do-it variable t 'switch-to-buffer-other-window))
341
342;;;###autoload
343(defun find-variable-other-frame (variable)
c7efc289 344 "Find, in annother frame, the definition of VARIABLE near point.
2cd6a032
RS
345
346See `find-variable' for more details."
347 (interactive (find-function-read 'variable))
348 (find-function-do-it variable t 'switch-to-buffer-other-frame))
fffee8be 349
b07745ec 350;;;###autoload
fffee8be
DL
351(defun find-function-on-key (key)
352 "Find the function that KEY invokes. KEY is a string.
353Point is saved if FUNCTION is in the current buffer."
354 (interactive "kFind function on key: ")
4a8ea8dc 355 (save-excursion
43920c26 356 (let* ((event (and (eventp key) (aref key 0))) ; Null event OK below.
4a8ea8dc
DL
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)
372 (if (consp defn)
373 (message "%s runs %s" key-desc (prin1-to-string defn))
374 (find-function-other-window defn)))))))
2cd6a032
RS
375
376;;;###autoload
377(defun find-function-at-point ()
378 "Find directly the function at point in the other window."
379 (interactive)
380 (let ((symb (function-at-point)))
381 (when symb
382 (find-function-other-window symb))))
383
384;;;###autoload
385(defun find-variable-at-point ()
386 "Find directly the function at point in the other window."
387 (interactive)
388 (let ((symb (variable-at-point)))
389 (when (and symb (not (equal symb 0)))
390 (find-variable-other-window symb))))
fffee8be 391
86f28125
RS
392;;;###autoload
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))
402
fffee8be
DL
403(provide 'find-func)
404
405;;; find-func.el ends here