autoloading eval-when forms
[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
ba318903 3;; Copyright (C) 1997, 1999, 2001-2014 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
d6cba7ae 12;; GNU Emacs is free software: you can redistribute it and/or modify
fffee8be 13;; it under the terms of the GNU General Public License as published by
d6cba7ae
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
fffee8be
DL
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
d6cba7ae 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
fffee8be
DL
24
25;;; Commentary:
26;;
27;; The funniest thing about this is that I can't imagine why a package
28;; so obviously useful as this hasn't been written before!!
fffee8be 29;; ;;; find-func
86f28125
RS
30;; (find-function-setup-keys)
31;;
32;; or just:
33;;
2cd6a032 34;; (load "find-func")
fffee8be 35;;
86f28125 36;; if you don't like the given keybindings and away you go! It does
2cd6a032
RS
37;; pretty much what you would expect, putting the cursor at the
38;; definition of the function or variable at point.
fffee8be 39;;
2cd6a032 40;; The code started out from `describe-function', `describe-key'
fffee8be
DL
41;; ("help.el") and `fff-find-loaded-emacs-lisp-function' (Noah Friedman's
42;; "fff.el").
43
e8af40ee 44;;; Code:
fffee8be
DL
45
46;;; User variables:
2cd6a032 47
0b5bb3ec 48(defgroup find-function nil
2cd6a032
RS
49 "Finds the definition of the Emacs Lisp symbol near point."
50;; :prefix "find-function"
0b5bb3ec 51 :group 'lisp)
fffee8be 52
54cabb1b
SM
53(defconst find-function-space-re "\\(?:\\s-\\|\n\\|;.*\n\\)+")
54
2cd6a032 55(defcustom find-function-regexp
d3d4fb62
RS
56 ;; Match things like (defun foo ...), (defmacro foo ...),
57 ;; (define-skeleton foo ...), (define-generic-mode 'foo ...),
d8f479c6 58 ;; (define-derived-mode foo ...), (define-minor-mode foo)
54cabb1b
SM
59 (concat
60 "^\\s-*(\\(def\\(ine-skeleton\\|ine-generic-mode\\|ine-derived-mode\\|\
aa4a1bf8 61ine\\(?:-global\\)?-minor-mode\\|ine-compilation-mode\\|un-cvs-mode\\|\
8f1a5a9b 62foo\\|[^icfgv]\\(\\w\\|\\s_\\)+\\*?\\)\\|easy-mmode-define-[a-z-]+\\|easy-menu-define\\|\
aa4a1bf8 63menu-bar-make-toggle\\)"
fe3947c3 64 find-function-space-re
54cabb1b 65 "\\('\\|\(quote \\)?%s\\(\\s-\\|$\\|\(\\|\)\\)")
d3d4fb62
RS
66 "The regexp used by `find-function' to search for a function definition.
67Note it must contain a `%s' at the place where `format'
2cd6a032 68should insert the function name. The default value avoids `defconst',
b0339ffd 69`defgroup', `defvar', `defface'.
fffee8be 70
2cd6a032
RS
71Please send improvements and fixes to the maintainer."
72 :type 'regexp
86f28125 73 :group 'find-function
d8f479c6 74 :version "21.1")
2cd6a032
RS
75
76(defcustom find-variable-regexp
aa4a1bf8
JL
77 (concat
78 "^\\s-*(\\(def[^fumag]\\(\\w\\|\\s_\\)+\\*?\\|\
79easy-mmode-def\\(map\\|syntax\\)\\|easy-menu-define\\)"
80 find-function-space-re
81 "%s\\(\\s-\\|$\\)")
2cd6a032 82 "The regexp used by `find-variable' to search for a variable definition.
0acffda1
RS
83Note it must contain a `%s' at the place where `format'
84should insert the variable name. The default value
1b60b25a 85avoids `defun', `defmacro', `defalias', `defadvice', `defgroup', `defface'.
2cd6a032
RS
86
87Please send improvements and fixes to the maintainer."
88 :type 'regexp
86f28125 89 :group 'find-function
a469e8ba 90 :version "21.1")
fffee8be 91
0acffda1
RS
92(defcustom find-face-regexp
93 (concat"^\\s-*(defface" find-function-space-re "%s\\(\\s-\\|$\\)")
94 "The regexp used by `find-face' to search for a face definition.
95Note it must contain a `%s' at the place where `format'
96should insert the face name.
97
98Please send improvements and fixes to the maintainer."
99 :type 'regexp
100 :group 'find-function
bf247b6e 101 :version "22.1")
0acffda1
RS
102
103(defvar find-function-regexp-alist
104 '((nil . find-function-regexp)
105 (defvar . find-variable-regexp)
106 (defface . find-face-regexp))
107 "Alist mapping definition types into regexp variables.
108Each regexp variable's value should actually be a format string
109to be used to substitute the desired symbol name into the regexp.")
110(put 'find-function-regexp-alist 'risky-local-variable t)
111
0b5bb3ec 112(defcustom find-function-source-path nil
d3d4fb62 113 "The default list of directories where `find-function' searches.
fffee8be 114
d3d4fb62 115If this variable is nil then `find-function' searches `load-path' by
0b5bb3ec
SE
116default."
117 :type '(repeat directory)
118 :group 'find-function)
fffee8be 119
2cd6a032
RS
120(defcustom find-function-recenter-line 1
121 "The window line-number from which to start displaying a symbol definition.
122A value of nil implies center the beginning of the definition.
cb0fd101
JPW
123See `find-function' and `find-variable'."
124 :type '(choice (const :tag "Center" nil)
125 integer)
86f28125 126 :group 'find-function
a6223467 127 :version "20.3")
2cd6a032
RS
128
129(defcustom find-function-after-hook nil
130 "Hook run after finding symbol definition.
131
132See the functions `find-function' and `find-variable'."
d83b2f14 133 :type 'hook
86f28125 134 :group 'find-function
a6223467 135 :version "20.3")
2cd6a032
RS
136
137;;; Functions:
138
f77a6050
SM
139(defun find-library-suffixes ()
140 (let ((suffixes nil))
f352b9d7 141 (dolist (suffix (get-load-suffixes) (nreverse suffixes))
f77a6050
SM
142 (unless (string-match "elc" suffix) (push suffix suffixes)))))
143
6a2fb145
SM
144(defun find-library--load-name (library)
145 (let ((name library))
146 (dolist (dir load-path)
147 (let ((rel (file-relative-name library dir)))
148 (if (and (not (string-match "\\`\\.\\./" rel))
149 (< (length rel) (length name)))
150 (setq name rel))))
151 (unless (equal name library) name)))
152
f77a6050 153(defun find-library-name (library)
352f6bff
CY
154 "Return the absolute file name of the Emacs Lisp source of LIBRARY.
155LIBRARY should be a string (the name of the library)."
fef1f0f2
RF
156 ;; If the library is byte-compiled, try to find a source library by
157 ;; the same name.
158 (if (string-match "\\.el\\(c\\(\\..*\\)?\\)\\'" library)
1a40d81d 159 (setq library (replace-match "" t t library)))
6a2fb145 160 (or
8aa8da05
DG
161 (locate-file library
162 (or find-function-source-path load-path)
163 (find-library-suffixes))
164 (locate-file library
165 (or find-function-source-path load-path)
166 load-file-rep-suffixes)
6a2fb145
SM
167 (when (file-name-absolute-p library)
168 (let ((rel (find-library--load-name library)))
169 (when rel
170 (or
171 (locate-file rel
172 (or find-function-source-path load-path)
173 (find-library-suffixes))
174 (locate-file rel
175 (or find-function-source-path load-path)
176 load-file-rep-suffixes)))))
8aa8da05 177 (error "Can't find library %s" library)))
f77a6050 178
4479a2f8
SM
179(defvar find-function-C-source-directory
180 (let ((dir (expand-file-name "src" source-directory)))
a0e2175a 181 (if (file-accessible-directory-p dir) dir))
4479a2f8
SM
182 "Directory where the C source files of Emacs can be found.
183If nil, do not try to find the source code of functions and variables
184defined in C.")
185
f5e7fddd
GM
186(declare-function ad-get-advice-info "advice" (function))
187
188(defun find-function-advised-original (func)
189 "Return the original function symbol of an advised function FUNC.
190If FUNC is not the symbol of an advised function, just returns FUNC."
191 (or (and (symbolp func)
192 (featurep 'advice)
193 (let ((ofunc (cdr (assq 'origname (ad-get-advice-info func)))))
194 (and (fboundp ofunc) ofunc)))
195 func))
196
0acffda1 197(defun find-function-C-source (fun-or-var file type)
3bdedbcb 198 "Find the source location where FUN-OR-VAR is defined in FILE.
0acffda1 199TYPE should be nil to find a function, or `defvar' to find a variable."
77694924
SM
200 (let ((dir (or find-function-C-source-directory
201 (read-directory-name "Emacs C source dir: " nil nil t))))
202 (setq file (expand-file-name file dir))
203 (if (file-readable-p file)
204 (if (null find-function-C-source-directory)
205 (setq find-function-C-source-directory dir))
206 (error "The C source file %s is not available"
207 (file-name-nondirectory file))))
0acffda1 208 (unless type
f5e7fddd
GM
209 ;; Either or both an alias and its target might be advised.
210 (setq fun-or-var (find-function-advised-original
211 (indirect-function
212 (find-function-advised-original fun-or-var)))))
4479a2f8
SM
213 (with-current-buffer (find-file-noselect file)
214 (goto-char (point-min))
215 (unless (re-search-forward
0acffda1 216 (if type
4479a2f8
SM
217 (concat "DEFVAR[A-Z_]*[ \t\n]*([ \t\n]*\""
218 (regexp-quote (symbol-name fun-or-var))
219 "\"")
220 (concat "DEFUN[ \t\n]*([ \t\n]*\""
70e5a261 221 (regexp-quote (subr-name (advice--cd*r fun-or-var)))
4479a2f8
SM
222 "\""))
223 nil t)
224 (error "Can't find source for %s" fun-or-var))
225 (cons (current-buffer) (match-beginning 0))))
226
f77a6050
SM
227;;;###autoload
228(defun find-library (library)
352f6bff
CY
229 "Find the Emacs Lisp source of LIBRARY.
230LIBRARY should be a string (the name of the library)."
f77a6050 231 (interactive
e8dab975
SM
232 (let* ((dirs (or find-function-source-path load-path))
233 (suffixes (find-library-suffixes))
7c23d9e8
SM
234 (table (apply-partially 'locate-file-completion-table
235 dirs suffixes))
c896ea95 236 (def (if (eq (function-called-at-point) 'require)
d454552c
MR
237 ;; `function-called-at-point' may return 'require
238 ;; with `point' anywhere on this line. So wrap the
239 ;; `save-excursion' below in a `condition-case' to
240 ;; avoid reporting a scan-error here.
241 (condition-case nil
242 (save-excursion
243 (backward-up-list)
244 (forward-char)
245 (forward-sexp 2)
246 (thing-at-point 'symbol))
247 (error nil))
c896ea95 248 (thing-at-point 'symbol))))
7c23d9e8
SM
249 (when (and def (not (test-completion def table)))
250 (setq def nil))
c896ea95
VJL
251 (list
252 (completing-read (if def (format "Library name (default %s): " def)
253 "Library name: ")
7c23d9e8 254 table nil nil nil nil def))))
f77a6050
SM
255 (let ((buf (find-file-noselect (find-library-name library))))
256 (condition-case nil (switch-to-buffer buf) (error (pop-to-buffer buf)))))
257
a4f43048 258;;;###autoload
0acffda1
RS
259(defun find-function-search-for-symbol (symbol type library)
260 "Search for SYMBOL's definition of type TYPE in LIBRARY.
39ff5f64
RS
261Visit the library in a buffer, and return a cons cell (BUFFER . POSITION),
262or just (BUFFER . nil) if the definition can't be found in the file.
263
0acffda1
RS
264If TYPE is nil, look for a function definition.
265Otherwise, TYPE specifies the kind of definition,
266and it is interpreted via `find-function-regexp-alist'.
267The search is done in the source for library LIBRARY."
2cd6a032
RS
268 (if (null library)
269 (error "Don't know where `%s' is defined" symbol))
2bef95e5
RS
270 ;; Some functions are defined as part of the construct
271 ;; that defines something else.
4479a2f8 272 (while (and (symbolp symbol) (get symbol 'definition-name))
2bef95e5 273 (setq symbol (get symbol 'definition-name)))
14f798ff 274 (if (string-match "\\`src/\\(.*\\.\\(c\\|m\\)\\)\\'" library)
0acffda1 275 (find-function-C-source symbol (match-string 1 library) type)
5c8a04f1
MR
276 (when (string-match "\\.el\\(c\\)\\'" library)
277 (setq library (substring library 0 (match-beginning 1))))
278 ;; Strip extension from .emacs.el to make sure symbol is searched in
279 ;; .emacs too.
280 (when (string-match "\\.emacs\\(.el\\)" library)
281 (setq library (substring library 0 (match-beginning 1))))
0acffda1
RS
282 (let* ((filename (find-library-name library))
283 (regexp-symbol (cdr (assq type find-function-regexp-alist))))
78b6524e 284 (with-current-buffer (find-file-noselect filename)
0acffda1 285 (let ((regexp (format (symbol-value regexp-symbol)
35b6eb23
NR
286 ;; Entry for ` (backquote) macro in loaddefs.el,
287 ;; (defalias (quote \`)..., has a \ but
288 ;; (symbol-name symbol) doesn't. Add an
289 ;; optional \ to catch this.
73584626
NR
290 (concat "\\\\?"
291 (regexp-quote (symbol-name symbol)))))
77186c62 292 (case-fold-search))
fe75e6d0
MR
293 (with-syntax-table emacs-lisp-mode-syntax-table
294 (goto-char (point-min))
295 (if (or (re-search-forward regexp nil t)
a04e10bc
SM
296 ;; `regexp' matches definitions using known forms like
297 ;; `defun', or `defvar'. But some functions/variables
298 ;; are defined using special macros (or functions), so
299 ;; if `regexp' can't find the definition, we look for
300 ;; something of the form "(SOMETHING <symbol> ...)".
301 ;; This fails to distinguish function definitions from
302 ;; variable declarations (or even uses thereof), but is
303 ;; a good pragmatic fallback.
fe75e6d0 304 (re-search-forward
2b690e5b 305 (concat "^([^ ]+" find-function-space-re "['(]?"
fe75e6d0 306 (regexp-quote (symbol-name symbol))
b0339ffd 307 "\\_>")
fe75e6d0
MR
308 nil t))
309 (progn
310 (beginning-of-line)
311 (cons (current-buffer) (point)))
39ff5f64 312 (cons (current-buffer) nil))))))))
2cd6a032 313
8a8a9abe 314;;;###autoload
23a8a5ab 315(defun find-function-noselect (function &optional lisp-only)
d3d4fb62 316 "Return a pair (BUFFER . POINT) pointing to the definition of FUNCTION.
fffee8be 317
3bdedbcb 318Finds the source file containing the definition of FUNCTION
2cd6a032 319in a buffer and the point of the definition. The buffer is
39ff5f64
RS
320not selected. If the function definition can't be found in
321the buffer, returns (BUFFER).
fffee8be 322
23a8a5ab
CY
323If FUNCTION is a built-in function, this function normally
324attempts to find it in the Emacs C sources; however, if LISP-ONLY
325is non-nil, signal an error instead.
326
2cd6a032 327If the file where FUNCTION is defined is not known, then it is
373ed135 328searched for in `find-function-source-path' if non-nil, otherwise
2cd6a032 329in `load-path'."
fffee8be 330 (if (not function)
f5e7fddd
GM
331 (error "You didn't specify a function"))
332 (let ((def (symbol-function (find-function-advised-original function)))
2cd6a032 333 aliases)
f5e7fddd
GM
334 ;; FIXME for completeness, it might be nice to print something like:
335 ;; foo (which is advised), which is an alias for bar (which is advised).
fffee8be
DL
336 (while (symbolp def)
337 (or (eq def function)
338 (if aliases
339 (setq aliases (concat aliases
2cd6a032 340 (format ", which is an alias for `%s'"
fffee8be 341 (symbol-name def))))
f5e7fddd 342 (setq aliases (format "`%s' is an alias for `%s'"
2cd6a032 343 function (symbol-name def)))))
f5e7fddd
GM
344 (setq function (symbol-function (find-function-advised-original function))
345 def (symbol-function (find-function-advised-original function))))
fffee8be 346 (if aliases
55aed120 347 (message "%s" aliases))
2cd6a032 348 (let ((library
7abaf5cc 349 (cond ((autoloadp def) (nth 1 def))
6dfa731f 350 ((subrp def)
23a8a5ab
CY
351 (if lisp-only
352 (error "%s is a built-in function" function))
6dfa731f 353 (help-C-file-name def 'subr))
9f14330b 354 ((symbol-file function 'defun)))))
2cd6a032 355 (find-function-search-for-symbol function nil library))))
fffee8be 356
0acffda1 357(defun find-function-read (&optional type)
2cd6a032 358 "Read and return an interned symbol, defaulting to the one near point.
fffee8be 359
0acffda1
RS
360If TYPE is nil, insist on a symbol with a function definition.
361Otherwise TYPE should be `defvar' or `defface'.
362If TYPE is nil, defaults using `function-called-at-point',
363otherwise uses `variable-at-point'."
341cabd8 364 (let* ((symb1 (cond ((null type) (function-called-at-point))
365 ((eq type 'defvar) (variable-at-point))
366 (t (variable-at-point t))))
367 (symb (unless (eq symb1 0) symb1))
368 (predicate (cdr (assq type '((nil . fboundp)
369 (defvar . boundp)
370 (defface . facep)))))
371 (prompt-type (cdr (assq type '((nil . "function")
372 (defvar . "variable")
373 (defface . "face")))))
374 (prompt (concat "Find " prompt-type
375 (and symb (format " (default %s)" symb))
376 ": "))
377 (enable-recursive-minibuffers t))
378 (list (intern (completing-read
379 prompt obarray predicate
380 t nil nil (and symb (symbol-name symb)))))))
fffee8be 381
0acffda1 382(defun find-function-do-it (symbol type switch-fn)
d3d4fb62 383 "Find Emacs Lisp SYMBOL in a buffer and display it.
0acffda1
RS
384TYPE is nil to search for a function definition,
385or else `defvar' or `defface'.
386
387The variable `find-function-recenter-line' controls how
388to recenter the display. SWITCH-FN is the function to call
389to display and select the buffer.
390See also `find-function-after-hook'.
2cd6a032 391
0acffda1 392Set mark before moving, if the buffer already existed."
86f28125
RS
393 (let* ((orig-point (point))
394 (orig-buf (window-buffer))
2cd6a032 395 (orig-buffers (buffer-list))
86f28125 396 (buffer-point (save-excursion
0acffda1 397 (find-definition-noselect symbol type)))
86f28125
RS
398 (new-buf (car buffer-point))
399 (new-point (cdr buffer-point)))
2cd6a032 400 (when buffer-point
86f28125 401 (when (memq new-buf orig-buffers)
2cd6a032 402 (push-mark orig-point))
86f28125 403 (funcall switch-fn new-buf)
39ff5f64 404 (when new-point (goto-char new-point))
2cd6a032 405 (recenter find-function-recenter-line)
8d8ca3cf 406 (run-hooks 'find-function-after-hook))))
fffee8be 407
b07745ec 408;;;###autoload
2cd6a032 409(defun find-function (function)
c7efc289 410 "Find the definition of the FUNCTION near point.
fffee8be 411
3bdedbcb 412Finds the source file containing the definition of the function
436c08c2 413near point (selected by `function-called-at-point') in a buffer and
0acffda1
RS
414places point before the definition.
415Set mark before moving, if the buffer already existed.
fffee8be 416
2cd6a032 417The library where FUNCTION is defined is searched for in
373ed135 418`find-function-source-path', if non-nil, otherwise in `load-path'.
2cd6a032
RS
419See also `find-function-recenter-line' and `find-function-after-hook'."
420 (interactive (find-function-read))
421 (find-function-do-it function nil 'switch-to-buffer))
fffee8be 422
b07745ec 423;;;###autoload
2cd6a032 424(defun find-function-other-window (function)
c7efc289 425 "Find, in another window, the definition of FUNCTION near point.
fffee8be 426
2cd6a032
RS
427See `find-function' for more details."
428 (interactive (find-function-read))
429 (find-function-do-it function nil 'switch-to-buffer-other-window))
fffee8be 430
b07745ec 431;;;###autoload
2cd6a032 432(defun find-function-other-frame (function)
3bdedbcb 433 "Find, in another frame, the definition of FUNCTION near point.
fffee8be 434
2cd6a032
RS
435See `find-function' for more details."
436 (interactive (find-function-read))
437 (find-function-do-it function nil 'switch-to-buffer-other-frame))
438
e1acbda2 439;;;###autoload
1c787e34 440(defun find-variable-noselect (variable &optional file)
3bdedbcb 441 "Return a pair `(BUFFER . POINT)' pointing to the definition of VARIABLE.
2cd6a032 442
3bdedbcb
EZ
443Finds the library containing the definition of VARIABLE in a buffer and
444the point of the definition. The buffer is not selected.
39ff5f64 445If the variable's definition can't be found in the buffer, return (BUFFER).
2cd6a032 446
1c787e34 447The library where VARIABLE is defined is searched for in FILE or
373ed135 448`find-function-source-path', if non-nil, otherwise in `load-path'."
2cd6a032 449 (if (not variable)
3bdedbcb
EZ
450 (error "You didn't specify a variable")
451 (let ((library (or file
452 (symbol-file variable 'defvar)
453 (help-C-file-name variable 'var))))
454 (find-function-search-for-symbol variable 'defvar library))))
2cd6a032
RS
455
456;;;###autoload
457(defun find-variable (variable)
ebfb5ed9 458 "Find the definition of the VARIABLE at or before point.
2cd6a032 459
3bdedbcb 460Finds the library containing the definition of the variable
2cd6a032 461near point (selected by `variable-at-point') in a buffer and
0acffda1
RS
462places point before the definition.
463
464Set mark before moving, if the buffer already existed.
2cd6a032
RS
465
466The library where VARIABLE is defined is searched for in
373ed135 467`find-function-source-path', if non-nil, otherwise in `load-path'.
2cd6a032 468See also `find-function-recenter-line' and `find-function-after-hook'."
436c08c2
RS
469 (interactive (find-function-read 'defvar))
470 (find-function-do-it variable 'defvar 'switch-to-buffer))
fffee8be 471
2cd6a032
RS
472;;;###autoload
473(defun find-variable-other-window (variable)
c7efc289 474 "Find, in another window, the definition of VARIABLE near point.
2cd6a032
RS
475
476See `find-variable' for more details."
436c08c2
RS
477 (interactive (find-function-read 'defvar))
478 (find-function-do-it variable 'defvar 'switch-to-buffer-other-window))
2cd6a032
RS
479
480;;;###autoload
481(defun find-variable-other-frame (variable)
3bdedbcb 482 "Find, in another frame, the definition of VARIABLE near point.
2cd6a032
RS
483
484See `find-variable' for more details."
436c08c2
RS
485 (interactive (find-function-read 'defvar))
486 (find-function-do-it variable 'defvar 'switch-to-buffer-other-frame))
fffee8be 487
0acffda1
RS
488;;;###autoload
489(defun find-definition-noselect (symbol type &optional file)
490 "Return a pair `(BUFFER . POINT)' pointing to the definition of SYMBOL.
39ff5f64 491If the definition can't be found in the buffer, return (BUFFER).
3bdedbcb 492TYPE says what type of definition: nil for a function, `defvar' for a
c67a6c48 493variable, `defface' for a face. This function does not switch to the
3bdedbcb 494buffer nor display it.
0acffda1
RS
495
496The library where SYMBOL is defined is searched for in FILE or
373ed135 497`find-function-source-path', if non-nil, otherwise in `load-path'."
3bdedbcb
EZ
498 (cond
499 ((not symbol)
500 (error "You didn't specify a symbol"))
501 ((null type)
502 (find-function-noselect symbol))
503 ((eq type 'defvar)
504 (find-variable-noselect symbol file))
505 (t
0acffda1 506 (let ((library (or file (symbol-file symbol type))))
3bdedbcb 507 (find-function-search-for-symbol symbol type library)))))
0acffda1 508
c7ce7fc4
RS
509;; For symmetry, this should be called find-face; but some programs
510;; assume that, if that name is defined, it means something else.
0acffda1 511;;;###autoload
c7ce7fc4 512(defun find-face-definition (face)
0acffda1
RS
513 "Find the definition of FACE. FACE defaults to the name near point.
514
515Finds the Emacs Lisp library containing the definition of the face
516near point (selected by `variable-at-point') in a buffer and
517places point before the definition.
518
519Set mark before moving, if the buffer already existed.
520
521The library where FACE is defined is searched for in
373ed135 522`find-function-source-path', if non-nil, otherwise in `load-path'.
0acffda1
RS
523See also `find-function-recenter-line' and `find-function-after-hook'."
524 (interactive (find-function-read 'defface))
525 (find-function-do-it face 'defface 'switch-to-buffer))
526
b07745ec 527;;;###autoload
fffee8be
DL
528(defun find-function-on-key (key)
529 "Find the function that KEY invokes. KEY is a string.
0acffda1 530Set mark before moving, if the buffer already existed."
fffee8be 531 (interactive "kFind function on key: ")
cb4f3fc8
RS
532 (let (defn)
533 (save-excursion
534 (let* ((event (and (eventp key) (aref key 0))) ; Null event OK below.
535 (start (event-start event))
536 (modifiers (event-modifiers event))
537 (window (and (or (memq 'click modifiers) (memq 'down modifiers)
538 (memq 'drag modifiers))
539 (posn-window start))))
540 ;; For a mouse button event, go to the button it applies to
541 ;; to get the right key bindings. And go to the right place
542 ;; in case the keymap depends on where you clicked.
543 (when (windowp window)
544 (set-buffer (window-buffer window))
545 (goto-char (posn-point start)))
546 (setq defn (key-binding key))))
547 (let ((key-desc (key-description key)))
548 (if (or (null defn) (integerp defn))
549 (message "%s is unbound" key-desc)
550 (if (consp defn)
551 (message "%s runs %s" key-desc (prin1-to-string defn))
552 (find-function-other-window defn))))))
2cd6a032
RS
553
554;;;###autoload
555(defun find-function-at-point ()
556 "Find directly the function at point in the other window."
557 (interactive)
436c08c2 558 (let ((symb (function-called-at-point)))
2cd6a032
RS
559 (when symb
560 (find-function-other-window symb))))
561
562;;;###autoload
563(defun find-variable-at-point ()
3bdedbcb 564 "Find directly the variable at point in the other window."
2cd6a032
RS
565 (interactive)
566 (let ((symb (variable-at-point)))
567 (when (and symb (not (equal symb 0)))
568 (find-variable-other-window symb))))
fffee8be 569
86f28125
RS
570;;;###autoload
571(defun find-function-setup-keys ()
572 "Define some key bindings for the find-function family of functions."
573 (define-key ctl-x-map "F" 'find-function)
574 (define-key ctl-x-4-map "F" 'find-function-other-window)
575 (define-key ctl-x-5-map "F" 'find-function-other-frame)
576 (define-key ctl-x-map "K" 'find-function-on-key)
577 (define-key ctl-x-map "V" 'find-variable)
578 (define-key ctl-x-4-map "V" 'find-variable-other-window)
579 (define-key ctl-x-5-map "V" 'find-variable-other-frame))
580
fffee8be
DL
581(provide 'find-func)
582
583;;; find-func.el ends here