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)))