* lisp/emacs-lisp/bytecomp.el (byte-compile): Fix handling of closures.
[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
acaf905b 3;; Copyright (C) 1997, 1999, 2001-2012 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)))
181 (when (and (file-directory-p dir) (file-readable-p dir))
182 dir))
183 "Directory where the C source files of Emacs can be found.
184If nil, do not try to find the source code of functions and variables
185defined in C.")
186
f5e7fddd
GM
187(declare-function ad-get-advice-info "advice" (function))
188
189(defun find-function-advised-original (func)
190 "Return the original function symbol of an advised function FUNC.
191If FUNC is not the symbol of an advised function, just returns FUNC."
192 (or (and (symbolp func)
193 (featurep 'advice)
194 (let ((ofunc (cdr (assq 'origname (ad-get-advice-info func)))))
195 (and (fboundp ofunc) ofunc)))
196 func))
197
0acffda1 198(defun find-function-C-source (fun-or-var file type)
3bdedbcb 199 "Find the source location where FUN-OR-VAR is defined in FILE.
0acffda1 200TYPE should be nil to find a function, or `defvar' to find a variable."
77694924
SM
201 (let ((dir (or find-function-C-source-directory
202 (read-directory-name "Emacs C source dir: " nil nil t))))
203 (setq file (expand-file-name file dir))
204 (if (file-readable-p file)
205 (if (null find-function-C-source-directory)
206 (setq find-function-C-source-directory dir))
207 (error "The C source file %s is not available"
208 (file-name-nondirectory file))))
0acffda1 209 (unless type
f5e7fddd
GM
210 ;; Either or both an alias and its target might be advised.
211 (setq fun-or-var (find-function-advised-original
212 (indirect-function
213 (find-function-advised-original fun-or-var)))))
4479a2f8
SM
214 (with-current-buffer (find-file-noselect file)
215 (goto-char (point-min))
216 (unless (re-search-forward
0acffda1 217 (if type
4479a2f8
SM
218 (concat "DEFVAR[A-Z_]*[ \t\n]*([ \t\n]*\""
219 (regexp-quote (symbol-name fun-or-var))
220 "\"")
221 (concat "DEFUN[ \t\n]*([ \t\n]*\""
222 (regexp-quote (subr-name fun-or-var))
223 "\""))
224 nil t)
225 (error "Can't find source for %s" fun-or-var))
226 (cons (current-buffer) (match-beginning 0))))
227
f77a6050
SM
228;;;###autoload
229(defun find-library (library)
352f6bff
CY
230 "Find the Emacs Lisp source of LIBRARY.
231LIBRARY should be a string (the name of the library)."
f77a6050 232 (interactive
e8dab975
SM
233 (let* ((dirs (or find-function-source-path load-path))
234 (suffixes (find-library-suffixes))
7c23d9e8
SM
235 (table (apply-partially 'locate-file-completion-table
236 dirs suffixes))
c896ea95 237 (def (if (eq (function-called-at-point) 'require)
d454552c
MR
238 ;; `function-called-at-point' may return 'require
239 ;; with `point' anywhere on this line. So wrap the
240 ;; `save-excursion' below in a `condition-case' to
241 ;; avoid reporting a scan-error here.
242 (condition-case nil
243 (save-excursion
244 (backward-up-list)
245 (forward-char)
246 (forward-sexp 2)
247 (thing-at-point 'symbol))
248 (error nil))
c896ea95 249 (thing-at-point 'symbol))))
7c23d9e8
SM
250 (when (and def (not (test-completion def table)))
251 (setq def nil))
c896ea95
VJL
252 (list
253 (completing-read (if def (format "Library name (default %s): " def)
254 "Library name: ")
7c23d9e8 255 table nil nil nil nil def))))
f77a6050
SM
256 (let ((buf (find-file-noselect (find-library-name library))))
257 (condition-case nil (switch-to-buffer buf) (error (pop-to-buffer buf)))))
258
a4f43048 259;;;###autoload
0acffda1
RS
260(defun find-function-search-for-symbol (symbol type library)
261 "Search for SYMBOL's definition of type TYPE in LIBRARY.
39ff5f64
RS
262Visit the library in a buffer, and return a cons cell (BUFFER . POSITION),
263or just (BUFFER . nil) if the definition can't be found in the file.
264
0acffda1
RS
265If TYPE is nil, look for a function definition.
266Otherwise, TYPE specifies the kind of definition,
267and it is interpreted via `find-function-regexp-alist'.
268The search is done in the source for library LIBRARY."
2cd6a032
RS
269 (if (null library)
270 (error "Don't know where `%s' is defined" symbol))
2bef95e5
RS
271 ;; Some functions are defined as part of the construct
272 ;; that defines something else.
4479a2f8 273 (while (and (symbolp symbol) (get symbol 'definition-name))
2bef95e5 274 (setq symbol (get symbol 'definition-name)))
14f798ff 275 (if (string-match "\\`src/\\(.*\\.\\(c\\|m\\)\\)\\'" library)
0acffda1 276 (find-function-C-source symbol (match-string 1 library) type)
5c8a04f1
MR
277 (when (string-match "\\.el\\(c\\)\\'" library)
278 (setq library (substring library 0 (match-beginning 1))))
279 ;; Strip extension from .emacs.el to make sure symbol is searched in
280 ;; .emacs too.
281 (when (string-match "\\.emacs\\(.el\\)" library)
282 (setq library (substring library 0 (match-beginning 1))))
0acffda1
RS
283 (let* ((filename (find-library-name library))
284 (regexp-symbol (cdr (assq type find-function-regexp-alist))))
78b6524e 285 (with-current-buffer (find-file-noselect filename)
0acffda1 286 (let ((regexp (format (symbol-value regexp-symbol)
35b6eb23
NR
287 ;; Entry for ` (backquote) macro in loaddefs.el,
288 ;; (defalias (quote \`)..., has a \ but
289 ;; (symbol-name symbol) doesn't. Add an
290 ;; optional \ to catch this.
73584626
NR
291 (concat "\\\\?"
292 (regexp-quote (symbol-name symbol)))))
77186c62 293 (case-fold-search))
fe75e6d0
MR
294 (with-syntax-table emacs-lisp-mode-syntax-table
295 (goto-char (point-min))
296 (if (or (re-search-forward regexp nil t)
a04e10bc
SM
297 ;; `regexp' matches definitions using known forms like
298 ;; `defun', or `defvar'. But some functions/variables
299 ;; are defined using special macros (or functions), so
300 ;; if `regexp' can't find the definition, we look for
301 ;; something of the form "(SOMETHING <symbol> ...)".
302 ;; This fails to distinguish function definitions from
303 ;; variable declarations (or even uses thereof), but is
304 ;; a good pragmatic fallback.
fe75e6d0 305 (re-search-forward
2b690e5b 306 (concat "^([^ ]+" find-function-space-re "['(]?"
fe75e6d0 307 (regexp-quote (symbol-name symbol))
b0339ffd 308 "\\_>")
fe75e6d0
MR
309 nil t))
310 (progn
311 (beginning-of-line)
312 (cons (current-buffer) (point)))
39ff5f64 313 (cons (current-buffer) nil))))))))
2cd6a032 314
8a8a9abe 315;;;###autoload
23a8a5ab 316(defun find-function-noselect (function &optional lisp-only)
d3d4fb62 317 "Return a pair (BUFFER . POINT) pointing to the definition of FUNCTION.
fffee8be 318
3bdedbcb 319Finds the source file containing the definition of FUNCTION
2cd6a032 320in a buffer and the point of the definition. The buffer is
39ff5f64
RS
321not selected. If the function definition can't be found in
322the buffer, returns (BUFFER).
fffee8be 323
23a8a5ab
CY
324If FUNCTION is a built-in function, this function normally
325attempts to find it in the Emacs C sources; however, if LISP-ONLY
326is non-nil, signal an error instead.
327
2cd6a032 328If the file where FUNCTION is defined is not known, then it is
373ed135 329searched for in `find-function-source-path' if non-nil, otherwise
2cd6a032 330in `load-path'."
fffee8be 331 (if (not function)
f5e7fddd
GM
332 (error "You didn't specify a function"))
333 (let ((def (symbol-function (find-function-advised-original function)))
2cd6a032 334 aliases)
f5e7fddd
GM
335 ;; FIXME for completeness, it might be nice to print something like:
336 ;; foo (which is advised), which is an alias for bar (which is advised).
fffee8be
DL
337 (while (symbolp def)
338 (or (eq def function)
339 (if aliases
340 (setq aliases (concat aliases
2cd6a032 341 (format ", which is an alias for `%s'"
fffee8be 342 (symbol-name def))))
f5e7fddd 343 (setq aliases (format "`%s' is an alias for `%s'"
2cd6a032 344 function (symbol-name def)))))
f5e7fddd
GM
345 (setq function (symbol-function (find-function-advised-original function))
346 def (symbol-function (find-function-advised-original function))))
fffee8be 347 (if aliases
55aed120 348 (message "%s" aliases))
2cd6a032 349 (let ((library
7abaf5cc 350 (cond ((autoloadp def) (nth 1 def))
6dfa731f 351 ((subrp def)
23a8a5ab
CY
352 (if lisp-only
353 (error "%s is a built-in function" function))
6dfa731f 354 (help-C-file-name def 'subr))
9f14330b 355 ((symbol-file function 'defun)))))
2cd6a032 356 (find-function-search-for-symbol function nil library))))
fffee8be 357
0acffda1 358(defun find-function-read (&optional type)
2cd6a032 359 "Read and return an interned symbol, defaulting to the one near point.
fffee8be 360
0acffda1
RS
361If TYPE is nil, insist on a symbol with a function definition.
362Otherwise TYPE should be `defvar' or `defface'.
363If TYPE is nil, defaults using `function-called-at-point',
364otherwise uses `variable-at-point'."
341cabd8 365 (let* ((symb1 (cond ((null type) (function-called-at-point))
366 ((eq type 'defvar) (variable-at-point))
367 (t (variable-at-point t))))
368 (symb (unless (eq symb1 0) symb1))
369 (predicate (cdr (assq type '((nil . fboundp)
370 (defvar . boundp)
371 (defface . facep)))))
372 (prompt-type (cdr (assq type '((nil . "function")
373 (defvar . "variable")
374 (defface . "face")))))
375 (prompt (concat "Find " prompt-type
376 (and symb (format " (default %s)" symb))
377 ": "))
378 (enable-recursive-minibuffers t))
379 (list (intern (completing-read
380 prompt obarray predicate
381 t nil nil (and symb (symbol-name symb)))))))
fffee8be 382
0acffda1 383(defun find-function-do-it (symbol type switch-fn)
d3d4fb62 384 "Find Emacs Lisp SYMBOL in a buffer and display it.
0acffda1
RS
385TYPE is nil to search for a function definition,
386or else `defvar' or `defface'.
387
388The variable `find-function-recenter-line' controls how
389to recenter the display. SWITCH-FN is the function to call
390to display and select the buffer.
391See also `find-function-after-hook'.
2cd6a032 392
0acffda1 393Set mark before moving, if the buffer already existed."
86f28125
RS
394 (let* ((orig-point (point))
395 (orig-buf (window-buffer))
2cd6a032 396 (orig-buffers (buffer-list))
86f28125 397 (buffer-point (save-excursion
0acffda1 398 (find-definition-noselect symbol type)))
86f28125
RS
399 (new-buf (car buffer-point))
400 (new-point (cdr buffer-point)))
2cd6a032 401 (when buffer-point
86f28125 402 (when (memq new-buf orig-buffers)
2cd6a032 403 (push-mark orig-point))
86f28125 404 (funcall switch-fn new-buf)
39ff5f64 405 (when new-point (goto-char new-point))
2cd6a032 406 (recenter find-function-recenter-line)
8d8ca3cf 407 (run-hooks 'find-function-after-hook))))
fffee8be 408
b07745ec 409;;;###autoload
2cd6a032 410(defun find-function (function)
c7efc289 411 "Find the definition of the FUNCTION near point.
fffee8be 412
3bdedbcb 413Finds the source file containing the definition of the function
436c08c2 414near point (selected by `function-called-at-point') in a buffer and
0acffda1
RS
415places point before the definition.
416Set mark before moving, if the buffer already existed.
fffee8be 417
2cd6a032 418The library where FUNCTION is defined is searched for in
373ed135 419`find-function-source-path', if non-nil, otherwise in `load-path'.
2cd6a032
RS
420See also `find-function-recenter-line' and `find-function-after-hook'."
421 (interactive (find-function-read))
422 (find-function-do-it function nil 'switch-to-buffer))
fffee8be 423
b07745ec 424;;;###autoload
2cd6a032 425(defun find-function-other-window (function)
c7efc289 426 "Find, in another window, the definition of FUNCTION near point.
fffee8be 427
2cd6a032
RS
428See `find-function' for more details."
429 (interactive (find-function-read))
430 (find-function-do-it function nil 'switch-to-buffer-other-window))
fffee8be 431
b07745ec 432;;;###autoload
2cd6a032 433(defun find-function-other-frame (function)
3bdedbcb 434 "Find, in another frame, the definition of FUNCTION near point.
fffee8be 435
2cd6a032
RS
436See `find-function' for more details."
437 (interactive (find-function-read))
438 (find-function-do-it function nil 'switch-to-buffer-other-frame))
439
e1acbda2 440;;;###autoload
1c787e34 441(defun find-variable-noselect (variable &optional file)
3bdedbcb 442 "Return a pair `(BUFFER . POINT)' pointing to the definition of VARIABLE.
2cd6a032 443
3bdedbcb
EZ
444Finds the library containing the definition of VARIABLE in a buffer and
445the point of the definition. The buffer is not selected.
39ff5f64 446If the variable's definition can't be found in the buffer, return (BUFFER).
2cd6a032 447
1c787e34 448The library where VARIABLE is defined is searched for in FILE or
373ed135 449`find-function-source-path', if non-nil, otherwise in `load-path'."
2cd6a032 450 (if (not variable)
3bdedbcb
EZ
451 (error "You didn't specify a variable")
452 (let ((library (or file
453 (symbol-file variable 'defvar)
454 (help-C-file-name variable 'var))))
455 (find-function-search-for-symbol variable 'defvar library))))
2cd6a032
RS
456
457;;;###autoload
458(defun find-variable (variable)
ebfb5ed9 459 "Find the definition of the VARIABLE at or before point.
2cd6a032 460
3bdedbcb 461Finds the library containing the definition of the variable
2cd6a032 462near point (selected by `variable-at-point') in a buffer and
0acffda1
RS
463places point before the definition.
464
465Set mark before moving, if the buffer already existed.
2cd6a032
RS
466
467The library where VARIABLE is defined is searched for in
373ed135 468`find-function-source-path', if non-nil, otherwise in `load-path'.
2cd6a032 469See also `find-function-recenter-line' and `find-function-after-hook'."
436c08c2
RS
470 (interactive (find-function-read 'defvar))
471 (find-function-do-it variable 'defvar 'switch-to-buffer))
fffee8be 472
2cd6a032
RS
473;;;###autoload
474(defun find-variable-other-window (variable)
c7efc289 475 "Find, in another window, the definition of VARIABLE near point.
2cd6a032
RS
476
477See `find-variable' for more details."
436c08c2
RS
478 (interactive (find-function-read 'defvar))
479 (find-function-do-it variable 'defvar 'switch-to-buffer-other-window))
2cd6a032
RS
480
481;;;###autoload
482(defun find-variable-other-frame (variable)
3bdedbcb 483 "Find, in another frame, the definition of VARIABLE near point.
2cd6a032
RS
484
485See `find-variable' for more details."
436c08c2
RS
486 (interactive (find-function-read 'defvar))
487 (find-function-do-it variable 'defvar 'switch-to-buffer-other-frame))
fffee8be 488
0acffda1
RS
489;;;###autoload
490(defun find-definition-noselect (symbol type &optional file)
491 "Return a pair `(BUFFER . POINT)' pointing to the definition of SYMBOL.
39ff5f64 492If the definition can't be found in the buffer, return (BUFFER).
3bdedbcb 493TYPE says what type of definition: nil for a function, `defvar' for a
c67a6c48 494variable, `defface' for a face. This function does not switch to the
3bdedbcb 495buffer nor display it.
0acffda1
RS
496
497The library where SYMBOL is defined is searched for in FILE or
373ed135 498`find-function-source-path', if non-nil, otherwise in `load-path'."
3bdedbcb
EZ
499 (cond
500 ((not symbol)
501 (error "You didn't specify a symbol"))
502 ((null type)
503 (find-function-noselect symbol))
504 ((eq type 'defvar)
505 (find-variable-noselect symbol file))
506 (t
0acffda1 507 (let ((library (or file (symbol-file symbol type))))
3bdedbcb 508 (find-function-search-for-symbol symbol type library)))))
0acffda1 509
c7ce7fc4
RS
510;; For symmetry, this should be called find-face; but some programs
511;; assume that, if that name is defined, it means something else.
0acffda1 512;;;###autoload
c7ce7fc4 513(defun find-face-definition (face)
0acffda1
RS
514 "Find the definition of FACE. FACE defaults to the name near point.
515
516Finds the Emacs Lisp library containing the definition of the face
517near point (selected by `variable-at-point') in a buffer and
518places point before the definition.
519
520Set mark before moving, if the buffer already existed.
521
522The library where FACE is defined is searched for in
373ed135 523`find-function-source-path', if non-nil, otherwise in `load-path'.
0acffda1
RS
524See also `find-function-recenter-line' and `find-function-after-hook'."
525 (interactive (find-function-read 'defface))
526 (find-function-do-it face 'defface 'switch-to-buffer))
527
b07745ec 528;;;###autoload
fffee8be
DL
529(defun find-function-on-key (key)
530 "Find the function that KEY invokes. KEY is a string.
0acffda1 531Set mark before moving, if the buffer already existed."
fffee8be 532 (interactive "kFind function on key: ")
cb4f3fc8
RS
533 (let (defn)
534 (save-excursion
535 (let* ((event (and (eventp key) (aref key 0))) ; Null event OK below.
536 (start (event-start event))
537 (modifiers (event-modifiers event))
538 (window (and (or (memq 'click modifiers) (memq 'down modifiers)
539 (memq 'drag modifiers))
540 (posn-window start))))
541 ;; For a mouse button event, go to the button it applies to
542 ;; to get the right key bindings. And go to the right place
543 ;; in case the keymap depends on where you clicked.
544 (when (windowp window)
545 (set-buffer (window-buffer window))
546 (goto-char (posn-point start)))
547 (setq defn (key-binding key))))
548 (let ((key-desc (key-description key)))
549 (if (or (null defn) (integerp defn))
550 (message "%s is unbound" key-desc)
551 (if (consp defn)
552 (message "%s runs %s" key-desc (prin1-to-string defn))
553 (find-function-other-window defn))))))
2cd6a032
RS
554
555;;;###autoload
556(defun find-function-at-point ()
557 "Find directly the function at point in the other window."
558 (interactive)
436c08c2 559 (let ((symb (function-called-at-point)))
2cd6a032
RS
560 (when symb
561 (find-function-other-window symb))))
562
563;;;###autoload
564(defun find-variable-at-point ()
3bdedbcb 565 "Find directly the variable at point in the other window."
2cd6a032
RS
566 (interactive)
567 (let ((symb (variable-at-point)))
568 (when (and symb (not (equal symb 0)))
569 (find-variable-other-window symb))))
fffee8be 570
86f28125
RS
571;;;###autoload
572(defun find-function-setup-keys ()
573 "Define some key bindings for the find-function family of functions."
574 (define-key ctl-x-map "F" 'find-function)
575 (define-key ctl-x-4-map "F" 'find-function-other-window)
576 (define-key ctl-x-5-map "F" 'find-function-other-frame)
577 (define-key ctl-x-map "K" 'find-function-on-key)
578 (define-key ctl-x-map "V" 'find-variable)
579 (define-key ctl-x-4-map "V" 'find-variable-other-window)
580 (define-key ctl-x-5-map "V" 'find-variable-other-frame))
581
fffee8be
DL
582(provide 'find-func)
583
584;;; find-func.el ends here