(Fmap_charset_chars): Fix docstring.
[bpt/emacs.git] / lisp / emacs-lisp / find-func.el
CommitLineData
2cd6a032 1;;; find-func.el --- find the definition of the Emacs Lisp function near point
fffee8be 2
d2922337 3;; Copyright (C) 1997, 1999, 2001 Free Software Foundation, Inc.
fffee8be
DL
4
5;; Author: Jens Petersen <petersen@kurims.kyoto-u.ac.jp>
6;; Maintainer: petersen@kurims.kyoto-u.ac.jp
2cd6a032 7;; Keywords: emacs-lisp, functions, variables
fffee8be
DL
8;; Created: 97/07/25
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
26
27;;; Commentary:
28;;
29;; The funniest thing about this is that I can't imagine why a package
30;; so obviously useful as this hasn't been written before!!
fffee8be 31;; ;;; find-func
86f28125
RS
32;; (find-function-setup-keys)
33;;
34;; or just:
35;;
2cd6a032 36;; (load "find-func")
fffee8be 37;;
86f28125 38;; if you don't like the given keybindings and away you go! It does
2cd6a032
RS
39;; pretty much what you would expect, putting the cursor at the
40;; definition of the function or variable at point.
fffee8be 41;;
2cd6a032 42;; The code started out from `describe-function', `describe-key'
fffee8be
DL
43;; ("help.el") and `fff-find-loaded-emacs-lisp-function' (Noah Friedman's
44;; "fff.el").
45
e8af40ee 46;;; Code:
fffee8be 47
2cd6a032
RS
48(require 'loadhist)
49
fffee8be 50;;; User variables:
2cd6a032 51
0b5bb3ec 52(defgroup find-function nil
2cd6a032
RS
53 "Finds the definition of the Emacs Lisp symbol near point."
54;; :prefix "find-function"
0b5bb3ec 55 :group 'lisp)
fffee8be 56
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\\|\
d2922337
GM
62\[^cgv\W]\\w+\\*?\\)\\|define-minor-mode\
63\\|easy-mmode-define-global-mode\\)\\(\\s-\\|\n\\)+'?\
848e8371 64%s\\(\\s-\\|$\\|\(\\|\)\\)"
d3d4fb62
RS
65 "The regexp used by `find-function' to search for a function definition.
66Note it must contain a `%s' at the place where `format'
2cd6a032
RS
67should insert the function name. The default value avoids `defconst',
68`defgroup', `defvar'.
fffee8be 69
2cd6a032
RS
70Please send improvements and fixes to the maintainer."
71 :type 'regexp
86f28125 72 :group 'find-function
d8f479c6 73 :version "21.1")
2cd6a032
RS
74
75(defcustom find-variable-regexp
f35a7618 76 "^\\s-*(def[^umag]\\(\\w\\|\\s_\\)+\\*?\\s-+%s\\(\\s-\\|$\\)"
2cd6a032
RS
77 "The regexp used by `find-variable' to search for a variable definition.
78It should match right up to the variable name. The default value
f35a7618 79avoids `defun', `defmacro', `defalias', `defadvice', `defgroup'.
2cd6a032
RS
80
81Please send improvements and fixes to the maintainer."
82 :type 'regexp
86f28125 83 :group 'find-function
a469e8ba 84 :version "21.1")
fffee8be 85
0b5bb3ec 86(defcustom find-function-source-path nil
d3d4fb62 87 "The default list of directories where `find-function' searches.
fffee8be 88
d3d4fb62 89If this variable is nil then `find-function' searches `load-path' by
0b5bb3ec
SE
90default."
91 :type '(repeat directory)
92 :group 'find-function)
fffee8be 93
2cd6a032
RS
94(defcustom find-function-recenter-line 1
95 "The window line-number from which to start displaying a symbol definition.
96A value of nil implies center the beginning of the definition.
97See the function `center-to-window-line' for more information, and
98`find-function' and `find-variable'."
86f28125 99 :group 'find-function
a6223467 100 :version "20.3")
2cd6a032
RS
101
102(defcustom find-function-after-hook nil
103 "Hook run after finding symbol definition.
104
105See the functions `find-function' and `find-variable'."
86f28125 106 :group 'find-function
a6223467 107 :version "20.3")
2cd6a032
RS
108
109;;; Functions:
110
111(defun find-function-search-for-symbol (symbol variable-p library)
d3d4fb62 112 "Search for SYMBOL.
2cd6a032 113If VARIABLE-P is nil, `find-function-regexp' is used, otherwise
d3d4fb62 114`find-variable-regexp' is used. The search is done in library LIBRARY."
2cd6a032
RS
115 (if (null library)
116 (error "Don't know where `%s' is defined" symbol))
78b6524e
DL
117 (save-match-data
118 (if (string-match "\\.el\\(c\\)\\'" library)
119 (setq library (substring library 0 (match-beginning 1))))
120 (let* ((path find-function-source-path)
121 (compression (or (rassq 'jka-compr-handler file-name-handler-alist)
122 (member 'crypt-find-file-hook find-file-hooks)))
123 (filename (progn
124 ;; use `file-name-sans-extension' here? (if it gets fixed)
125 (if (string-match "\\(\\.el\\)\\'" library)
126 (setq library (substring library 0
127 (match-beginning 1))))
128 (or (locate-library (concat library ".el") t path)
129 (locate-library library t path)
130 (if compression
131 (or (locate-library (concat library ".el.gz")
132 t path)
133 (locate-library (concat library ".gz")
134 t path)))))))
135 (if (not filename)
136 (error "The library `%s' is not in the path" library))
137 (with-current-buffer (find-file-noselect filename)
2cd6a032
RS
138 (let ((regexp (format (if variable-p
139 find-variable-regexp
140 find-function-regexp)
141 (regexp-quote (symbol-name symbol))))
142 (syn-table (syntax-table)))
143 (unwind-protect
144 (progn
145 (set-syntax-table emacs-lisp-mode-syntax-table)
146 (goto-char (point-min))
1c787e34
SM
147 (if (or (re-search-forward regexp nil t)
148 (re-search-forward
149 (concat "^([^ ]+ +"
150 (regexp-quote (symbol-name symbol))
151 "\\>")
152 nil t))
2cd6a032
RS
153 (progn
154 (beginning-of-line)
155 (cons (current-buffer) (point)))
d3d4fb62 156 (error "Cannot find definition of `%s' in library `%s'"
2cd6a032
RS
157 symbol library)))
158 (set-syntax-table syn-table)))))))
159
8a8a9abe 160;;;###autoload
2cd6a032 161(defun find-function-noselect (function)
d3d4fb62 162 "Return a pair (BUFFER . POINT) pointing to the definition of FUNCTION.
fffee8be
DL
163
164Finds the Emacs Lisp library containing the definition of FUNCTION
2cd6a032 165in a buffer and the point of the definition. The buffer is
fffee8be
DL
166not selected.
167
2cd6a032 168If the file where FUNCTION is defined is not known, then it is
d3d4fb62 169searched for in `find-function-source-path' if non nil, otherwise
2cd6a032 170in `load-path'."
fffee8be
DL
171 (if (not function)
172 (error "You didn't specify a function"))
2cd6a032
RS
173 (and (subrp (symbol-function function))
174 (error "%s is a primitive function" function))
fffee8be 175 (let ((def (symbol-function function))
2cd6a032 176 aliases)
fffee8be
DL
177 (while (symbolp def)
178 (or (eq def function)
179 (if aliases
180 (setq aliases (concat aliases
2cd6a032 181 (format ", which is an alias for `%s'"
fffee8be 182 (symbol-name def))))
2cd6a032
RS
183 (setq aliases (format "`%s' an alias for `%s'"
184 function (symbol-name def)))))
fffee8be
DL
185 (setq function (symbol-function function)
186 def (symbol-function function)))
187 (if aliases
188 (message aliases))
2cd6a032
RS
189 (let ((library
190 (cond ((eq (car-safe def) 'autoload)
191 (nth 1 def))
192 ((symbol-file function)))))
193 (find-function-search-for-symbol function nil library))))
fffee8be 194
a469e8ba 195(defalias 'function-at-point 'function-called-at-point)
fffee8be 196
2cd6a032
RS
197(defun find-function-read (&optional variable-p)
198 "Read and return an interned symbol, defaulting to the one near point.
fffee8be 199
2cd6a032 200If the optional VARIABLE-P is nil, then a function is gotten
d3d4fb62 201defaulting to the value of the function `function-at-point', otherwise
2cd6a032
RS
202a variable is asked for, with the default coming from
203`variable-at-point'."
204 (let ((symb (funcall (if variable-p
205 'variable-at-point
206 'function-at-point)))
fffee8be
DL
207 (enable-recursive-minibuffers t)
208 val)
2cd6a032
RS
209 (if (equal symb 0)
210 (setq symb nil))
211 (setq val (if variable-p
212 (completing-read
213 (concat "Find variable"
214 (if symb
215 (format " (default %s)" symb))
216 ": ")
217 obarray 'boundp t nil)
218 (completing-read
219 (concat "Find function"
220 (if symb
221 (format " (default %s)" symb))
222 ": ")
223 obarray 'fboundp t nil)))
fffee8be 224 (list (if (equal val "")
2cd6a032
RS
225 symb
226 (intern val)))))
fffee8be 227
2cd6a032 228(defun find-function-do-it (symbol variable-p switch-fn)
d3d4fb62
RS
229 "Find Emacs Lisp SYMBOL in a buffer and display it.
230If VARIABLE-P is nil, a function definition is searched for, otherwise
2cd6a032
RS
231a variable definition is searched for. The start of a definition is
232centered according to the variable `find-function-recenter-line'.
d3d4fb62 233See also `find-function-after-hook' It is displayed with function SWITCH-FN.
2cd6a032
RS
234
235Point is saved in the buffer if it is one of the current buffers."
86f28125
RS
236 (let* ((orig-point (point))
237 (orig-buf (window-buffer))
2cd6a032 238 (orig-buffers (buffer-list))
86f28125
RS
239 (buffer-point (save-excursion
240 (funcall (if variable-p
241 'find-variable-noselect
242 'find-function-noselect)
243 symbol)))
244 (new-buf (car buffer-point))
245 (new-point (cdr buffer-point)))
2cd6a032 246 (when buffer-point
86f28125 247 (when (memq new-buf orig-buffers)
2cd6a032 248 (push-mark orig-point))
86f28125
RS
249 (funcall switch-fn new-buf)
250 (goto-char new-point)
2cd6a032 251 (recenter find-function-recenter-line)
8d8ca3cf 252 (run-hooks 'find-function-after-hook))))
fffee8be 253
b07745ec 254;;;###autoload
2cd6a032 255(defun find-function (function)
c7efc289 256 "Find the definition of the FUNCTION near point.
fffee8be
DL
257
258Finds the Emacs Lisp library containing the definition of the function
2cd6a032
RS
259near point (selected by `function-at-point') in a buffer and
260places point before the definition. Point is saved in the buffer if
261it is one of the current buffers.
fffee8be 262
2cd6a032 263The library where FUNCTION is defined is searched for in
d3d4fb62 264`find-function-source-path', if non nil, otherwise in `load-path'.
2cd6a032
RS
265See also `find-function-recenter-line' and `find-function-after-hook'."
266 (interactive (find-function-read))
267 (find-function-do-it function nil 'switch-to-buffer))
fffee8be 268
b07745ec 269;;;###autoload
2cd6a032 270(defun find-function-other-window (function)
c7efc289 271 "Find, in another window, the definition of FUNCTION near point.
fffee8be 272
2cd6a032
RS
273See `find-function' for more details."
274 (interactive (find-function-read))
275 (find-function-do-it function nil 'switch-to-buffer-other-window))
fffee8be 276
b07745ec 277;;;###autoload
2cd6a032 278(defun find-function-other-frame (function)
c7efc289 279 "Find, in ananother frame, the definition of FUNCTION near point.
fffee8be 280
2cd6a032
RS
281See `find-function' for more details."
282 (interactive (find-function-read))
283 (find-function-do-it function nil 'switch-to-buffer-other-frame))
284
e1acbda2 285;;;###autoload
1c787e34
SM
286(defun find-variable-noselect (variable &optional file)
287 "Return a pair `(BUFFER . POINT)' pointing to the definition of SYMBOL.
2cd6a032
RS
288
289Finds the Emacs Lisp library containing the definition of SYMBOL
290in a buffer and the point of the definition. The buffer is
291not selected.
292
1c787e34 293The library where VARIABLE is defined is searched for in FILE or
d3d4fb62 294`find-function-source-path', if non nil, otherwise in `load-path'."
2cd6a032
RS
295 (if (not variable)
296 (error "You didn't specify a variable"))
1c787e34 297 (let ((library (or file (symbol-file variable))))
2cd6a032
RS
298 (find-function-search-for-symbol variable 'variable library)))
299
300;;;###autoload
301(defun find-variable (variable)
c7efc289 302 "Find the definition of the VARIABLE near point.
2cd6a032
RS
303
304Finds the Emacs Lisp library containing the definition of the variable
305near point (selected by `variable-at-point') in a buffer and
306places point before the definition. Point is saved in the buffer if
307it is one of the current buffers.
308
309The library where VARIABLE is defined is searched for in
d3d4fb62 310`find-function-source-path', if non nil, otherwise in `load-path'.
2cd6a032
RS
311See also `find-function-recenter-line' and `find-function-after-hook'."
312 (interactive (find-function-read 'variable))
313 (find-function-do-it variable t 'switch-to-buffer))
fffee8be 314
2cd6a032
RS
315;;;###autoload
316(defun find-variable-other-window (variable)
c7efc289 317 "Find, in another window, the definition of VARIABLE near point.
2cd6a032
RS
318
319See `find-variable' for more details."
320 (interactive (find-function-read 'variable))
321 (find-function-do-it variable t 'switch-to-buffer-other-window))
322
323;;;###autoload
324(defun find-variable-other-frame (variable)
c7efc289 325 "Find, in annother frame, the definition of VARIABLE near point.
2cd6a032
RS
326
327See `find-variable' for more details."
328 (interactive (find-function-read 'variable))
329 (find-function-do-it variable t 'switch-to-buffer-other-frame))
fffee8be 330
b07745ec 331;;;###autoload
fffee8be
DL
332(defun find-function-on-key (key)
333 "Find the function that KEY invokes. KEY is a string.
334Point is saved if FUNCTION is in the current buffer."
335 (interactive "kFind function on key: ")
4a8ea8dc 336 (save-excursion
43920c26 337 (let* ((event (and (eventp key) (aref key 0))) ; Null event OK below.
4a8ea8dc
DL
338 (start (event-start event))
339 (modifiers (event-modifiers event))
340 (window (and (or (memq 'click modifiers) (memq 'down modifiers)
341 (memq 'drag modifiers))
342 (posn-window start))))
343 ;; For a mouse button event, go to the button it applies to
344 ;; to get the right key bindings. And go to the right place
345 ;; in case the keymap depends on where you clicked.
346 (when (windowp window)
347 (set-buffer (window-buffer window))
348 (goto-char (posn-point start)))
349 (let ((defn (key-binding key))
350 (key-desc (key-description key)))
351 (if (or (null defn) (integerp defn))
352 (message "%s is unbound" key-desc)
353 (if (consp defn)
354 (message "%s runs %s" key-desc (prin1-to-string defn))
355 (find-function-other-window defn)))))))
2cd6a032
RS
356
357;;;###autoload
358(defun find-function-at-point ()
359 "Find directly the function at point in the other window."
360 (interactive)
361 (let ((symb (function-at-point)))
362 (when symb
363 (find-function-other-window symb))))
364
365;;;###autoload
366(defun find-variable-at-point ()
367 "Find directly the function at point in the other window."
368 (interactive)
369 (let ((symb (variable-at-point)))
370 (when (and symb (not (equal symb 0)))
371 (find-variable-other-window symb))))
fffee8be 372
86f28125
RS
373;;;###autoload
374(defun find-function-setup-keys ()
375 "Define some key bindings for the find-function family of functions."
376 (define-key ctl-x-map "F" 'find-function)
377 (define-key ctl-x-4-map "F" 'find-function-other-window)
378 (define-key ctl-x-5-map "F" 'find-function-other-frame)
379 (define-key ctl-x-map "K" 'find-function-on-key)
380 (define-key ctl-x-map "V" 'find-variable)
381 (define-key ctl-x-4-map "V" 'find-variable-other-window)
382 (define-key ctl-x-5-map "V" 'find-variable-other-frame))
383
fffee8be
DL
384(provide 'find-func)
385
386;;; find-func.el ends here