Commit | Line | Data |
---|---|---|
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. |
66 | Note it must contain a `%s' at the place where `format' | |
2cd6a032 RS |
67 | should insert the function name. The default value avoids `defconst', |
68 | `defgroup', `defvar'. | |
fffee8be | 69 | |
2cd6a032 RS |
70 | Please 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. |
78 | It should match right up to the variable name. The default value | |
f35a7618 | 79 | avoids `defun', `defmacro', `defalias', `defadvice', `defgroup'. |
2cd6a032 RS |
80 | |
81 | Please 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 | 89 | If this variable is nil then `find-function' searches `load-path' by |
0b5bb3ec SE |
90 | default." |
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. | |
96 | A value of nil implies center the beginning of the definition. | |
97 | See 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 | ||
105 | See 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 | 113 | If 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 | |
164 | Finds the Emacs Lisp library containing the definition of FUNCTION | |
2cd6a032 | 165 | in a buffer and the point of the definition. The buffer is |
fffee8be DL |
166 | not selected. |
167 | ||
2cd6a032 | 168 | If the file where FUNCTION is defined is not known, then it is |
d3d4fb62 | 169 | searched for in `find-function-source-path' if non nil, otherwise |
2cd6a032 | 170 | in `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 | 200 | If the optional VARIABLE-P is nil, then a function is gotten |
d3d4fb62 | 201 | defaulting to the value of the function `function-at-point', otherwise |
2cd6a032 RS |
202 | a 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. |
230 | If VARIABLE-P is nil, a function definition is searched for, otherwise | |
2cd6a032 RS |
231 | a variable definition is searched for. The start of a definition is |
232 | centered according to the variable `find-function-recenter-line'. | |
d3d4fb62 | 233 | See also `find-function-after-hook' It is displayed with function SWITCH-FN. |
2cd6a032 RS |
234 | |
235 | Point 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 | |
258 | Finds the Emacs Lisp library containing the definition of the function | |
2cd6a032 RS |
259 | near point (selected by `function-at-point') in a buffer and |
260 | places point before the definition. Point is saved in the buffer if | |
261 | it is one of the current buffers. | |
fffee8be | 262 | |
2cd6a032 | 263 | The library where FUNCTION is defined is searched for in |
d3d4fb62 | 264 | `find-function-source-path', if non nil, otherwise in `load-path'. |
2cd6a032 RS |
265 | See 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 |
273 | See `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 |
281 | See `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 | |
289 | Finds the Emacs Lisp library containing the definition of SYMBOL | |
290 | in a buffer and the point of the definition. The buffer is | |
291 | not selected. | |
292 | ||
1c787e34 | 293 | The 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 | |
304 | Finds the Emacs Lisp library containing the definition of the variable | |
305 | near point (selected by `variable-at-point') in a buffer and | |
306 | places point before the definition. Point is saved in the buffer if | |
307 | it is one of the current buffers. | |
308 | ||
309 | The library where VARIABLE is defined is searched for in | |
d3d4fb62 | 310 | `find-function-source-path', if non nil, otherwise in `load-path'. |
2cd6a032 RS |
311 | See 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 | |
319 | See `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 | |
327 | See `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. | |
334 | Point 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 |