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