Line data Source code
1 : ;;; find-func.el --- find the definition of the Emacs Lisp function near point -*- lexical-binding:t -*-
2 :
3 : ;; Copyright (C) 1997, 1999, 2001-2017 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, functions, variables
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 3 of the License, or
15 : ;; (at your option) 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. If not, see <http://www.gnu.org/licenses/>.
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!!
29 : ;; ;;; find-func
30 : ;; (find-function-setup-keys)
31 : ;;
32 : ;; or just:
33 : ;;
34 : ;; (load "find-func")
35 : ;;
36 : ;; if you don't like the given keybindings and away you go! It does
37 : ;; pretty much what you would expect, putting the cursor at the
38 : ;; definition of the function or variable at point.
39 : ;;
40 : ;; The code started out from `describe-function', `describe-key'
41 : ;; ("help.el") and `fff-find-loaded-emacs-lisp-function' (Noah Friedman's
42 : ;; "fff.el").
43 :
44 : ;;; Code:
45 :
46 : (eval-when-compile (require 'cl-lib))
47 :
48 : ;;; User variables:
49 :
50 : (defgroup find-function nil
51 : "Finds the definition of the Emacs Lisp symbol near point."
52 : ;; :prefix "find-function"
53 : :group 'lisp)
54 :
55 : (defconst find-function-space-re "\\(?:\\s-\\|\n\\|;.*\n\\)+")
56 :
57 : (defcustom find-function-regexp
58 : ;; Match things like (defun foo ...), (defmacro foo ...),
59 : ;; (define-skeleton foo ...), (define-generic-mode 'foo ...),
60 : ;; (define-derived-mode foo ...), (define-minor-mode foo)
61 : (concat
62 : "^\\s-*(\\(def\\(ine-skeleton\\|ine-generic-mode\\|ine-derived-mode\\|\
63 : ine\\(?:-global\\)?-minor-mode\\|ine-compilation-mode\\|un-cvs-mode\\|\
64 : foo\\|\\(?:[^icfgv]\\|g[^r]\\)\\(\\w\\|\\s_\\)+\\*?\\)\\|easy-mmode-define-[a-z-]+\\|easy-menu-define\\|\
65 : menu-bar-make-toggle\\)"
66 : 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',
71 : `defgroup', `defvar', `defface'.
72 :
73 : Please send improvements and fixes to the maintainer."
74 : :type 'regexp
75 : :group 'find-function
76 : :version "21.1")
77 :
78 : (defcustom find-variable-regexp
79 : (concat
80 : "^\\s-*(\\(def[^fumag]\\(\\w\\|\\s_\\)+\\*?\\|\
81 : easy-mmode-def\\(map\\|syntax\\)\\|easy-menu-define\\)"
82 : find-function-space-re
83 : "%s\\(\\s-\\|$\\)")
84 : "The regexp used by `find-variable' to search for a variable definition.
85 : Note it must contain a `%s' at the place where `format'
86 : should insert the variable name. The default value
87 : avoids `defun', `defmacro', `defalias', `defadvice', `defgroup', `defface'.
88 :
89 : Please send improvements and fixes to the maintainer."
90 : :type 'regexp
91 : :group 'find-function
92 : :version "21.1")
93 :
94 : (defcustom find-face-regexp
95 : (concat"^\\s-*(defface" find-function-space-re "%s\\(\\s-\\|$\\)")
96 : "The regexp used by `find-face' to search for a face definition.
97 : Note it must contain a `%s' at the place where `format'
98 : should insert the face name.
99 :
100 : Please send improvements and fixes to the maintainer."
101 : :type 'regexp
102 : :group 'find-function
103 : :version "22.1")
104 :
105 : (defcustom find-feature-regexp
106 : (concat ";;; Code:")
107 : "The regexp used by `xref-find-definitions' when searching for a feature definition.
108 : Note it may contain up to one `%s' at the place where `format'
109 : should insert the feature name."
110 : ;; We search for ";;; Code" rather than (feature '%s) because the
111 : ;; former is near the start of the code, and the latter is very
112 : ;; uninteresting. If the regexp is not found, just goes to
113 : ;; (point-min), which is acceptable in this case.
114 : :type 'regexp
115 : :group 'xref
116 : :version "25.1")
117 :
118 : (defcustom find-alias-regexp
119 : "(defalias +'%s"
120 : "The regexp used by `xref-find-definitions' to search for an alias definition.
121 : Note it must contain a `%s' at the place where `format'
122 : should insert the feature name."
123 : :type 'regexp
124 : :group 'xref
125 : :version "25.1")
126 :
127 : (defvar find-function-regexp-alist
128 : '((nil . find-function-regexp)
129 : (defvar . find-variable-regexp)
130 : (defface . find-face-regexp)
131 : (feature . find-feature-regexp)
132 : (defalias . find-alias-regexp))
133 : "Alist mapping definition types into regexp variables.
134 : Each regexp variable's value should actually be a format string
135 : to be used to substitute the desired symbol name into the regexp.
136 : Instead of regexp variable, types can be mapped to functions as well,
137 : in which case the function is called with one argument (the object
138 : we're looking for) and it should search for it.")
139 : (put 'find-function-regexp-alist 'risky-local-variable t)
140 :
141 : (defcustom find-function-source-path nil
142 : "The default list of directories where `find-function' searches.
143 :
144 : If this variable is nil then `find-function' searches `load-path' by
145 : default."
146 : :type '(repeat directory)
147 : :group 'find-function)
148 :
149 : (defcustom find-function-recenter-line 1
150 : "The window line-number from which to start displaying a symbol definition.
151 : A value of nil implies center the beginning of the definition.
152 : See `find-function' and `find-variable'."
153 : :type '(choice (const :tag "Center" nil)
154 : integer)
155 : :group 'find-function
156 : :version "20.3")
157 :
158 : (defcustom find-function-after-hook nil
159 : "Hook run after finding symbol definition.
160 :
161 : See the functions `find-function' and `find-variable'."
162 : :type 'hook
163 : :group 'find-function
164 : :version "20.3")
165 :
166 : ;;; Functions:
167 :
168 : (defun find-library-suffixes ()
169 0 : (let ((suffixes nil))
170 0 : (dolist (suffix (get-load-suffixes) (nreverse suffixes))
171 0 : (unless (string-match "elc" suffix) (push suffix suffixes)))))
172 :
173 : (defun find-library--load-name (library)
174 0 : (let ((name library))
175 0 : (dolist (dir load-path)
176 0 : (let ((rel (file-relative-name library dir)))
177 0 : (if (and (not (string-match "\\`\\.\\./" rel))
178 0 : (< (length rel) (length name)))
179 0 : (setq name rel))))
180 0 : (unless (equal name library) name)))
181 :
182 : (defun find-library-name (library)
183 : "Return the absolute file name of the Emacs Lisp source of LIBRARY.
184 : LIBRARY should be a string (the name of the library)."
185 : ;; If the library is byte-compiled, try to find a source library by
186 : ;; the same name.
187 0 : (when (string-match "\\.el\\(c\\(\\..*\\)?\\)\\'" library)
188 0 : (setq library (replace-match "" t t library)))
189 0 : (or
190 0 : (locate-file library
191 0 : (or find-function-source-path load-path)
192 0 : (find-library-suffixes))
193 0 : (locate-file library
194 0 : (or find-function-source-path load-path)
195 0 : load-file-rep-suffixes)
196 0 : (when (file-name-absolute-p library)
197 0 : (let ((rel (find-library--load-name library)))
198 0 : (when rel
199 0 : (or
200 0 : (locate-file rel
201 0 : (or find-function-source-path load-path)
202 0 : (find-library-suffixes))
203 0 : (locate-file rel
204 0 : (or find-function-source-path load-path)
205 0 : load-file-rep-suffixes)))))
206 0 : (find-library--from-load-history library)
207 0 : (error "Can't find library %s" library)))
208 :
209 : (defun find-library--from-load-history (library)
210 : ;; In `load-history', the file may be ".elc", ".el", ".el.gz", and
211 : ;; LIBRARY may be "foo.el" or "foo".
212 0 : (let ((load-re
213 0 : (concat "\\(" (regexp-quote (file-name-sans-extension library)) "\\)"
214 0 : (regexp-opt (get-load-suffixes)) "\\'")))
215 0 : (cl-loop
216 0 : for (file . _) in load-history thereis
217 0 : (and (stringp file) (string-match load-re file)
218 0 : (let ((dir (substring file 0 (match-beginning 1)))
219 0 : (basename (match-string 1 file)))
220 0 : (locate-file basename (list dir) (find-library-suffixes)))))))
221 :
222 : (defvar find-function-C-source-directory
223 : (let ((dir (expand-file-name "src" source-directory)))
224 : (if (file-accessible-directory-p dir) dir))
225 : "Directory where the C source files of Emacs can be found.
226 : If nil, do not try to find the source code of functions and variables
227 : defined in C.")
228 :
229 : (declare-function ad-get-advice-info "advice" (function))
230 :
231 : (defun find-function-advised-original (func)
232 : "Return the original function definition of an advised function FUNC.
233 : If FUNC is not a symbol, return it. Else, if it's not advised,
234 : return the symbol's function definition."
235 0 : (or (and (symbolp func)
236 0 : (featurep 'nadvice)
237 0 : (let ((ofunc (advice--symbol-function func)))
238 0 : (if (advice--p ofunc)
239 0 : (advice--cd*r ofunc)
240 0 : ofunc)))
241 0 : func))
242 :
243 : (defun find-function-C-source (fun-or-var file type)
244 : "Find the source location where FUN-OR-VAR is defined in FILE.
245 : TYPE should be nil to find a function, or `defvar' to find a variable."
246 0 : (let ((dir (or find-function-C-source-directory
247 0 : (read-directory-name "Emacs C source dir: " nil nil t))))
248 0 : (setq file (expand-file-name file dir))
249 0 : (if (file-readable-p file)
250 0 : (if (null find-function-C-source-directory)
251 0 : (setq find-function-C-source-directory dir))
252 0 : (error "The C source file %s is not available"
253 0 : (file-name-nondirectory file))))
254 0 : (unless type
255 : ;; Either or both an alias and its target might be advised.
256 0 : (setq fun-or-var (find-function-advised-original
257 0 : (indirect-function
258 0 : (find-function-advised-original fun-or-var)))))
259 0 : (with-current-buffer (find-file-noselect file)
260 0 : (goto-char (point-min))
261 0 : (unless (re-search-forward
262 0 : (if type
263 0 : (concat "DEFVAR[A-Z_]*[ \t\n]*([ \t\n]*\""
264 0 : (regexp-quote (symbol-name fun-or-var))
265 0 : "\"")
266 0 : (concat "DEFUN[ \t\n]*([ \t\n]*\""
267 0 : (regexp-quote (subr-name (advice--cd*r fun-or-var)))
268 0 : "\""))
269 0 : nil t)
270 0 : (error "Can't find source for %s" fun-or-var))
271 0 : (cons (current-buffer) (match-beginning 0))))
272 :
273 : ;;;###autoload
274 : (defun find-library (library)
275 : "Find the Emacs Lisp source of LIBRARY.
276 :
277 : Interactively, prompt for LIBRARY using the one at or near point."
278 0 : (interactive (list (read-library-name)))
279 0 : (prog1
280 0 : (switch-to-buffer (find-file-noselect (find-library-name library)))
281 0 : (run-hooks 'find-function-after-hook)))
282 :
283 : (defun read-library-name ()
284 : "Read and return a library name, defaulting to the one near point.
285 :
286 : A library name is the filename of an Emacs Lisp library located
287 : in a directory under `load-path' (or `find-function-source-path',
288 : if non-nil)."
289 0 : (let* ((dirs (or find-function-source-path load-path))
290 0 : (suffixes (find-library-suffixes))
291 0 : (table (apply-partially 'locate-file-completion-table
292 0 : dirs suffixes))
293 0 : (def (if (eq (function-called-at-point) 'require)
294 : ;; `function-called-at-point' may return 'require
295 : ;; with `point' anywhere on this line. So wrap the
296 : ;; `save-excursion' below in a `condition-case' to
297 : ;; avoid reporting a scan-error here.
298 0 : (condition-case nil
299 0 : (save-excursion
300 0 : (backward-up-list)
301 0 : (forward-char)
302 0 : (forward-sexp 2)
303 0 : (thing-at-point 'symbol))
304 0 : (error nil))
305 0 : (thing-at-point 'symbol))))
306 0 : (when (and def (not (test-completion def table)))
307 0 : (setq def nil))
308 0 : (completing-read (if def
309 0 : (format "Library name (default %s): " def)
310 0 : "Library name: ")
311 0 : table nil nil nil nil def)))
312 :
313 : ;;;###autoload
314 : (defun find-library-other-window (library)
315 : "Find the Emacs Lisp source of LIBRARY in another window.
316 :
317 : See `find-library' for more details."
318 0 : (interactive (list (read-library-name)))
319 0 : (prog1
320 0 : (switch-to-buffer-other-window (find-file-noselect
321 0 : (find-library-name library)))
322 0 : (run-hooks 'find-function-after-hook)))
323 :
324 : ;;;###autoload
325 : (defun find-library-other-frame (library)
326 : "Find the Emacs Lisp source of LIBRARY in another frame.
327 :
328 : See `find-library' for more details."
329 0 : (interactive (list (read-library-name)))
330 0 : (prog1
331 0 : (switch-to-buffer-other-frame (find-file-noselect
332 0 : (find-library-name library)))
333 0 : (run-hooks 'find-function-after-hook)))
334 :
335 : ;;;###autoload
336 : (defun find-function-search-for-symbol (symbol type library)
337 : "Search for SYMBOL's definition of type TYPE in LIBRARY.
338 : Visit the library in a buffer, and return a cons cell (BUFFER . POSITION),
339 : or just (BUFFER . nil) if the definition can't be found in the file.
340 :
341 : If TYPE is nil, look for a function definition.
342 : Otherwise, TYPE specifies the kind of definition,
343 : and it is interpreted via `find-function-regexp-alist'.
344 : The search is done in the source for library LIBRARY."
345 0 : (if (null library)
346 0 : (error "Don't know where `%s' is defined" symbol))
347 : ;; Some functions are defined as part of the construct
348 : ;; that defines something else.
349 0 : (while (and (symbolp symbol) (get symbol 'definition-name))
350 0 : (setq symbol (get symbol 'definition-name)))
351 0 : (if (string-match "\\`src/\\(.*\\.\\(c\\|m\\)\\)\\'" library)
352 0 : (find-function-C-source symbol (match-string 1 library) type)
353 0 : (when (string-match "\\.el\\(c\\)\\'" library)
354 0 : (setq library (substring library 0 (match-beginning 1))))
355 : ;; Strip extension from .emacs.el to make sure symbol is searched in
356 : ;; .emacs too.
357 0 : (when (string-match "\\.emacs\\(.el\\)" library)
358 0 : (setq library (substring library 0 (match-beginning 1))))
359 0 : (let* ((filename (find-library-name library))
360 0 : (regexp-symbol (cdr (assq type find-function-regexp-alist))))
361 0 : (with-current-buffer (find-file-noselect filename)
362 0 : (let ((regexp (if (functionp regexp-symbol) regexp-symbol
363 0 : (format (symbol-value regexp-symbol)
364 : ;; Entry for ` (backquote) macro in loaddefs.el,
365 : ;; (defalias (quote \`)..., has a \ but
366 : ;; (symbol-name symbol) doesn't. Add an
367 : ;; optional \ to catch this.
368 0 : (concat "\\\\?"
369 0 : (regexp-quote (symbol-name symbol))))))
370 : (case-fold-search))
371 0 : (with-syntax-table emacs-lisp-mode-syntax-table
372 0 : (goto-char (point-min))
373 0 : (if (if (functionp regexp)
374 0 : (funcall regexp symbol)
375 0 : (or (re-search-forward regexp nil t)
376 : ;; `regexp' matches definitions using known forms like
377 : ;; `defun', or `defvar'. But some functions/variables
378 : ;; are defined using special macros (or functions), so
379 : ;; if `regexp' can't find the definition, we look for
380 : ;; something of the form "(SOMETHING <symbol> ...)".
381 : ;; This fails to distinguish function definitions from
382 : ;; variable declarations (or even uses thereof), but is
383 : ;; a good pragmatic fallback.
384 0 : (re-search-forward
385 0 : (concat "^([^ ]+" find-function-space-re "['(]?"
386 0 : (regexp-quote (symbol-name symbol))
387 0 : "\\_>")
388 0 : nil t)))
389 0 : (progn
390 0 : (beginning-of-line)
391 0 : (cons (current-buffer) (point)))
392 0 : (cons (current-buffer) nil))))))))
393 :
394 : (defun find-function-library (function &optional lisp-only verbose)
395 : "Return the pair (ORIG-FUNCTION . LIBRARY) for FUNCTION.
396 :
397 : ORIG-FUNCTION is the original name, after removing all advice and
398 : resolving aliases. LIBRARY is an absolute file name, a relative
399 : file name inside the C sources directory, or a name of an
400 : autoloaded feature.
401 :
402 : If ORIG-FUNCTION is a built-in function and LISP-ONLY is non-nil,
403 : signal an error.
404 :
405 : If VERBOSE is non-nil, and FUNCTION is an alias, display a
406 : message about the whole chain of aliases."
407 0 : (let ((def (when (symbolp function)
408 0 : (or (fboundp function)
409 0 : (signal 'void-function (list function)))
410 0 : (find-function-advised-original function)))
411 : aliases)
412 : ;; FIXME for completeness, it might be nice to print something like:
413 : ;; foo (which is advised), which is an alias for bar (which is advised).
414 0 : (while (and def (symbolp def))
415 0 : (or (eq def function)
416 0 : (not verbose)
417 0 : (setq aliases (if aliases
418 0 : (concat aliases
419 0 : (format-message
420 : ", which is an alias for `%s'"
421 0 : (symbol-name def)))
422 0 : (format-message "`%s' is an alias for `%s'"
423 0 : function (symbol-name def)))))
424 0 : (setq function (find-function-advised-original function)
425 0 : def (find-function-advised-original function)))
426 0 : (if aliases
427 0 : (message "%s" aliases))
428 0 : (cons function
429 0 : (cond
430 0 : ((autoloadp def) (nth 1 def))
431 0 : ((subrp def)
432 0 : (if lisp-only
433 0 : (error "%s is a built-in function" function))
434 0 : (help-C-file-name def 'subr))
435 0 : ((symbol-file function 'defun))))))
436 :
437 : ;;;###autoload
438 : (defun find-function-noselect (function &optional lisp-only)
439 : "Return a pair (BUFFER . POINT) pointing to the definition of FUNCTION.
440 :
441 : Finds the source file containing the definition of FUNCTION
442 : in a buffer and the point of the definition. The buffer is
443 : not selected. If the function definition can't be found in
444 : the buffer, returns (BUFFER).
445 :
446 : If FUNCTION is a built-in function, this function normally
447 : attempts to find it in the Emacs C sources; however, if LISP-ONLY
448 : is non-nil, signal an error instead.
449 :
450 : If the file where FUNCTION is defined is not known, then it is
451 : searched for in `find-function-source-path' if non-nil, otherwise
452 : in `load-path'."
453 0 : (if (not function)
454 0 : (error "You didn't specify a function"))
455 0 : (let ((func-lib (find-function-library function lisp-only t)))
456 0 : (find-function-search-for-symbol (car func-lib) nil (cdr func-lib))))
457 :
458 : (defun find-function-read (&optional type)
459 : "Read and return an interned symbol, defaulting to the one near point.
460 :
461 : If TYPE is nil, insist on a symbol with a function definition.
462 : Otherwise TYPE should be `defvar' or `defface'.
463 : If TYPE is nil, defaults using `function-called-at-point',
464 : otherwise uses `variable-at-point'."
465 0 : (let* ((symb1 (cond ((null type) (function-called-at-point))
466 0 : ((eq type 'defvar) (variable-at-point))
467 0 : (t (variable-at-point t))))
468 0 : (symb (unless (eq symb1 0) symb1))
469 0 : (predicate (cdr (assq type '((nil . fboundp)
470 : (defvar . boundp)
471 0 : (defface . facep)))))
472 0 : (prompt-type (cdr (assq type '((nil . "function")
473 : (defvar . "variable")
474 0 : (defface . "face")))))
475 0 : (prompt (concat "Find " prompt-type
476 0 : (and symb (format " (default %s)" symb))
477 0 : ": "))
478 : (enable-recursive-minibuffers t))
479 0 : (list (intern (completing-read
480 0 : prompt obarray predicate
481 0 : t nil nil (and symb (symbol-name symb)))))))
482 :
483 : (defun find-function-do-it (symbol type switch-fn)
484 : "Find Emacs Lisp SYMBOL in a buffer and display it.
485 : TYPE is nil to search for a function definition,
486 : or else `defvar' or `defface'.
487 :
488 : The variable `find-function-recenter-line' controls how
489 : to recenter the display. SWITCH-FN is the function to call
490 : to display and select the buffer.
491 : See also `find-function-after-hook'.
492 :
493 : Set mark before moving, if the buffer already existed."
494 0 : (let* ((orig-point (point))
495 0 : (orig-buffers (buffer-list))
496 0 : (buffer-point (save-excursion
497 0 : (find-definition-noselect symbol type)))
498 0 : (new-buf (car buffer-point))
499 0 : (new-point (cdr buffer-point)))
500 0 : (when buffer-point
501 0 : (when (memq new-buf orig-buffers)
502 0 : (push-mark orig-point))
503 0 : (funcall switch-fn new-buf)
504 0 : (when new-point (goto-char new-point))
505 0 : (recenter find-function-recenter-line)
506 0 : (run-hooks 'find-function-after-hook))))
507 :
508 : ;;;###autoload
509 : (defun find-function (function)
510 : "Find the definition of the FUNCTION near point.
511 :
512 : Finds the source file containing the definition of the function
513 : near point (selected by `function-called-at-point') in a buffer and
514 : places point before the definition.
515 : Set mark before moving, if the buffer already existed.
516 :
517 : The library where FUNCTION is defined is searched for in
518 : `find-function-source-path', if non-nil, otherwise in `load-path'.
519 : See also `find-function-recenter-line' and `find-function-after-hook'."
520 0 : (interactive (find-function-read))
521 0 : (find-function-do-it function nil 'switch-to-buffer))
522 :
523 : ;;;###autoload
524 : (defun find-function-other-window (function)
525 : "Find, in another window, the definition of FUNCTION near point.
526 :
527 : See `find-function' for more details."
528 0 : (interactive (find-function-read))
529 0 : (find-function-do-it function nil 'switch-to-buffer-other-window))
530 :
531 : ;;;###autoload
532 : (defun find-function-other-frame (function)
533 : "Find, in another frame, the definition of FUNCTION near point.
534 :
535 : See `find-function' for more details."
536 0 : (interactive (find-function-read))
537 0 : (find-function-do-it function nil 'switch-to-buffer-other-frame))
538 :
539 : ;;;###autoload
540 : (defun find-variable-noselect (variable &optional file)
541 : "Return a pair `(BUFFER . POINT)' pointing to the definition of VARIABLE.
542 :
543 : Finds the library containing the definition of VARIABLE in a buffer and
544 : the point of the definition. The buffer is not selected.
545 : If the variable's definition can't be found in the buffer, return (BUFFER).
546 :
547 : The library where VARIABLE is defined is searched for in FILE or
548 : `find-function-source-path', if non-nil, otherwise in `load-path'."
549 0 : (if (not variable)
550 0 : (error "You didn't specify a variable")
551 0 : (let ((library (or file
552 0 : (symbol-file variable 'defvar)
553 0 : (help-C-file-name variable 'var))))
554 0 : (find-function-search-for-symbol variable 'defvar library))))
555 :
556 : ;;;###autoload
557 : (defun find-variable (variable)
558 : "Find the definition of the VARIABLE at or before point.
559 :
560 : Finds the library containing the definition of the variable
561 : near point (selected by `variable-at-point') in a buffer and
562 : places point before the definition.
563 :
564 : Set mark before moving, if the buffer already existed.
565 :
566 : The library where VARIABLE is defined is searched for in
567 : `find-function-source-path', if non-nil, otherwise in `load-path'.
568 : See also `find-function-recenter-line' and `find-function-after-hook'."
569 0 : (interactive (find-function-read 'defvar))
570 0 : (find-function-do-it variable 'defvar 'switch-to-buffer))
571 :
572 : ;;;###autoload
573 : (defun find-variable-other-window (variable)
574 : "Find, in another window, the definition of VARIABLE near point.
575 :
576 : See `find-variable' for more details."
577 0 : (interactive (find-function-read 'defvar))
578 0 : (find-function-do-it variable 'defvar 'switch-to-buffer-other-window))
579 :
580 : ;;;###autoload
581 : (defun find-variable-other-frame (variable)
582 : "Find, in another frame, the definition of VARIABLE near point.
583 :
584 : See `find-variable' for more details."
585 0 : (interactive (find-function-read 'defvar))
586 0 : (find-function-do-it variable 'defvar 'switch-to-buffer-other-frame))
587 :
588 : ;;;###autoload
589 : (defun find-definition-noselect (symbol type &optional file)
590 : "Return a pair `(BUFFER . POINT)' pointing to the definition of SYMBOL.
591 : If the definition can't be found in the buffer, return (BUFFER).
592 : TYPE says what type of definition: nil for a function, `defvar' for a
593 : variable, `defface' for a face. This function does not switch to the
594 : buffer nor display it.
595 :
596 : The library where SYMBOL is defined is searched for in FILE or
597 : `find-function-source-path', if non-nil, otherwise in `load-path'."
598 0 : (cond
599 0 : ((not symbol)
600 0 : (error "You didn't specify a symbol"))
601 0 : ((null type)
602 0 : (find-function-noselect symbol))
603 0 : ((eq type 'defvar)
604 0 : (find-variable-noselect symbol file))
605 : (t
606 0 : (let ((library (or file (symbol-file symbol type))))
607 0 : (find-function-search-for-symbol symbol type library)))))
608 :
609 : ;; For symmetry, this should be called find-face; but some programs
610 : ;; assume that, if that name is defined, it means something else.
611 : ;;;###autoload
612 : (defun find-face-definition (face)
613 : "Find the definition of FACE. FACE defaults to the name near point.
614 :
615 : Finds the Emacs Lisp library containing the definition of the face
616 : near point (selected by `variable-at-point') in a buffer and
617 : places point before the definition.
618 :
619 : Set mark before moving, if the buffer already existed.
620 :
621 : The library where FACE is defined is searched for in
622 : `find-function-source-path', if non-nil, otherwise in `load-path'.
623 : See also `find-function-recenter-line' and `find-function-after-hook'."
624 0 : (interactive (find-function-read 'defface))
625 0 : (find-function-do-it face 'defface 'switch-to-buffer))
626 :
627 : (defun find-function-on-key-do-it (key find-fn)
628 : "Find the function that KEY invokes. KEY is a string.
629 : Set mark before moving, if the buffer already existed.
630 :
631 : FIND-FN is the function to call to navigate to the function."
632 0 : (let (defn)
633 0 : (save-excursion
634 0 : (let* ((event (and (eventp key) (aref key 0))) ; Null event OK below.
635 0 : (start (event-start event))
636 0 : (modifiers (event-modifiers event))
637 0 : (window (and (or (memq 'click modifiers) (memq 'down modifiers)
638 0 : (memq 'drag modifiers))
639 0 : (posn-window start))))
640 : ;; For a mouse button event, go to the button it applies to
641 : ;; to get the right key bindings. And go to the right place
642 : ;; in case the keymap depends on where you clicked.
643 0 : (when (windowp window)
644 0 : (set-buffer (window-buffer window))
645 0 : (goto-char (posn-point start)))
646 0 : (setq defn (key-binding key))))
647 0 : (let ((key-desc (key-description key)))
648 0 : (if (or (null defn) (integerp defn))
649 0 : (message "%s is unbound" key-desc)
650 0 : (if (consp defn)
651 0 : (message "%s runs %s" key-desc (prin1-to-string defn))
652 0 : (funcall find-fn defn))))))
653 :
654 : ;;;###autoload
655 : (defun find-function-on-key (key)
656 : "Find the function that KEY invokes. KEY is a string.
657 : Set mark before moving, if the buffer already existed."
658 : (interactive "kFind function on key: ")
659 0 : (find-function-on-key-do-it key #'find-function))
660 :
661 : ;;;###autoload
662 : (defun find-function-on-key-other-window (key)
663 : "Find, in the other window, the function that KEY invokes.
664 : See `find-function-on-key'."
665 : (interactive "kFind function on key: ")
666 0 : (find-function-on-key-do-it key #'find-function-other-window))
667 :
668 : ;;;###autoload
669 : (defun find-function-on-key-other-frame (key)
670 : "Find, in the other frame, the function that KEY invokes.
671 : See `find-function-on-key'."
672 : (interactive "kFind function on key: ")
673 0 : (find-function-on-key-do-it key #'find-function-other-frame))
674 :
675 : ;;;###autoload
676 : (defun find-function-at-point ()
677 : "Find directly the function at point in the other window."
678 : (interactive)
679 0 : (let ((symb (function-called-at-point)))
680 0 : (when symb
681 0 : (find-function-other-window symb))))
682 :
683 : ;;;###autoload
684 : (defun find-variable-at-point ()
685 : "Find directly the variable at point in the other window."
686 : (interactive)
687 0 : (let ((symb (variable-at-point)))
688 0 : (when (and symb (not (equal symb 0)))
689 0 : (find-variable-other-window symb))))
690 :
691 : ;;;###autoload
692 : (defun find-function-setup-keys ()
693 : "Define some key bindings for the find-function family of functions."
694 0 : (define-key ctl-x-map "F" 'find-function)
695 0 : (define-key ctl-x-4-map "F" 'find-function-other-window)
696 0 : (define-key ctl-x-5-map "F" 'find-function-other-frame)
697 0 : (define-key ctl-x-map "K" 'find-function-on-key)
698 0 : (define-key ctl-x-4-map "K" 'find-function-on-key-other-window)
699 0 : (define-key ctl-x-5-map "K" 'find-function-on-key-other-frame)
700 0 : (define-key ctl-x-map "V" 'find-variable)
701 0 : (define-key ctl-x-4-map "V" 'find-variable-other-window)
702 0 : (define-key ctl-x-5-map "V" 'find-variable-other-frame))
703 :
704 : (provide 'find-func)
705 :
706 : ;;; find-func.el ends here
|