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