Some fixes to follow coding conventions.
[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
4a8ea8dc 3;; Copyright (C) 1997, 1999 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
2cd6a032 57(defcustom find-function-regexp
d3d4fb62
RS
58 ;; Match things like (defun foo ...), (defmacro foo ...),
59 ;; (define-skeleton foo ...), (define-generic-mode 'foo ...),
d8f479c6 60 ;; (define-derived-mode foo ...), (define-minor-mode foo)
d3d4fb62 61 "^\\s-*(\\(def\\(ine-skeleton\\|ine-generic-mode\\|ine-derived-mode\\|\
b185f63a 62\[^cgv\W]\\w+\\*?\\)\\|define-minor-mode\\)\\s-+'?\
848e8371 63%s\\(\\s-\\|$\\|\(\\|\)\\)"
d3d4fb62
RS
64 "The regexp used by `find-function' to search for a function definition.
65Note it must contain a `%s' at the place where `format'
2cd6a032
RS
66should insert the function name. The default value avoids `defconst',
67`defgroup', `defvar'.
fffee8be 68
2cd6a032
RS
69Please send improvements and fixes to the maintainer."
70 :type 'regexp
86f28125 71 :group 'find-function
d8f479c6 72 :version "21.1")
2cd6a032
RS
73
74(defcustom find-variable-regexp
f35a7618 75 "^\\s-*(def[^umag]\\(\\w\\|\\s_\\)+\\*?\\s-+%s\\(\\s-\\|$\\)"
2cd6a032
RS
76 "The regexp used by `find-variable' to search for a variable definition.
77It should match right up to the variable name. The default value
f35a7618 78avoids `defun', `defmacro', `defalias', `defadvice', `defgroup'.
2cd6a032
RS
79
80Please send improvements and fixes to the maintainer."
81 :type 'regexp
86f28125 82 :group 'find-function
a469e8ba 83 :version "21.1")
fffee8be 84
0b5bb3ec 85(defcustom find-function-source-path nil
d3d4fb62 86 "The default list of directories where `find-function' searches.
fffee8be 87
d3d4fb62 88If this variable is nil then `find-function' searches `load-path' by
0b5bb3ec
SE
89default."
90 :type '(repeat directory)
91 :group 'find-function)
fffee8be 92
2cd6a032
RS
93(defcustom find-function-recenter-line 1
94 "The window line-number from which to start displaying a symbol definition.
95A value of nil implies center the beginning of the definition.
96See the function `center-to-window-line' for more information, and
97`find-function' and `find-variable'."
86f28125 98 :group 'find-function
a6223467 99 :version "20.3")
2cd6a032
RS
100
101(defcustom find-function-after-hook nil
102 "Hook run after finding symbol definition.
103
104See the functions `find-function' and `find-variable'."
86f28125 105 :group 'find-function
a6223467 106 :version "20.3")
2cd6a032
RS
107
108;;; Functions:
109
110(defun find-function-search-for-symbol (symbol variable-p library)
d3d4fb62 111 "Search for SYMBOL.
2cd6a032 112If VARIABLE-P is nil, `find-function-regexp' is used, otherwise
d3d4fb62 113`find-variable-regexp' is used. The search is done in library LIBRARY."
2cd6a032
RS
114 (if (null library)
115 (error "Don't know where `%s' is defined" symbol))
78b6524e
DL
116 (save-match-data
117 (if (string-match "\\.el\\(c\\)\\'" library)
118 (setq library (substring library 0 (match-beginning 1))))
119 (let* ((path find-function-source-path)
120 (compression (or (rassq 'jka-compr-handler file-name-handler-alist)
121 (member 'crypt-find-file-hook find-file-hooks)))
122 (filename (progn
123 ;; use `file-name-sans-extension' here? (if it gets fixed)
124 (if (string-match "\\(\\.el\\)\\'" library)
125 (setq library (substring library 0
126 (match-beginning 1))))
127 (or (locate-library (concat library ".el") t path)
128 (locate-library library t path)
129 (if compression
130 (or (locate-library (concat library ".el.gz")
131 t path)
132 (locate-library (concat library ".gz")
133 t path)))))))
134 (if (not filename)
135 (error "The library `%s' is not in the path" library))
136 (with-current-buffer (find-file-noselect filename)
2cd6a032
RS
137 (let ((regexp (format (if variable-p
138 find-variable-regexp
139 find-function-regexp)
140 (regexp-quote (symbol-name symbol))))
141 (syn-table (syntax-table)))
142 (unwind-protect
143 (progn
144 (set-syntax-table emacs-lisp-mode-syntax-table)
145 (goto-char (point-min))
146 (if (re-search-forward regexp nil t)
147 (progn
148 (beginning-of-line)
149 (cons (current-buffer) (point)))
d3d4fb62 150 (error "Cannot find definition of `%s' in library `%s'"
2cd6a032
RS
151 symbol library)))
152 (set-syntax-table syn-table)))))))
153
8a8a9abe 154;;;###autoload
2cd6a032 155(defun find-function-noselect (function)
d3d4fb62 156 "Return a pair (BUFFER . POINT) pointing to the definition of FUNCTION.
fffee8be
DL
157
158Finds the Emacs Lisp library containing the definition of FUNCTION
2cd6a032 159in a buffer and the point of the definition. The buffer is
fffee8be
DL
160not selected.
161
2cd6a032 162If the file where FUNCTION is defined is not known, then it is
d3d4fb62 163searched for in `find-function-source-path' if non nil, otherwise
2cd6a032 164in `load-path'."
fffee8be
DL
165 (if (not function)
166 (error "You didn't specify a function"))
2cd6a032
RS
167 (and (subrp (symbol-function function))
168 (error "%s is a primitive function" function))
fffee8be 169 (let ((def (symbol-function function))
2cd6a032 170 aliases)
fffee8be
DL
171 (while (symbolp def)
172 (or (eq def function)
173 (if aliases
174 (setq aliases (concat aliases
2cd6a032 175 (format ", which is an alias for `%s'"
fffee8be 176 (symbol-name def))))
2cd6a032
RS
177 (setq aliases (format "`%s' an alias for `%s'"
178 function (symbol-name def)))))
fffee8be
DL
179 (setq function (symbol-function function)
180 def (symbol-function function)))
181 (if aliases
182 (message aliases))
2cd6a032
RS
183 (let ((library
184 (cond ((eq (car-safe def) 'autoload)
185 (nth 1 def))
186 ((symbol-file function)))))
187 (find-function-search-for-symbol function nil library))))
fffee8be 188
a469e8ba 189(defalias 'function-at-point 'function-called-at-point)
fffee8be 190
2cd6a032
RS
191(defun find-function-read (&optional variable-p)
192 "Read and return an interned symbol, defaulting to the one near point.
fffee8be 193
2cd6a032 194If the optional VARIABLE-P is nil, then a function is gotten
d3d4fb62 195defaulting to the value of the function `function-at-point', otherwise
2cd6a032
RS
196a variable is asked for, with the default coming from
197`variable-at-point'."
198 (let ((symb (funcall (if variable-p
199 'variable-at-point
200 'function-at-point)))
fffee8be
DL
201 (enable-recursive-minibuffers t)
202 val)
2cd6a032
RS
203 (if (equal symb 0)
204 (setq symb nil))
205 (setq val (if variable-p
206 (completing-read
207 (concat "Find variable"
208 (if symb
209 (format " (default %s)" symb))
210 ": ")
211 obarray 'boundp t nil)
212 (completing-read
213 (concat "Find function"
214 (if symb
215 (format " (default %s)" symb))
216 ": ")
217 obarray 'fboundp t nil)))
fffee8be 218 (list (if (equal val "")
2cd6a032
RS
219 symb
220 (intern val)))))
fffee8be 221
2cd6a032 222(defun find-function-do-it (symbol variable-p switch-fn)
d3d4fb62
RS
223 "Find Emacs Lisp SYMBOL in a buffer and display it.
224If VARIABLE-P is nil, a function definition is searched for, otherwise
2cd6a032
RS
225a variable definition is searched for. The start of a definition is
226centered according to the variable `find-function-recenter-line'.
d3d4fb62 227See also `find-function-after-hook' It is displayed with function SWITCH-FN.
2cd6a032
RS
228
229Point is saved in the buffer if it is one of the current buffers."
86f28125
RS
230 (let* ((orig-point (point))
231 (orig-buf (window-buffer))
2cd6a032 232 (orig-buffers (buffer-list))
86f28125
RS
233 (buffer-point (save-excursion
234 (funcall (if variable-p
235 'find-variable-noselect
236 'find-function-noselect)
237 symbol)))
238 (new-buf (car buffer-point))
239 (new-point (cdr buffer-point)))
2cd6a032 240 (when buffer-point
86f28125 241 (when (memq new-buf orig-buffers)
2cd6a032 242 (push-mark orig-point))
86f28125
RS
243 (funcall switch-fn new-buf)
244 (goto-char new-point)
2cd6a032 245 (recenter find-function-recenter-line)
8d8ca3cf 246 (run-hooks 'find-function-after-hook))))
fffee8be 247
b07745ec 248;;;###autoload
2cd6a032 249(defun find-function (function)
c7efc289 250 "Find the definition of the FUNCTION near point.
fffee8be
DL
251
252Finds the Emacs Lisp library containing the definition of the function
2cd6a032
RS
253near point (selected by `function-at-point') in a buffer and
254places point before the definition. Point is saved in the buffer if
255it is one of the current buffers.
fffee8be 256
2cd6a032 257The library where FUNCTION is defined is searched for in
d3d4fb62 258`find-function-source-path', if non nil, otherwise in `load-path'.
2cd6a032
RS
259See also `find-function-recenter-line' and `find-function-after-hook'."
260 (interactive (find-function-read))
261 (find-function-do-it function nil 'switch-to-buffer))
fffee8be 262
b07745ec 263;;;###autoload
2cd6a032 264(defun find-function-other-window (function)
c7efc289 265 "Find, in another window, the definition of FUNCTION near point.
fffee8be 266
2cd6a032
RS
267See `find-function' for more details."
268 (interactive (find-function-read))
269 (find-function-do-it function nil 'switch-to-buffer-other-window))
fffee8be 270
b07745ec 271;;;###autoload
2cd6a032 272(defun find-function-other-frame (function)
c7efc289 273 "Find, in ananother frame, the definition of FUNCTION near point.
fffee8be 274
2cd6a032
RS
275See `find-function' for more details."
276 (interactive (find-function-read))
277 (find-function-do-it function nil 'switch-to-buffer-other-frame))
278
e1acbda2 279;;;###autoload
2cd6a032 280(defun find-variable-noselect (variable)
d3d4fb62 281 "Return a pair `(buffer . point)' pointing to the definition of SYMBOL.
2cd6a032
RS
282
283Finds the Emacs Lisp library containing the definition of SYMBOL
284in a buffer and the point of the definition. The buffer is
285not selected.
286
287The library where VARIABLE is defined is searched for in
d3d4fb62 288`find-function-source-path', if non nil, otherwise in `load-path'."
2cd6a032
RS
289 (if (not variable)
290 (error "You didn't specify a variable"))
291 (let ((library (symbol-file variable)))
292 (find-function-search-for-symbol variable 'variable library)))
293
294;;;###autoload
295(defun find-variable (variable)
c7efc289 296 "Find the definition of the VARIABLE near point.
2cd6a032
RS
297
298Finds the Emacs Lisp library containing the definition of the variable
299near point (selected by `variable-at-point') in a buffer and
300places point before the definition. Point is saved in the buffer if
301it is one of the current buffers.
302
303The library where VARIABLE is defined is searched for in
d3d4fb62 304`find-function-source-path', if non nil, otherwise in `load-path'.
2cd6a032
RS
305See also `find-function-recenter-line' and `find-function-after-hook'."
306 (interactive (find-function-read 'variable))
307 (find-function-do-it variable t 'switch-to-buffer))
fffee8be 308
2cd6a032
RS
309;;;###autoload
310(defun find-variable-other-window (variable)
c7efc289 311 "Find, in another window, the definition of VARIABLE near point.
2cd6a032
RS
312
313See `find-variable' for more details."
314 (interactive (find-function-read 'variable))
315 (find-function-do-it variable t 'switch-to-buffer-other-window))
316
317;;;###autoload
318(defun find-variable-other-frame (variable)
c7efc289 319 "Find, in annother frame, the definition of VARIABLE near point.
2cd6a032
RS
320
321See `find-variable' for more details."
322 (interactive (find-function-read 'variable))
323 (find-function-do-it variable t 'switch-to-buffer-other-frame))
fffee8be 324
b07745ec 325;;;###autoload
fffee8be
DL
326(defun find-function-on-key (key)
327 "Find the function that KEY invokes. KEY is a string.
328Point is saved if FUNCTION is in the current buffer."
329 (interactive "kFind function on key: ")
4a8ea8dc 330 (save-excursion
43920c26 331 (let* ((event (and (eventp key) (aref key 0))) ; Null event OK below.
4a8ea8dc
DL
332 (start (event-start event))
333 (modifiers (event-modifiers event))
334 (window (and (or (memq 'click modifiers) (memq 'down modifiers)
335 (memq 'drag modifiers))
336 (posn-window start))))
337 ;; For a mouse button event, go to the button it applies to
338 ;; to get the right key bindings. And go to the right place
339 ;; in case the keymap depends on where you clicked.
340 (when (windowp window)
341 (set-buffer (window-buffer window))
342 (goto-char (posn-point start)))
343 (let ((defn (key-binding key))
344 (key-desc (key-description key)))
345 (if (or (null defn) (integerp defn))
346 (message "%s is unbound" key-desc)
347 (if (consp defn)
348 (message "%s runs %s" key-desc (prin1-to-string defn))
349 (find-function-other-window defn)))))))
2cd6a032
RS
350
351;;;###autoload
352(defun find-function-at-point ()
353 "Find directly the function at point in the other window."
354 (interactive)
355 (let ((symb (function-at-point)))
356 (when symb
357 (find-function-other-window symb))))
358
359;;;###autoload
360(defun find-variable-at-point ()
361 "Find directly the function at point in the other window."
362 (interactive)
363 (let ((symb (variable-at-point)))
364 (when (and symb (not (equal symb 0)))
365 (find-variable-other-window symb))))
fffee8be 366
86f28125
RS
367;;;###autoload
368(defun find-function-setup-keys ()
369 "Define some key bindings for the find-function family of functions."
370 (define-key ctl-x-map "F" 'find-function)
371 (define-key ctl-x-4-map "F" 'find-function-other-window)
372 (define-key ctl-x-5-map "F" 'find-function-other-frame)
373 (define-key ctl-x-map "K" 'find-function-on-key)
374 (define-key ctl-x-map "V" 'find-variable)
375 (define-key ctl-x-4-map "V" 'find-variable-other-window)
376 (define-key ctl-x-5-map "V" 'find-variable-other-frame))
377
fffee8be
DL
378(provide 'find-func)
379
380;;; find-func.el ends here