Mercurial > hg > xemacs-beta
comparison lisp/hyperbole/hmouse-tag.el @ 100:4be1180a9e89 r20-1b2
Import from CVS: tag r20-1b2
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:15:11 +0200 |
parents | 131b0175ea99 |
children |
comparison
equal
deleted
inserted
replaced
99:2d83cbd90d8d | 100:4be1180a9e89 |
---|---|
4 ;; SUMMARY: Smart Key support of programming language tags location. | 4 ;; SUMMARY: Smart Key support of programming language tags location. |
5 ;; USAGE: GNU Emacs Lisp Library | 5 ;; USAGE: GNU Emacs Lisp Library |
6 ;; KEYWORDS: c, hypermedia, mouse, oop, tools | 6 ;; KEYWORDS: c, hypermedia, mouse, oop, tools |
7 ;; | 7 ;; |
8 ;; AUTHOR: Bob Weiner | 8 ;; AUTHOR: Bob Weiner |
9 ;; ORG: Brown U. | 9 ;; ORG: InfoDock Associates |
10 ;; | 10 ;; |
11 ;; ORIG-DATE: 24-Aug-91 | 11 ;; ORIG-DATE: 24-Aug-91 |
12 ;; LAST-MOD: 11-Sep-95 at 18:19:48 by Bob Weiner | 12 ;; LAST-MOD: 17-Feb-97 at 15:31:50 by Bob Weiner |
13 ;; | |
14 ;; This file is part of Hyperbole. | |
15 ;; Available for use and distribution under the same terms as GNU Emacs. | |
16 ;; | |
17 ;; Copyright (C) 1991-1995, Free Software Foundation, Inc. | |
18 ;; Developed with support from Motorola Inc. | |
19 ;; | |
20 ;; DESCRIPTION: | |
21 ;; | |
22 ;; Supports C, C++, Objective-C, Lisp, Fortran, and Assembly. | |
23 ;; See the GNU Emacs manual for information on how to create a TAGS file | |
24 ;; from the `etags' program. | |
25 ;; Does not support the `ctags' tags file format. | |
26 ;; | |
27 ;; YOU MUST APPROPRIATELY SET THE PUBLIC VARIABLES BELOW BEFORE USE. | |
28 ;; | |
29 ;; DESCRIP-END. | |
30 | |
31 ;;; ************************************************************************ | 13 ;;; ************************************************************************ |
32 ;;; Other required Elisp libraries | 14 ;;; Other required Elisp libraries |
33 ;;; ************************************************************************ | 15 ;;; ************************************************************************ |
16 | |
17 (require 'hpath) | |
18 (require 'hbut) | |
34 | 19 |
35 (if (cond ((or (featurep 'etags) (featurep 'tags)) | 20 (if (cond ((or (featurep 'etags) (featurep 'tags)) |
36 nil) | 21 nil) |
37 ((or hyperb:lemacs-p hyperb:emacs19-p) | 22 ((or hyperb:lemacs-p hyperb:emacs19-p) |
38 ;; Force use of .elc file here since otherwise the bin/etags | 23 ;; Force use of .elc file here since otherwise the bin/etags |
69 | 54 |
70 (defvar smart-c-include-dirs nil | 55 (defvar smart-c-include-dirs nil |
71 "*Ordered list of directories to search for C/C++ include files. | 56 "*Ordered list of directories to search for C/C++ include files. |
72 Each directory must end with a directory separator. Directories normally | 57 Each directory must end with a directory separator. Directories normally |
73 searched by the C/C++ pre-processor should be set instead in | 58 searched by the C/C++ pre-processor should be set instead in |
74 'smart-c-cpp-include-dirs'.") | 59 `smart-c-cpp-include-dirs'.") |
75 | 60 |
76 (defvar smart-c-use-lib-man nil | 61 (defvar smart-c-use-lib-man nil |
77 "When non-nil makes 'smart-c' and 'smart-c++' display man pages for recognized lib symbols. | 62 "When non-nil makes `smart-c' and `smart-c++' display man pages for recognized lib symbols. |
78 When nil, 'smart-c' and 'smart-c++' look up only symbols defined in an etags | 63 When nil, `smart-c' and `smart-c++' look up only symbols defined in an etags |
79 TAGS file. | 64 TAGS file. |
80 | 65 |
81 Create the file ~/.CLIBS-LIST and populate it with the full pathnames (one per | 66 Create the file ~/.CLIBS-LIST and populate it with the full pathnames (one per |
82 line) of all of the C/C++ libraries whose symbols you want to match against. | 67 line) of all of the C/C++ libraries whose symbols you want to match against. |
83 Your MANPATH environment variable must include paths for the man pages of | 68 Your MANPATH environment variable must include paths for the man pages of |
89 | 74 |
90 (defconst smart-c-include-regexp | 75 (defconst smart-c-include-regexp |
91 "[ \t/*]*#[ \t]*\\(include\\|import\\)[ \t]+\\([\"<]\\)\\([^\">]+\\)[\">]" | 76 "[ \t/*]*#[ \t]*\\(include\\|import\\)[ \t]+\\([\"<]\\)\\([^\">]+\\)[\">]" |
92 "Regexp to match to C, C++, or Objective-C include file lines. | 77 "Regexp to match to C, C++, or Objective-C include file lines. |
93 Include keyword matched is grouping 1. Type of include, user-specified via | 78 Include keyword matched is grouping 1. Type of include, user-specified via |
94 double quote, or system-related starting with '<' is given by grouping 2. | 79 double quote, or system-related starting with `<' is given by grouping 2. |
95 File name is grouping 3.") | 80 File name is grouping 3.") |
81 | |
82 (defvar smart-java-package-dirs | |
83 (and (fboundp 'getenv) (getenv "JAVA_HOME") | |
84 (list (expand-file-name "src/" (file-name-as-directory (getenv "JAVA_HOME"))))) | |
85 "*Ordered list of directories to search for imported Java packages. | |
86 Each directory must end with a directory separator.") | |
87 | |
88 (defconst smart-java-package-regexp | |
89 "[ \t/*]*\\(package\\|import\\)[ \t]+\\([^; \t\n\r\f]+\\)" | |
90 "Regexp to match to Java `package' and `import' lines. | |
91 Keyword matched is grouping 1. Referent is grouping 2.") | |
96 | 92 |
97 (defvar smart-emacs-tags-file nil | 93 (defvar smart-emacs-tags-file nil |
98 "*Full path name of etags file for GNU Emacs source.") | 94 "*Full path name of etags file for GNU Emacs source.") |
99 | 95 |
100 ;;; ************************************************************************ | 96 ;;; ************************************************************************ |
108 It assumes that its caller has already checked that the key was pressed in an | 104 It assumes that its caller has already checked that the key was pressed in an |
109 appropriate buffer and has moved the cursor to the selected buffer. | 105 appropriate buffer and has moved the cursor to the selected buffer. |
110 | 106 |
111 If: | 107 If: |
112 (1) on an include statement, the include file is displayed; | 108 (1) on an include statement, the include file is displayed; |
113 Look for include file in directory list 'smart-asm-include-dirs'. | 109 Look for include file in directory list `smart-asm-include-dirs'. |
114 (2) on an identifier, the identifier definition is displayed, | 110 (2) on an identifier, the identifier definition is displayed, |
115 assuming the identifier is found within an 'etags' generated tag file | 111 assuming the identifier is found within an `etags' generated tag file |
116 in the current directory or any of its ancestor directories." | 112 in the current directory or any of its ancestor directories." |
117 | 113 |
118 (interactive) | 114 (interactive) |
119 (or | 115 (or |
120 (if identifier nil (smart-asm-include-file)) | 116 (if identifier nil (smart-asm-include-file)) |
121 (let ((tag (or identifier (smart-asm-at-tag-p)))) | 117 (let ((tag (or identifier (smart-asm-at-tag-p)))) |
122 ;; Set free variable tags-file-name so that next 'find-tag' command uses | 118 ;; Set free variable tags-file-name so that next `find-tag' command uses |
123 ;; whatever tags file is set here. | 119 ;; whatever tags file is set here. |
124 (setq tags-file-name (smart-tags-file buffer-file-name)) | 120 (setq tags-file-name (smart-tags-file buffer-file-name)) |
125 (message "Looking for '%s' in '%s'..." tag tags-file-name) | 121 (message "Looking for `%s' in `%s'..." tag tags-file-name) |
126 (condition-case () | 122 (condition-case () |
127 (progn | 123 (progn |
128 (funcall (if (br-in-browser) | 124 (smart-tags-display tag next) |
129 'find-tag 'find-tag-other-window) | 125 (message "Found definition for `%s'." tag)) |
130 tag next) | 126 (error (message "`%s' not found in `%s'." tag tags-file-name) |
131 (message "Found definition for '%s'." tag)) | |
132 (error (message "'%s' not found in '%s'." tag tags-file-name) | |
133 (beep)))))) | 127 (beep)))))) |
134 | 128 |
135 ;;;###autoload | 129 ;;;###autoload |
136 (defun smart-asm-at-tag-p () | 130 (defun smart-asm-at-tag-p () |
137 "Return assembly tag name that point is within, else nil." | 131 "Return assembly tag name that point is within, else nil." |
138 (let* ((identifier-chars "_.$a-zA-Z0-9") | 132 (let* ((identifier-chars "_.$a-zA-Z0-9") |
139 (identifier (concat "[_.$a-zA-Z][" identifier-chars "]*"))) | 133 (identifier (concat "[_.$a-zA-Z][" identifier-chars "]*"))) |
140 (save-excursion | 134 (save-excursion |
141 (skip-chars-backward identifier-chars) | 135 (skip-chars-backward identifier-chars) |
142 (if (looking-at identifier) | 136 (if (looking-at identifier) |
143 (buffer-substring (point) (match-end 0)))))) | 137 (smart-flash-tag |
138 (buffer-substring (point) (match-end 0)) | |
139 (point) (match-end 0)))))) | |
140 | |
141 (defun smart-c (&optional identifier next) | |
142 "Jumps to the definition of optional C IDENTIFIER or the one at point. | |
143 Optional second arg NEXT means jump to next matching C tag. | |
144 | |
145 It assumes that its caller has already checked that the key was pressed in an | |
146 appropriate buffer and has moved the cursor to the selected buffer. | |
147 | |
148 If: | |
149 (1) on a `#include' statement, the include file is displayed; | |
150 Look for include file in directory lists `smart-c-cpp-include-dirs' | |
151 and `smart-c-include-dirs'. | |
152 (2) on a C identifier, the identifier definition is displayed, | |
153 assuming the identifier is found within an `etags' generated tag file | |
154 in the current directory or any of its ancestor directories. | |
155 (3) if `smart-c-use-lib-man' is non-nil, the C identifier is | |
156 recognized as a library symbol, and a man page is found for the | |
157 identifier, then the man page is displayed." | |
158 | |
159 (interactive) | |
160 (or | |
161 (if identifier nil (smart-c-include-file)) | |
162 (let ((tag (or identifier (smart-c-at-tag-p)))) | |
163 ;; Set free variable tags-file-name so that next `find-tag' command uses | |
164 ;; whatever tags file is set here. | |
165 (setq tags-file-name (smart-tags-file buffer-file-name)) | |
166 (message "Looking for `%s' in `%s'..." tag tags-file-name) | |
167 (condition-case () | |
168 (progn | |
169 (smart-tags-display tag next) | |
170 (message "Found definition for `%s'." tag)) | |
171 (error | |
172 (if (not smart-c-use-lib-man) | |
173 (progn (message "`%s' not found in `%s'." tag tags-file-name) | |
174 (beep)) | |
175 (message "Checking if `%s' is a C library function..." tag) | |
176 (if (smart-library-symbol tag) | |
177 (progn (message "Displaying C library man page for `%s'." tag) | |
178 (manual-entry tag)) | |
179 (message "`%s' not found in `%s' or C libraries." | |
180 tag tags-file-name) | |
181 (beep)))))))) | |
182 | |
183 ;;;###autoload | |
184 (defun smart-c-at-tag-p () | |
185 "Return C tag name that point is within, else nil." | |
186 (let* ((identifier-chars "_a-zA-Z0-9") | |
187 (identifier (concat "[_a-zA-Z][" identifier-chars "]*"))) | |
188 (save-excursion | |
189 (skip-chars-backward identifier-chars) | |
190 (if (looking-at identifier) | |
191 (smart-flash-tag | |
192 (buffer-substring (point) (match-end 0)) | |
193 (point) (match-end 0)))))) | |
194 | |
195 ;;;###autoload | |
196 (defun smart-c++ (&optional identifier next) | |
197 "Jumps to the definition of optional C++ IDENTIFIER or the one at point. | |
198 Optional second arg NEXT means jump to next matching C++ tag. | |
199 | |
200 It assumes that its caller has already checked that the key was pressed in an | |
201 appropriate buffer and has moved the cursor to the selected buffer. | |
202 | |
203 If: | |
204 (1) on a `#include' statement, the include file is displayed; | |
205 Look for include file in directory lists `smart-c-cpp-include-dirs' | |
206 and `smart-c-include-dirs'. | |
207 (2) on a C++ identifier, the identifier definition is displayed, | |
208 assuming the identifier is found within an `etags' generated tag file | |
209 in the current directory or any of its ancestor directories. | |
210 (3) if `smart-c-use-lib-man' is non-nil, the C++ identifier is | |
211 recognized as a library symbol, and a man page is found for the | |
212 identifier, then the man page is displayed." | |
213 | |
214 (interactive) | |
215 (if (fboundp 'c++-to-definition) | |
216 ;; Only fboundp if OO-Browser has been loaded. | |
217 (smart-c++-oo-browser) | |
218 (or | |
219 (if identifier nil (smart-c-include-file)) | |
220 (let ((tag (or identifier (smart-c++-at-tag-p)))) | |
221 ;; Set free variable tags-file-name so that next `find-tag' command uses | |
222 ;; whatever tags file is set here. | |
223 (setq tags-file-name (smart-tags-file buffer-file-name)) | |
224 (message "Looking for `%s' in `%s'..." tag tags-file-name) | |
225 (condition-case () | |
226 (progn | |
227 (smart-tags-display tag next) | |
228 (message "Found definition for `%s'." tag)) | |
229 (error | |
230 (if (not smart-c-use-lib-man) | |
231 (progn (message "`%s' not found in `%s'." tag tags-file-name) | |
232 (beep)) | |
233 (message "Checking if `%s' is a C++ library function..." tag) | |
234 (if (smart-library-symbol tag) | |
235 (progn (message "Displaying C++ library man page for `%s'." tag) | |
236 (manual-entry tag)) | |
237 (message "`%s' not found in `%s' or C++ libraries." | |
238 tag tags-file-name) | |
239 (beep))))))))) | |
240 | |
241 ;;; The following should be called only if the OO-Browser is available. | |
242 (defun smart-c++-oo-browser (&optional junk) | |
243 "Jumps to the definition of selected C++ construct via OO-Browser support. | |
244 Optional JUNK is ignored. Does nothing if the OO-Browser is not available. | |
245 | |
246 It assumes that its caller has already checked that the key was pressed in an | |
247 appropriate buffer and has moved the cursor to the selected buffer. | |
248 | |
249 If key is pressed: | |
250 (1) on a `#include' statement, the include file is displayed; | |
251 Look for include file in directory lists `smart-c-cpp-include-dirs' | |
252 and `smart-c-include-dirs'. | |
253 (2) within a method declaration, its definition is displayed; | |
254 (3) on a class name, the class definition is shown. | |
255 | |
256 (2) and (3) require that an OO-Browser Environment has been loaded with | |
257 the {M-x br-env-load RET} command." | |
258 | |
259 (interactive) | |
260 (c++-to-definition t)) | |
261 | |
262 (defun smart-c++-at-tag-p () | |
263 "Return C++ tag name that point is within, else nil." | |
264 (let* ((identifier-chars "_:~<>a-zA-Z0-9") | |
265 (identifier (concat "\\([_~:<a-zA-Z][" identifier-chars "]*" | |
266 "[ \t]*[^]) \t:;.,?~{}][^[( \t:;.,~^!|?{}]?[=*]?\\)[ \t\n]*("))) | |
267 (save-excursion | |
268 (skip-chars-backward identifier-chars) | |
269 (if (looking-at identifier) | |
270 (smart-flash-tag | |
271 (buffer-substring (match-beginning 1) (match-end 1)) | |
272 (match-beginning 1) (match-end 1)))))) | |
273 | |
274 (defun smart-emacs-lisp-mode-p () | |
275 "Return t if in a mode which uses Emacs Lisp symbols." | |
276 (or (memq major-mode '(emacs-lisp-mode lisp-interaction-mode debugger-mode)) | |
277 ;; Emacs Lisp symbols appear in Help buffers frequently. | |
278 (string-match "Help\\*$" (buffer-name)))) | |
279 | |
280 (defun smart-fortran (&optional identifier next) | |
281 "Jumps to the definition of optional Fortran IDENTIFIER or the one at point. | |
282 Optional second arg NEXT means jump to next matching Fortran tag. | |
283 | |
284 It assumes that its caller has already checked that the key was pressed in an | |
285 appropriate buffer and has moved the cursor to the selected buffer. | |
286 | |
287 If on a Fortran identifier, the identifier definition is displayed, | |
288 assuming the identifier is found within an `etags' generated tag file | |
289 in the current directory or any of its ancestor directories." | |
290 (interactive) | |
291 (let ((tag (or identifier (smart-fortran-at-tag-p)))) | |
292 ;; Set free variable tags-file-name so that next `find-tag' command uses | |
293 ;; whatever tags file is set here. | |
294 (setq tags-file-name (smart-tags-file buffer-file-name)) | |
295 (message "Looking for `%s' in `%s'..." tag tags-file-name) | |
296 (condition-case () | |
297 (progn | |
298 (smart-tags-display tag next) | |
299 (message "Found definition for `%s'." tag)) | |
300 (error | |
301 (message "`%s' not found in `%s'." tag tags-file-name) | |
302 (beep))))) | |
303 | |
304 ;;;###autoload | |
305 (defun smart-fortran-at-tag-p () | |
306 "Return Fortran tag name that point is within, else nil." | |
307 (let* ((identifier-chars "_a-zA-Z0-9") | |
308 (identifier (concat "[_a-zA-Z][" identifier-chars "]*"))) | |
309 (save-excursion | |
310 (skip-chars-backward identifier-chars) | |
311 (if (looking-at identifier) | |
312 (smart-flash-tag | |
313 (buffer-substring (point) (match-end 0)) | |
314 (point) (match-end 0)))))) | |
315 | |
316 ;;;###autoload | |
317 (defun smart-java (&optional identifier next) | |
318 "Jumps to the definition of optional Java IDENTIFIER or the one at point. | |
319 Optional second arg NEXT means jump to next matching Java tag. | |
320 | |
321 It assumes that its caller has already checked that the key was pressed in an | |
322 appropriate buffer and has moved the cursor to the selected buffer. | |
323 | |
324 If: | |
325 (1) within a commented @see cross-reference, the referent is displayed; | |
326 (2) on a `package' or `import' statement, the referent is displayed; | |
327 Look for referent files in the directory list `smart-java-package-dirs'. | |
328 (3) on an Java identifier, the identifier definition is displayed, | |
329 assuming the identifier is found within an `etags' generated tag file | |
330 in the current directory or any of its ancestor directories." | |
331 | |
332 (interactive) | |
333 (if (fboundp 'java-to-definition) | |
334 ;; Only fboundp if OO-Browser has been loaded. | |
335 (smart-java-oo-browser) | |
336 (or | |
337 (if identifier nil (or (smart-java-cross-reference) (smart-java-packages))) | |
338 (let ((tag (or identifier (smart-java-at-tag-p)))) | |
339 ;; Set free variable tags-file-name so that next `find-tag' command uses | |
340 ;; whatever tags file is set here. | |
341 (setq tags-file-name (smart-tags-file buffer-file-name)) | |
342 (message "Looking for `%s' in `%s'..." tag tags-file-name) | |
343 (condition-case () | |
344 (progn | |
345 (smart-tags-display tag next) | |
346 (message "Found definition for `%s'." tag)) | |
347 (error (progn (message "`%s' not found in `%s'." tag tags-file-name) | |
348 (beep)))))))) | |
349 | |
350 ;;; The following should be called only if the OO-Browser is available. | |
351 (defun smart-java-oo-browser (&optional junk) | |
352 "Jumps to the definition of selected Java construct via OO-Browser support. | |
353 Optional JUNK is ignored. Does nothing if the OO-Browser is not available. | |
354 | |
355 It assumes that its caller has already checked that the key was pressed in an | |
356 appropriate buffer and has moved the cursor to the selected buffer. | |
357 | |
358 If key is pressed: | |
359 (1) within a commented @see cross-reference, the referent is displayed; | |
360 (2) on a `package' or `import' statement, the referent is displayed; | |
361 Look for referent files in the directory list `smart-java-package-dirs'. | |
362 (3) within a method declaration, its definition is displayed; | |
363 (4) on a class name, the class definition is shown." | |
364 | |
365 (interactive) | |
366 (or (smart-java-cross-reference) | |
367 (smart-java-packages) | |
368 (java-to-definition t))) | |
369 | |
370 ;;;###autoload | |
371 (defun smart-java-at-tag-p () | |
372 "Return Java tag name that point is within, else nil." | |
373 (let* ((identifier-chars "_$.a-zA-Z0-9") | |
374 (identifier | |
375 (concat "[_$a-zA-Z][" identifier-chars "]*"))) | |
376 (save-excursion | |
377 (skip-chars-backward identifier-chars) | |
378 (if (looking-at identifier) | |
379 (smart-flash-tag | |
380 (buffer-substring (point) (match-end 0)) | |
381 (point) (match-end 0)))))) | |
382 | |
383 (defun smart-lisp (&optional next) | |
384 "Jumps to the definition of any selected Lisp construct. | |
385 If on an Emacs Lisp require, load, or autoload clause and `find-library' | |
386 from load-library package by Hallvard Furuseth (hallvard@ifi.uio.no) has | |
387 been loaded, jumps to library source, if possible. | |
388 | |
389 Otherwise, the construct must be found within an `etags' generated tag file | |
390 in the current directory or any of its ancestor directories in order for its | |
391 definition to be located. | |
392 | |
393 Optional NEXT means jump to next matching Lisp tag. When matching to an Emacs | |
394 Lisp tag using `wtags' (Bob Weiner's personal modifications to `etags'), | |
395 there is no next tag, so display documentation for current tag instead. | |
396 | |
397 This command assumes that its caller has already checked that the key was | |
398 pressed in an appropriate buffer and has moved the cursor to the selected | |
399 buffer." | |
400 | |
401 (interactive) | |
402 ;; Handle `require', `load', and `autoload' clauses in Emacs Lisp. | |
403 (or (and (fboundp 'find-library) | |
404 (smart-emacs-lisp-mode-p) | |
405 (let ((req) | |
406 (opoint (point))) | |
407 (setq req (and (search-backward "\(" nil t) | |
408 (looking-at (concat | |
409 "(\\(require\\|load\\|autoload\\)" | |
410 "[ \t]+.*['\"]" | |
411 "\\([^][() \t\n\^M`'\"]+\\)")))) | |
412 (goto-char opoint) | |
413 (if req (progn | |
414 (setq req (buffer-substring (match-beginning 2) | |
415 (match-end 2))) | |
416 (hpath:display-buffer (current-buffer)) | |
417 (find-library req) | |
418 t)))) | |
419 (let ((tag (smart-lisp-at-tag-p))) | |
420 ;; Set free variable tags-file-name so that next `find-tag' command | |
421 ;; uses whatever tags file is set here. | |
422 (setq tags-file-name (smart-tags-file default-directory)) | |
423 ;; This part only works properly for Emacs Lisp, so is conditionalized. | |
424 (if (and next (smart-emacs-lisp-mode-p) (featurep 'wtags)) | |
425 (progn (setq tag (intern tag)) | |
426 (cond ((fboundp tag) (describe-function tag)) | |
427 ((boundp tag) (describe-variable tag)) | |
428 (t (error "(smart-lisp): Unbound symbol: %s" tag)))) | |
429 (condition-case () | |
430 (smart-tags-display tag next) | |
431 (error (if (equal tags-file-name smart-emacs-tags-file) | |
432 (progn (message "`%s' not found in `%s'." | |
433 tag tags-file-name) | |
434 (beep)) | |
435 (setq tags-file-name smart-emacs-tags-file) | |
436 (smart-tags-display tag next)))))))) | |
437 | |
438 (defun smart-lisp-at-tag-p () | |
439 "Returns Lisp tag name that point is within, else nil. | |
440 Returns nil when point is within a Lisp `def' keyword." | |
441 (let* ((identifier-chars "-_*:+%$#!<>a-zA-Z0-9") | |
442 (identifier (concat "[-<*a-zA-Z][" identifier-chars "]*")) | |
443 (opoint (point))) | |
444 (save-excursion | |
445 (beginning-of-line) | |
446 (if (and (looking-at "\\(;*[ \t]*\\)?(def[^- \n\t]+") | |
447 (< opoint (match-end 0))) | |
448 nil | |
449 (goto-char opoint) | |
450 (skip-chars-backward identifier-chars) | |
451 (if (looking-at identifier) | |
452 (smart-flash-tag | |
453 (buffer-substring (point) (match-end 0)) | |
454 (point) (match-end 0))))))) | |
455 | |
456 ;;;###autoload | |
457 (defun smart-lisp-mode-p () | |
458 "Return t if in a mode which uses Lisp symbols." | |
459 (or (smart-emacs-lisp-mode-p) | |
460 (memq major-mode '(lisp-mode scheme-mode)))) | |
461 | |
462 ;;;###autoload | |
463 (defun smart-objc (&optional identifier next) | |
464 "Jumps to the definition of optional Objective-C IDENTIFIER or the one at point. | |
465 Optional second arg NEXT means jump to next matching Objective-C tag. | |
466 | |
467 It assumes that its caller has already checked that the key was pressed in an | |
468 appropriate buffer and has moved the cursor to the selected buffer. | |
469 | |
470 If: | |
471 (1) on a `#include' statement, the include file is displayed; | |
472 Look for include file in directory lists `smart-c-cpp-include-dirs' | |
473 and `smart-c-include-dirs'. | |
474 (2) on an Objective-C identifier, the identifier definition is displayed, | |
475 assuming the identifier is found within an `etags' generated tag file | |
476 in the current directory or any of its ancestor directories. | |
477 (3) if `smart-c-use-lib-man' is non-nil, the Objective-C identifier is | |
478 recognized as a library symbol, and a man page is found for the | |
479 identifier, then the man page is displayed." | |
480 | |
481 (interactive) | |
482 | |
483 (if (fboundp 'objc-to-definition) | |
484 ;; Only fboundp if OO-Browser has been loaded. | |
485 (smart-objc-oo-browser) | |
486 (or | |
487 (if identifier nil (smart-c-include-file)) | |
488 (let ((tag (or identifier (smart-objc-at-tag-p)))) | |
489 ;; Set free variable tags-file-name so that next `find-tag' command uses | |
490 ;; whatever tags file is set here. | |
491 (setq tags-file-name (smart-tags-file buffer-file-name)) | |
492 (message "Looking for `%s' in `%s'..." tag tags-file-name) | |
493 (condition-case () | |
494 (progn | |
495 (smart-tags-display tag next) | |
496 (message "Found definition for `%s'." tag)) | |
497 (error | |
498 (if (not smart-c-use-lib-man) | |
499 (progn (message "`%s' not found in `%s'." tag tags-file-name) | |
500 (beep)) | |
501 (message | |
502 "Checking if `%s' is an Objective-C library function..." tag) | |
503 (if (smart-library-symbol tag) | |
504 (progn | |
505 (message | |
506 "Displaying Objective-C library man page for `%s'." tag) | |
507 (manual-entry tag)) | |
508 (message "`%s' not found in `%s' or Objective-C libraries." | |
509 tag tags-file-name) | |
510 (beep))))))))) | |
511 | |
512 ;;; The following should be called only if the OO-Browser is available. | |
513 (defun smart-objc-oo-browser (&optional junk) | |
514 "Jumps to the definition of selected Objective-C construct via OO-Browser support. | |
515 Optional JUNK is ignored. Does nothing if the OO-Browser is not available. | |
516 | |
517 It assumes that its caller has already checked that the key was pressed in an | |
518 appropriate buffer and has moved the cursor to the selected buffer. | |
519 | |
520 If key is pressed: | |
521 (1) on a `#include' statement, the include file is displayed; | |
522 Look for include file in directory lists `smart-c-cpp-include-dirs' | |
523 and `smart-c-include-dirs'. | |
524 (2) within a method declaration, its definition is displayed; | |
525 (3) on a class name, the class definition is shown. | |
526 | |
527 (2) and (3) require that an OO-Browser Environment has been loaded with | |
528 the {M-x br-env-load RET} command." | |
529 | |
530 (interactive) | |
531 (objc-to-definition t)) | |
532 | |
533 (defun smart-objc-at-tag-p () | |
534 "Return Objective-C tag name that point is within, else nil." | |
535 (let* ((identifier-chars "_a-zA-Z0-9") | |
536 (identifier | |
537 (concat "\\([-+][ \t]*\\)?\\([_a-zA-Z][" identifier-chars "]*\\)"))) | |
538 (save-excursion | |
539 (skip-chars-backward identifier-chars) | |
540 (if (looking-at identifier) | |
541 (smart-flash-tag | |
542 (buffer-substring (match-beginning 2) (match-end 2)) | |
543 (match-beginning 2) (match-end 2)))))) | |
544 | |
545 ;;; ************************************************************************ | |
546 ;;; Private functions | |
547 ;;; ************************************************************************ | |
144 | 548 |
145 (defun smart-asm-include-file () | 549 (defun smart-asm-include-file () |
146 "If point is on an include file line, tries to display file. | 550 "If point is on an include file line, tries to display file. |
147 Returns non-nil iff on an include file line, even if file is not found. | 551 Returns non-nil iff on an include file line, even if file is not found. |
148 Look for include file in 'smart-asm-include-dirs' and add suffix \".ins\" or | 552 Look for include file in `smart-asm-include-dirs' and add suffix \".ins\" or |
149 \".inc\" to filename if it lacks a suffix." | 553 \".inc\" to filename if it lacks a suffix." |
150 (let ((opoint (point))) | 554 (let ((opoint (point))) |
151 ;; Some assemblers utilize the C preprocessor, so try that first. | 555 ;; Some assemblers utilize the C preprocessor, so try that first. |
152 (cond ((smart-c-include-file)) | 556 (cond ((smart-c-include-file)) |
153 ((progn (beginning-of-line) | 557 ((progn (beginning-of-line) |
162 (setq file (regexp-quote file)) | 566 (setq file (regexp-quote file)) |
163 (setq file (concat (regexp-quote file) "\\.in[sc]$"))) | 567 (setq file (concat (regexp-quote file) "\\.in[sc]$"))) |
164 (while dir-list | 568 (while dir-list |
165 (setq dir-list | 569 (setq dir-list |
166 (if (setq path (car (directory-files | 570 (if (setq path (car (directory-files |
167 (car dir-list) t file))) | 571 (car dir-list) t file))) |
168 nil | 572 nil |
169 (cdr dir-list)))) | 573 (cdr dir-list)))) |
170 ;; | 574 ;; |
171 ;; If path exists, display file | 575 ;; If path exists, display file |
172 ;; | 576 ;; |
173 (if path | 577 (if path |
174 (if (and (file-readable-p path) | 578 (if (and (file-readable-p path) |
175 (progn | 579 (progn |
176 (if (br-in-browser) | 580 (hpath:find path) |
177 (find-file path) | |
178 (find-file-other-window path)) | |
179 (cond ((featurep 'asm-mode) t) | 581 (cond ((featurep 'asm-mode) t) |
180 ((load "asm-mode" nil 'nomessage) | 582 ((load "asm-mode" nil 'nomessage) |
181 (provide 'asm-mode)) | 583 (provide 'asm-mode)) |
182 (t | 584 (t |
183 (beep) | 585 (beep) |
184 (message | 586 (message |
185 "(smart-asm-include-file): asm-mode undefined.") | 587 "(smart-asm-include-file): asm-mode undefined.") |
186 nil | 588 nil |
187 )))) | 589 )))) |
188 nil | 590 nil |
189 (beep) | 591 (beep) |
190 (message "(smart-asm-include-file): '%s' unreadable." path)) | 592 (message "(smart-asm-include-file): `%s' unreadable." path)) |
191 (beep) | 593 (beep) |
192 (message "(smart-asm-include-file): '%s' not found." file)) | 594 (message "(smart-asm-include-file): `%s' not found." file)) |
193 path)) | 595 path)) |
194 ;; not on an include file line | 596 ;; not on an include file line |
195 (t (goto-char opoint) | 597 (t (goto-char opoint) |
196 nil)))) | 598 nil)))) |
197 | 599 |
198 | 600 |
199 (defun smart-c (&optional identifier next) | |
200 "Jumps to the definition of optional C IDENTIFIER or the one at point. | |
201 Optional second arg NEXT means jump to next matching C tag. | |
202 | |
203 It assumes that its caller has already checked that the key was pressed in an | |
204 appropriate buffer and has moved the cursor to the selected buffer. | |
205 | |
206 If: | |
207 (1) on a '#include' statement, the include file is displayed; | |
208 Look for include file in directory lists 'smart-c-cpp-include-dirs' | |
209 and 'smart-c-include-dirs'. | |
210 (2) on a C identifier, the identifier definition is displayed, | |
211 assuming the identifier is found within an 'etags' generated tag file | |
212 in the current directory or any of its ancestor directories. | |
213 (3) if 'smart-c-use-lib-man' is non-nil, the C identifier is | |
214 recognized as a library symbol, and a man page is found for the | |
215 identifier, then the man page is displayed." | |
216 | |
217 (interactive) | |
218 (or | |
219 (if identifier nil (smart-c-include-file)) | |
220 (let ((tag (or identifier (smart-c-at-tag-p)))) | |
221 ;; Set free variable tags-file-name so that next 'find-tag' command uses | |
222 ;; whatever tags file is set here. | |
223 (setq tags-file-name (smart-tags-file buffer-file-name)) | |
224 (message "Looking for '%s' in '%s'..." tag tags-file-name) | |
225 (condition-case () | |
226 (progn | |
227 (funcall (if (br-in-browser) | |
228 'find-tag 'find-tag-other-window) | |
229 tag next) | |
230 (message "Found definition for '%s'." tag)) | |
231 (error | |
232 (if (not smart-c-use-lib-man) | |
233 (progn (message "'%s' not found in '%s'." tag tags-file-name) | |
234 (beep)) | |
235 (message "Checking if '%s' is a C library function..." tag) | |
236 (if (smart-library-symbol tag) | |
237 (progn (message "Displaying C library man page for '%s'." tag) | |
238 (manual-entry tag)) | |
239 (message "'%s' not found in '%s' or C libraries." | |
240 tag tags-file-name) | |
241 (beep)))))))) | |
242 | |
243 ;;;###autoload | |
244 (defun smart-c-at-tag-p () | |
245 "Return C tag name that point is within, else nil." | |
246 (let* ((identifier-chars "_a-zA-Z0-9") | |
247 (identifier (concat "[_a-zA-Z][" identifier-chars "]*"))) | |
248 (save-excursion | |
249 (skip-chars-backward identifier-chars) | |
250 (if (looking-at identifier) | |
251 (buffer-substring (point) (match-end 0)))))) | |
252 | |
253 (defun smart-c-include-file () | 601 (defun smart-c-include-file () |
254 "If point is on an include file line, tries to display file. | 602 "If point is on an include file line, tries to display file. |
255 Returns non-nil iff on an include file line, even if file is not found. | 603 Returns non-nil iff on an include file line, even if file is not found. |
256 Look for include file in 'smart-c-cpp-include-dirs' and in directory list | 604 Look for include file in `smart-c-cpp-include-dirs' and in directory list |
257 'smart-c-include-dirs'." | 605 `smart-c-include-dirs'." |
258 (let ((opoint (point))) | 606 (let ((opoint (point))) |
259 (beginning-of-line) | 607 (beginning-of-line) |
260 (if (looking-at smart-c-include-regexp) | 608 (if (looking-at smart-c-include-regexp) |
261 (let ((incl-type (string-to-char | 609 (let ((incl-type (string-to-char |
262 (buffer-substring (match-beginning 2) | 610 (buffer-substring (match-beginning 2) |
279 ;; If found, display file | 627 ;; If found, display file |
280 ;; | 628 ;; |
281 (if found | 629 (if found |
282 (if (and (file-readable-p path) | 630 (if (and (file-readable-p path) |
283 (progn | 631 (progn |
284 (if (br-in-browser) | 632 (hpath:find path) |
285 (find-file path) | |
286 (find-file-other-window path)) | |
287 (cond ((or (featurep 'cc-mode) | 633 (cond ((or (featurep 'cc-mode) |
288 (featurep 'c-mode)) | 634 (featurep 'c-mode)) |
289 t) | 635 t) |
290 ((or (load "cc-mode" 'missing-ok 'nomessage) | 636 ((or (load "cc-mode" 'missing-ok 'nomessage) |
291 (load "c-mode" 'missing-ok 'nomessage)) | 637 (load "c-mode" 'missing-ok 'nomessage)) |
296 "(smart-c-include-file): c-mode undefined.") | 642 "(smart-c-include-file): c-mode undefined.") |
297 nil | 643 nil |
298 )))) | 644 )))) |
299 nil | 645 nil |
300 (beep) | 646 (beep) |
301 (message "(smart-c-include-file): '%s' unreadable." path)) | 647 (message "(smart-c-include-file): `%s' unreadable." path)) |
302 (beep) | 648 (beep) |
303 (message "(smart-c-include-file): '%s' not found." file)) | 649 (message "(smart-c-include-file): `%s' not found." file)) |
304 path) | 650 path) |
305 (goto-char opoint) | 651 (goto-char opoint) |
306 nil))) | 652 nil))) |
307 | 653 |
308 | 654 (defun smart-flash-tag (tag start end) |
309 ;;;###autoload | 655 "Tries to flash TAG at START to END in buffer, to indicate that it is serving as a hyperlink button. |
310 (defun smart-c++ (&optional identifier next) | 656 Returns TAG." |
311 "Jumps to the definition of optional C++ IDENTIFIER or the one at point. | 657 ;; Button flashing code might not yet have been loaded if the whole |
312 Optional second arg NEXT means jump to next matching C++ tag. | 658 ;; Hyperbole system has not been started. |
313 | 659 (if (fboundp 'hui:but-flash) |
314 It assumes that its caller has already checked that the key was pressed in an | 660 (progn |
315 appropriate buffer and has moved the cursor to the selected buffer. | 661 (ibut:label-set tag start end) |
316 | 662 (hui:but-flash))) |
317 If: | 663 tag) |
318 (1) on a '#include' statement, the include file is displayed; | 664 |
319 Look for include file in directory lists 'smart-c-cpp-include-dirs' | 665 (defun smart-java-cross-reference () |
320 and 'smart-c-include-dirs'. | 666 "If within a Java @see comment, displays the associated definition for editing and returns non-nil, else nil. |
321 (2) on a C++ identifier, the identifier definition is displayed, | 667 Non-nil is returned even if the @see referent cannot be found. |
322 assuming the identifier is found within an 'etags' generated tag file | 668 |
323 in the current directory or any of its ancestor directories. | 669 Does nothing if the `oo-browser' command is undefined, since it requires that |
324 (3) if 'smart-c-use-lib-man' is non-nil, the C++ identifier is | 670 package for class and feature lookups." |
325 recognized as a library symbol, and a man page is found for the | 671 ;; |
326 identifier, then the man page is displayed." | 672 ;; Valid forms of @see cross-references are: |
327 | 673 ;; * @see #getComponent - current class attribute |
328 (interactive) | 674 ;; * @see #waitForAll() - current class method, no arguments |
329 (or | 675 ;; * @see #checkID(int, boolean) - current class method, with arguments |
330 (if identifier nil (smart-c-include-file)) | 676 ;; * @see java.awt.ColorModel#getRGBdefault - library class method |
331 (let ((tag (or identifier (smart-c++-at-tag-p)))) | 677 ;; * @see Component#paintAll - class method |
332 ;; Set free variable tags-file-name so that next 'find-tag' command uses | 678 ;; * @see java.awt.GridBagLayout - library class |
333 ;; whatever tags file is set here. | 679 ;; * @see Container - class |
334 (setq tags-file-name (smart-tags-file buffer-file-name)) | 680 ;; |
335 (message "Looking for '%s' in '%s'..." tag tags-file-name) | 681 ;; For simplicity sake, this code ignores the library path given with any |
336 (condition-case () | 682 ;; class in favor of the OO-Browser's lookup tables. It also ignores any |
337 (progn | 683 ;; parameters associated with a method, and thus cannot distinguish between |
338 (funcall (if (br-in-browser) | 684 ;; methods with the same name within a single class, which we believe to be |
339 'find-tag 'find-tag-other-window) | 685 ;; fairly bad form anyway. |
340 tag next) | 686 ;; |
341 (message "Found definition for '%s'." tag)) | 687 (let ((opoint (point))) |
342 (error | 688 (if (and (eq major-mode 'java-mode) buffer-file-name |
343 (if (not smart-c-use-lib-man) | 689 (fboundp 'br-env-load) |
344 (progn (message "'%s' not found in '%s'." tag tags-file-name) | 690 (or (looking-at "@see[ \t]+") |
345 (beep)) | 691 (and (re-search-backward "[@\n\r\f]" nil t) |
346 (message "Checking if '%s' is a C++ library function..." tag) | 692 (looking-at "@see[ \t]+")))) |
347 (if (smart-library-symbol tag) | 693 (let ((class) (feature)) |
348 (progn (message "Displaying C++ library man page for '%s'." tag) | 694 ;; Ignore any library path preceding a classname (grouping 1) |
349 (manual-entry tag)) | 695 (cond |
350 (message "'%s' not found in '%s' or C++ libraries." | 696 ((looking-at |
351 tag tags-file-name) | 697 "@see[ \t]+\\(#\\)?\\([^][(){} \t\n\r\f#]+[.]\\)?\\([^][(){} \t\n\r\f#.]+\\)[][(){} \t\n\r\f]") |
352 (beep)))))))) | 698 (if (match-beginning 1) |
353 | 699 (setq class nil |
354 ;;; The following should be called only if the OO-Browser is available. | 700 feature (buffer-substring (match-beginning 3) |
355 ;;;###autoload | 701 (match-end 3))) |
356 (defun smart-c++-oobr (&optional junk) | 702 (setq class (buffer-substring (match-beginning 3) (match-end 3)) |
357 "Jumps to the definition of selected C++ construct via OO-Browser support. | 703 feature nil))) |
358 Optional JUNK is ignored. Does nothing if the OO-Browser is not available. | 704 ((looking-at |
359 | 705 "@see[ \t]+\\([^][(){} \t\n\r\f#]+[.]\\)?\\([^][(){} \t\n\r\f#.]+\\)#\\([^][(){} \t\n\r\f#.]+\\)") |
360 It assumes that its caller has already checked that the key was pressed in an | 706 (setq class (buffer-substring (match-beginning 2) |
361 appropriate buffer and has moved the cursor to the selected buffer. | 707 (match-end 2)) |
362 | 708 feature (buffer-substring (match-beginning 3) |
363 If key is pressed: | 709 (match-end 3))))) |
364 (1) on a '#include' statement, the include file is displayed; | 710 ;; Return to original point. |
365 Look for include file in directory lists 'smart-c-cpp-include-dirs' | 711 (goto-char opoint) |
366 and 'smart-c-include-dirs'. | 712 ;; Lookup class / feature. |
367 (2) within a method declaration, its definition is displayed; | 713 (cond |
368 (3) on a class name, the class definition is shown. | 714 ((and (null class) (null feature)) |
369 | 715 ;; Invalid or unrecognized @see format, so ignore. |
370 (2) and (3) require that an OO-Browser Environment has been loaded with | 716 (message "(smart-java-cross-reference): Invalid @see cross-reference format.") |
371 the {M-x br-env-load RTN} command." | 717 (beep) |
372 | 718 t) |
373 (interactive) | 719 ;; Ensure that a Java OO-Browser environment has been loaded. |
374 (c++-to-definition 'other-win)) | 720 (t (if (or (and (boundp 'br-lang-prefix) |
375 | 721 (equal br-lang-prefix "java-") |
376 (defun smart-c++-at-tag-p () | 722 (boundp 'br-env-file) (stringp br-env-file) |
377 "Return C++ tag name that point is within, else nil." | 723 (null br-env-spec)) |
378 (let* ((identifier-chars "_:~<>a-zA-Z0-9") | 724 ;; Load an existing Environment based on current |
379 (identifier (concat "\\([_~:<a-zA-Z][" identifier-chars "]*" | 725 ;; buffer or prompt to build one. This also |
380 "[ \t]*[^]) \t:;.,?~{}][^[( \t:;.,~^!|?{}]?[=*]?\\)[ \t\n]*("))) | 726 ;; loads the "br-java.el" library in which the |
381 (save-excursion | 727 ;; `java-class-def-regexp' variable used below |
382 (skip-chars-backward identifier-chars) | 728 ;; is defined. |
383 (if (looking-at identifier) | 729 (and (br-env-load |
384 (buffer-substring (point) (match-end 1)))))) | 730 (smart-tags-file |
385 | 731 buffer-file-name |
386 (defun smart-emacs-lisp-mode-p () | 732 (if (boundp 'br-env-default-file) |
387 "Return t if in a mode which uses Emacs Lisp symbols." | 733 br-env-default-file "OOBR"))) |
388 (or (eq major-mode 'emacs-lisp-mode) | 734 (equal br-lang-prefix "java-"))) |
389 (eq major-mode 'lisp-interaction-mode) | 735 (cond ((null feature) |
390 (eq major-mode 'debugger-mode) | 736 (br-edit nil class)) |
391 ;; Emacs Lisp symbols appear in Help buffers frequently. | 737 (t |
392 (string-match "Help\\*$" (buffer-name)))) | 738 (if (null class) |
393 | 739 (if (save-excursion |
394 (defun smart-fortran (&optional identifier next) | 740 (or (re-search-backward java-class-def-regexp nil t) |
395 "Jumps to the definition of optional Fortran IDENTIFIER or the one at point. | 741 (re-search-forward java-class-def-regexp nil t))) |
396 Optional second arg NEXT means jump to next matching Fortran tag. | 742 (setq class (buffer-substring |
397 | 743 (match-beginning java-class-def-name-grpn) |
398 It assumes that its caller has already checked that the key was pressed in an | 744 (match-end java-class-def-name-grpn))) |
399 appropriate buffer and has moved the cursor to the selected buffer. | 745 (error "(smart-java-cross-reference): This @see must be in a class definition."))) |
400 | 746 (br-edit-feature class feature t))) |
401 If on a Fortran identifier, the identifier definition is displayed, | 747 (error "(smart-java-cross-reference): The OO-Browser failed to load a Java environment."))))) |
402 assuming the identifier is found within an 'etags' generated tag file | 748 ;; Return to original point. |
403 in the current directory or any of its ancestor directories." | 749 (goto-char opoint) |
404 (interactive) | 750 nil))) |
405 (let ((tag (or identifier (smart-fortran-at-tag-p)))) | 751 |
406 ;; Set free variable tags-file-name so that next 'find-tag' command uses | 752 (defun smart-java-library-path (library-name) |
407 ;; whatever tags file is set here. | 753 "Search up directory tree from current directory for a match to LIBRARY-NAME." |
408 (setq tags-file-name (smart-tags-file buffer-file-name)) | 754 (let ((path default-directory) |
409 (message "Looking for '%s' in '%s'..." tag tags-file-name) | 755 (library-path) |
410 (condition-case () | 756 (library-regexp (if (string-match "\\.\\|'//" library-name) |
411 (progn | 757 (regexp-quote |
412 (funcall (if (br-in-browser) | 758 (concat (file-name-as-directory "") |
413 'find-tag 'find-tag-other-window) | 759 (substring library-name 0 (match-beginning 0)) |
414 tag next) | 760 (file-name-as-directory ""))))) |
415 (message "Found definition for '%s'." tag)) | 761 (start 0)) |
416 (error | 762 ;; Return rightmost match to first part of library-name. |
417 (message "'%s' not found in '%s'." tag tags-file-name) | 763 (if library-regexp |
418 (beep))))) | 764 (while (string-match library-regexp path start) |
419 | 765 (setq start (1+ (match-beginning 0)) |
420 ;;;###autoload | 766 library-path (substring path 0 (match-beginning 0))))) |
421 (defun smart-fortran-at-tag-p () | 767 library-path)) |
422 "Return Fortran tag name that point is within, else nil." | 768 |
423 (let* ((identifier-chars "_a-zA-Z0-9") | 769 (defun smart-java-packages () |
424 (identifier (concat "[_a-zA-Z][" identifier-chars "]*"))) | 770 "If point is on a `package' or `import' line, this tries to display the associated referent. |
425 (save-excursion | 771 Returns non-nil iff on such a line, even if the referent is not found. |
426 (skip-chars-backward identifier-chars) | 772 Look for packages in `smart-java-package-dirs'." |
427 (if (looking-at identifier) | 773 (let ((opoint (point))) |
428 (buffer-substring (point) (match-end 0)))))) | 774 (beginning-of-line) |
429 | 775 (if (looking-at smart-java-package-regexp) |
430 (defun smart-lisp (&optional next) | 776 (let ((keyword-type (buffer-substring |
431 "Jumps to the definition of any selected Lisp construct. | 777 (match-beginning 1) (match-end 1))) |
432 If on an Emacs Lisp require, load, or autoload clause and 'find-library' | 778 (referent (buffer-substring (match-beginning 2) (match-end 2))) |
433 from load-library package by Hallvard Furuseth (hallvard@ifi.uio.no) has | 779 (found) |
434 been loaded, jumps to library source, if possible. | 780 (subpath) |
435 | 781 dir-list path subfile) |
436 Otherwise, the construct must be found within an 'etags' generated tag file | 782 (goto-char opoint) |
437 in the current directory or any of its ancestor directories in order for its | 783 (if (string-equal keyword-type "package") |
438 definition to be located. | 784 (let ((library-path (smart-java-library-path referent))) |
439 | 785 (if library-path |
440 Optional NEXT means jump to next matching Lisp tag. When matching to an Emacs | 786 (hpath:find (expand-file-name |
441 Lisp tag using 'wtags' (Bob Weiner's personal modifications to 'etags'), | 787 (hypb:replace-match-string |
442 there is no next tag, so display documentation for current tag instead. | 788 "\\." referent (file-name-as-directory "") t) |
443 | 789 library-path)) |
444 This command assumes that its caller has already checked that the key was | 790 ;; Show the current directory, which should contain this package. |
445 pressed in an appropriate buffer and has moved the cursor to the selected | 791 (hpath:find default-directory))) |
446 buffer." | 792 ;; This is an `import' statement. If it includes a *, show the |
447 | 793 ;; associated library directory, otherwise, show the specific |
448 (interactive) | 794 ;; package. |
449 ;; Handle 'require', 'load', and 'autoload' clauses in Emacs Lisp. | 795 (if (string-match "\\.\\*" referent) |
450 (or (and (fboundp 'find-library) | 796 (setq subfile (substring referent 0 (match-beginning 0)) |
451 (smart-emacs-lisp-mode-p) | 797 subfile (hypb:replace-match-string |
452 (let ((req) | 798 "\\." subfile (file-name-as-directory "") t)) |
453 (opoint (point))) | 799 (setq subpath (hypb:replace-match-string |
454 (setq req (and (search-backward "\(" nil t) | 800 "\\." referent (file-name-as-directory "") t) |
455 (looking-at (concat | 801 subfile (concat subpath ".java"))) |
456 "(\\(require\\|load\\|autoload\\)" | 802 ;; |
457 "[ \t]+.*['\"]" | 803 ;; Try to find the path containing referent. |
458 "\\([^][() \t\n\^M`'\"]+\\)")))) | 804 ;; |
459 (goto-char opoint) | 805 ;; Search up the current directory tree for a possible matching |
460 (if req (progn | 806 ;; directory below which the referent library might live and add |
461 (setq req (buffer-substring (match-beginning 2) | 807 ;; this to smart-java-package-dirs for searching. |
462 (match-end 2))) | 808 (let ((library-path (smart-java-library-path referent))) |
463 (pop-to-buffer nil t) | 809 (if library-path |
464 (find-library req) | 810 (setq dir-list (cons library-path smart-java-package-dirs)))) |
465 t)))) | 811 |
466 (let ((tag (smart-lisp-at-tag-p))) | 812 (while dir-list |
467 ;; Set free variable tags-file-name so that next 'find-tag' command | 813 (setq path (expand-file-name subfile (car dir-list)) |
468 ;; uses whatever tags file is set here. | 814 dir-list (if (setq found (file-exists-p path)) |
469 (setq tags-file-name (smart-tags-file default-directory)) | 815 nil |
470 ;; This part only works properly for Emacs Lisp, so is conditionalized. | 816 (cdr dir-list)))) |
471 (if (and next (smart-emacs-lisp-mode-p) (featurep 'wtags)) | 817 (if (and (not found) subpath hyperb:microcruft-os-p) |
472 (progn (setq tag (intern tag)) | 818 ;; Try .jav suffix. |
473 (cond ((fboundp tag) (describe-function tag)) | 819 (progn (setq subfile (concat subpath ".jav") |
474 ((boundp tag) (describe-variable tag)) | 820 dir-list smart-java-package-dirs) |
475 (t (error "(smart-lisp): Unbound symbol: %s" tag)))) | 821 (while dir-list |
476 (condition-case () | 822 (setq path (expand-file-name subfile (car dir-list)) |
477 (funcall (if (br-in-browser) | 823 dir-list (if (setq found (file-exists-p path)) |
478 'find-tag 'find-tag-other-window) | 824 nil |
479 tag next) | 825 (cdr dir-list)))))) |
480 (error (if (equal tags-file-name smart-emacs-tags-file) | 826 ;; |
481 nil | 827 ;; If found, display file |
482 (setq tags-file-name smart-emacs-tags-file) | 828 ;; |
483 (funcall (if (br-in-browser) | 829 (if found |
484 'find-tag 'find-tag-other-window) | 830 (if (file-readable-p path) |
485 tag next)))))))) | 831 (hpath:find path) |
486 | 832 (beep) |
487 (defun smart-lisp-at-tag-p () | 833 (message "(smart-java-packages): `%s' unreadable." path)) |
488 "Returns Lisp tag name that point is within, else nil. | 834 (beep) |
489 Returns nil when point is on the first line of a 'def' form past the first 4 | 835 (message "(smart-java-packages): `%s' not found." referent)) |
490 characters." | 836 path)) |
491 (let* ((identifier-chars "-_*:+%$#!<>a-zA-Z0-9") | 837 (goto-char opoint) |
492 (identifier (concat "[-<*a-zA-Z][" identifier-chars "]*")) | 838 nil))) |
493 (opoint (point))) | |
494 (save-excursion | |
495 (beginning-of-line) | |
496 (if (and (looking-at "\\(;*[ \t]*\\)?(def[^- \n\t]+[ \n\t]") | |
497 (> opoint (match-end 0))) | |
498 nil | |
499 (goto-char opoint) | |
500 (skip-chars-backward identifier-chars) | |
501 (if (looking-at identifier) | |
502 (buffer-substring (point) (match-end 0))))))) | |
503 | |
504 (defun smart-lisp-mode-p () | |
505 "Return t if in a mode which uses Lisp symbols." | |
506 (or (smart-emacs-lisp-mode-p) | |
507 (eq major-mode 'lisp-mode) | |
508 (eq major-mode 'scheme-mode))) | |
509 | |
510 ;;;###autoload | |
511 (defun smart-objc (&optional identifier next) | |
512 "Jumps to the definition of optional Objective-C IDENTIFIER or the one at point. | |
513 Optional second arg NEXT means jump to next matching Objective-C tag. | |
514 | |
515 It assumes that its caller has already checked that the key was pressed in an | |
516 appropriate buffer and has moved the cursor to the selected buffer. | |
517 | |
518 If: | |
519 (1) on a '#include' statement, the include file is displayed; | |
520 Look for include file in directory lists 'smart-c-cpp-include-dirs' | |
521 and 'smart-c-include-dirs'. | |
522 (2) on an Objective-C identifier, the identifier definition is displayed, | |
523 assuming the identifier is found within an 'etags' generated tag file | |
524 in the current directory or any of its ancestor directories. | |
525 (3) if 'smart-c-use-lib-man' is non-nil, the Objective-C identifier is | |
526 recognized as a library symbol, and a man page is found for the | |
527 identifier, then the man page is displayed." | |
528 | |
529 (interactive) | |
530 (or | |
531 (if identifier nil (smart-c-include-file)) | |
532 (let ((tag (or identifier (smart-objc-at-tag-p)))) | |
533 ;; Set free variable tags-file-name so that next 'find-tag' command uses | |
534 ;; whatever tags file is set here. | |
535 (setq tags-file-name (smart-tags-file buffer-file-name)) | |
536 (message "Looking for '%s' in '%s'..." tag tags-file-name) | |
537 (condition-case () | |
538 (progn | |
539 (funcall (if (br-in-browser) | |
540 'find-tag 'find-tag-other-window) | |
541 tag next) | |
542 (message "Found definition for '%s'." tag)) | |
543 (error | |
544 (if (not smart-c-use-lib-man) | |
545 (progn (message "'%s' not found in '%s'." tag tags-file-name) | |
546 (beep)) | |
547 (message | |
548 "Checking if '%s' is an Objective-C library function..." tag) | |
549 (if (smart-library-symbol tag) | |
550 (progn | |
551 (message | |
552 "Displaying Objective-C library man page for '%s'." tag) | |
553 (manual-entry tag)) | |
554 (message "'%s' not found in '%s' or Objective-C libraries." | |
555 tag tags-file-name) | |
556 (beep)))))))) | |
557 | |
558 ;;; The following should be called only if the OO-Browser is available. | |
559 ;;;###autoload | |
560 (defun smart-objc-oobr (&optional junk) | |
561 "Jumps to the definition of selected Objective-C construct via OO-Browser support. | |
562 Optional JUNK is ignored. Does nothing if the OO-Browser is not available. | |
563 | |
564 It assumes that its caller has already checked that the key was pressed in an | |
565 appropriate buffer and has moved the cursor to the selected buffer. | |
566 | |
567 If key is pressed: | |
568 (1) on a '#include' statement, the include file is displayed; | |
569 Look for include file in directory lists 'smart-c-cpp-include-dirs' | |
570 and 'smart-c-include-dirs'. | |
571 (2) within a method declaration, its definition is displayed; | |
572 (3) on a class name, the class definition is shown. | |
573 | |
574 (2) and (3) require that an OO-Browser Environment has been loaded with | |
575 the {M-x br-env-load RTN} command." | |
576 | |
577 (interactive) | |
578 (objc-to-definition 'other-win)) | |
579 | |
580 (defun smart-objc-at-tag-p () | |
581 "Return Objective-C tag name that point is within, else nil." | |
582 (let* ((identifier-chars "_a-zA-Z0-9") | |
583 (identifier | |
584 (concat "\\([-+][ \t]*\\)?\\([_a-zA-Z][" identifier-chars "]*\\)"))) | |
585 (save-excursion | |
586 (skip-chars-backward identifier-chars) | |
587 (if (looking-at identifier) | |
588 (buffer-substring (match-beginning 2) (match-end 2)))))) | |
589 | |
590 ;;; ************************************************************************ | |
591 ;;; Private functions | |
592 ;;; ************************************************************************ | |
593 | 839 |
594 (defun smart-library-symbol (tag) | 840 (defun smart-library-symbol (tag) |
595 "Return non-nil if TAG is a library symbol listed in cache of such symbols. | 841 "Return non-nil if TAG is a library symbol listed in cache of such symbols. |
596 See the \"${hyperb:dir}/smart-clib-sym\" script for more information." | 842 See the \"${hyperb:dir}/smart-clib-sym\" script for more information." |
597 (let ((buf (get-buffer-create "*junk*")) | 843 (let ((buf (get-buffer-create "*junk*")) |
604 nil buf nil tag) | 850 nil buf nil tag) |
605 (setq found (string-equal (buffer-substring 1 2) "1")) | 851 (setq found (string-equal (buffer-substring 1 2) "1")) |
606 (set-buffer-modified-p nil) | 852 (set-buffer-modified-p nil) |
607 (kill-buffer buf) | 853 (kill-buffer buf) |
608 found))) | 854 found))) |
855 | |
856 (defun smart-tags-display (tag next) | |
857 (if next (setq tag nil)) | |
858 (let ((func (or (if (fboundp 'find-tag-internal) 'find-tag-internal) | |
859 (if (fboundp 'find-tag-noselect) 'find-tag-noselect))) | |
860 ;; For XEmacs | |
861 (tags-always-exact t) | |
862 ;; For Emacs 19 | |
863 (find-tag-tag-order (if (boundp 'find-tag-tag-order) | |
864 find-tag-tag-order))) | |
865 (if find-tag-tag-order | |
866 (if next nil (setq find-tag-tag-order '(tag-exact-match-p))) | |
867 ;; For InfoDock (XEmacs may also take this branch), force exact match. | |
868 (if (stringp tag) (setq tag (list tag)))) | |
869 (if (and func (funcall func tag)) | |
870 (hpath:display-buffer (current-buffer))) | |
871 ;; Signals an error if tag is not found which is caught by many callers | |
872 ;; of this function. | |
873 (find-tag tag))) | |
609 | 874 |
610 ;;;###autoload | 875 ;;;###autoload |
611 (defun smart-tags-file-path (file) | 876 (defun smart-tags-file-path (file) |
612 "Expand relative FILE name by looking it up in the nearest tags file. | 877 "Expand relative FILE name by looking it up in the nearest tags file. |
613 Return FILE unchanged if it exists relative to the current directory or | 878 Return FILE unchanged if it exists relative to the current directory or |
626 (progn (beginning-of-line) | 891 (progn (beginning-of-line) |
627 (point)))))))))) | 892 (point)))))))))) |
628 file)) | 893 file)) |
629 | 894 |
630 ;;;###autoload | 895 ;;;###autoload |
631 (defun smart-tags-file (curr-filename) | 896 (defun smart-tags-file (curr-filename &optional name-of-tags-file) |
632 "Return appropriate tags file name for CURR-FILENAME or 'tags-file-name'." | 897 "Return appropriate tags file name for CURR-FILENAME or `tags-file-name'. |
898 Optional NAME-OF-TAGS-FILE is the literal filename for which to look." | |
633 (let ((path curr-filename) | 899 (let ((path curr-filename) |
634 (tags-file)) | 900 (tags-file)) |
635 (while (and | 901 (while (and |
636 (stringp path) | 902 (stringp path) |
637 (setq path (file-name-directory path)) | 903 (setq path (file-name-directory path)) |
638 (setq path (directory-file-name path)) | 904 (setq path (directory-file-name path)) |
639 ;; Not at root directory | 905 ;; Not at root directory |
640 (not (string-match ":?/\\'" path)) | 906 (not (string-match ":?/\\'" path)) |
641 ;; No tags file | 907 ;; No tags file |
642 (not (file-exists-p | 908 (not (file-exists-p |
643 (setq tags-file (expand-file-name "TAGS" path))))) | 909 (setq tags-file (expand-file-name (or name-of-tags-file "TAGS") path))))) |
644 (setq tags-file nil)) | 910 (setq tags-file nil)) |
645 (if (and (not tags-file) | 911 (if (and (not tags-file) |
646 (stringp curr-filename) | 912 (stringp curr-filename) |
647 (smart-emacs-lisp-mode-p) | 913 (smart-emacs-lisp-mode-p) |
648 (let ((path (file-name-directory curr-filename))) | 914 (let ((path (file-name-directory curr-filename))) |