Mercurial > hg > xemacs-beta
comparison lisp/hyperbole/hmouse-tag.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 4103f0995bd7 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;!emacs | |
2 ;; | |
3 ;; FILE: hmouse-tag.el | |
4 ;; SUMMARY: Smart Key support of programming language tags location. | |
5 ;; USAGE: GNU Emacs Lisp Library | |
6 ;; KEYWORDS: c, hypermedia, mouse, oop, tools | |
7 ;; | |
8 ;; AUTHOR: Bob Weiner | |
9 ;; ORG: Brown U. | |
10 ;; | |
11 ;; ORIG-DATE: 24-Aug-91 | |
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 | |
31 ;;; ************************************************************************ | |
32 ;;; Other required Elisp libraries | |
33 ;;; ************************************************************************ | |
34 | |
35 (if (cond ((or (featurep 'etags) (featurep 'tags)) | |
36 nil) | |
37 ((or hyperb:lemacs-p hyperb:emacs19-p) | |
38 ;; Force use of .elc file here since otherwise the bin/etags | |
39 ;; executable might be found in a user's load-path by the load | |
40 ;; command. | |
41 (or (load "etags.elc" t nil t) | |
42 (load "tags-fix" t))) | |
43 ((load "tags" t))) | |
44 (provide 'tags)) | |
45 | |
46 ;;; ************************************************************************ | |
47 ;;; Public variables | |
48 ;;; ************************************************************************ | |
49 | |
50 (defvar smart-asm-include-dirs nil | |
51 "*Ordered list of directories to search for assembly language include files. | |
52 Each directory must end with a directory separator.") | |
53 | |
54 (defconst smart-asm-include-regexp | |
55 "[ \t*#|;]*\\(include\\|lib\\)[ \t]+\\([^ \t\n\^M]+\\)" | |
56 "Regexp to match to assembly language include file lines. | |
57 Include keyword matched is grouping 1. File name is grouping 2 but may be | |
58 missing its suffix, so add \".ins\" or \".inc\" if need be. | |
59 Examples include: | |
60 INCLUDE GLOBALS | |
61 should jump to file \"globals.ins\" | |
62 lib conditionals_equ.inc | |
63 should include \"conditionals_equ.inc\"") | |
64 | |
65 (defvar smart-c-cpp-include-dirs '("/usr/include/") | |
66 "*Ordered list of include directories by default searched by C/C++ preprocessor. | |
67 Each directory must end with a directory separator. See also | |
68 'smart-c-include-dirs'.") | |
69 | |
70 (defvar smart-c-include-dirs nil | |
71 "*Ordered list of directories to search for C/C++ include files. | |
72 Each directory must end with a directory separator. Directories normally | |
73 searched by the C/C++ pre-processor should be set instead in | |
74 'smart-c-cpp-include-dirs'.") | |
75 | |
76 (defvar smart-c-use-lib-man nil | |
77 "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 | |
79 TAGS file. | |
80 | |
81 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. | |
83 Your MANPATH environment variable must include paths for the man pages of | |
84 these libraries also. | |
85 | |
86 Your smart-clib-sym executable script must output a 1 if a symbol is from a | |
87 C/C++ library listed in ~/.CLIBS-LIST or 0 if not! Otherwise, don't set this | |
88 variable to t.") | |
89 | |
90 (defconst smart-c-include-regexp | |
91 "[ \t/*]*#[ \t]*\\(include\\|import\\)[ \t]+\\([\"<]\\)\\([^\">]+\\)[\">]" | |
92 "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 | |
94 double quote, or system-related starting with '<' is given by grouping 2. | |
95 File name is grouping 3.") | |
96 | |
97 (defvar smart-emacs-tags-file nil | |
98 "*Full path name of etags file for GNU Emacs source.") | |
99 | |
100 ;;; ************************************************************************ | |
101 ;;; Public functions | |
102 ;;; ************************************************************************ | |
103 | |
104 (defun smart-asm (&optional identifier next) | |
105 "Jumps to the definition of optional assembly IDENTIFIER or the one at point. | |
106 Optional second arg NEXT means jump to next matching assembly tag. | |
107 | |
108 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. | |
110 | |
111 If: | |
112 (1) on an include statement, the include file is displayed; | |
113 Look for include file in directory list 'smart-asm-include-dirs'. | |
114 (2) on an identifier, the identifier definition is displayed, | |
115 assuming the identifier is found within an 'etags' generated tag file | |
116 in the current directory or any of its ancestor directories." | |
117 | |
118 (interactive) | |
119 (or | |
120 (if identifier nil (smart-asm-include-file)) | |
121 (let ((tag (or identifier (smart-asm-at-tag-p)))) | |
122 ;; Set free variable tags-file-name so that next 'find-tag' command uses | |
123 ;; whatever tags file is set here. | |
124 (setq tags-file-name (smart-tags-file buffer-file-name)) | |
125 (message "Looking for '%s' in '%s'..." tag tags-file-name) | |
126 (condition-case () | |
127 (progn | |
128 (funcall (if (br-in-browser) | |
129 'find-tag 'find-tag-other-window) | |
130 tag next) | |
131 (message "Found definition for '%s'." tag)) | |
132 (error (message "'%s' not found in '%s'." tag tags-file-name) | |
133 (beep)))))) | |
134 | |
135 ;;;###autoload | |
136 (defun smart-asm-at-tag-p () | |
137 "Return assembly tag name that point is within, else nil." | |
138 (let* ((identifier-chars "_.$a-zA-Z0-9") | |
139 (identifier (concat "[_.$a-zA-Z][" identifier-chars "]*"))) | |
140 (save-excursion | |
141 (skip-chars-backward identifier-chars) | |
142 (if (looking-at identifier) | |
143 (buffer-substring (point) (match-end 0)))))) | |
144 | |
145 (defun smart-asm-include-file () | |
146 "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. | |
148 Look for include file in 'smart-asm-include-dirs' and add suffix \".ins\" or | |
149 \".inc\" to filename if it lacks a suffix." | |
150 (let ((opoint (point))) | |
151 ;; Some assemblers utilize the C preprocessor, so try that first. | |
152 (cond ((smart-c-include-file)) | |
153 ((progn (beginning-of-line) | |
154 (looking-at smart-asm-include-regexp)) | |
155 (let ((file (buffer-substring (match-beginning 2) (match-end 2))) | |
156 (path) | |
157 (dir-list smart-asm-include-dirs)) | |
158 (goto-char opoint) | |
159 (setq dir-list (cons (file-name-directory buffer-file-name) | |
160 dir-list)) | |
161 (if (string-match "\\." file) | |
162 (setq file (regexp-quote file)) | |
163 (setq file (concat (regexp-quote file) "\\.in[sc]$"))) | |
164 (while dir-list | |
165 (setq dir-list | |
166 (if (setq path (car (directory-files | |
167 (car dir-list) t file))) | |
168 nil | |
169 (cdr dir-list)))) | |
170 ;; | |
171 ;; If path exists, display file | |
172 ;; | |
173 (if path | |
174 (if (and (file-readable-p path) | |
175 (progn | |
176 (if (br-in-browser) | |
177 (find-file path) | |
178 (find-file-other-window path)) | |
179 (cond ((featurep 'asm-mode) t) | |
180 ((load "asm-mode" nil 'nomessage) | |
181 (provide 'asm-mode)) | |
182 (t | |
183 (beep) | |
184 (message | |
185 "(smart-asm-include-file): asm-mode undefined.") | |
186 nil | |
187 )))) | |
188 nil | |
189 (beep) | |
190 (message "(smart-asm-include-file): '%s' unreadable." path)) | |
191 (beep) | |
192 (message "(smart-asm-include-file): '%s' not found." file)) | |
193 path)) | |
194 ;; not on an include file line | |
195 (t (goto-char opoint) | |
196 nil)))) | |
197 | |
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 | |
253 (defun smart-c-include-file () | |
254 "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. | |
256 Look for include file in 'smart-c-cpp-include-dirs' and in directory list | |
257 'smart-c-include-dirs'." | |
258 (let ((opoint (point))) | |
259 (beginning-of-line) | |
260 (if (looking-at smart-c-include-regexp) | |
261 (let ((incl-type (string-to-char | |
262 (buffer-substring (match-beginning 2) | |
263 (1+ (match-beginning 2))))) | |
264 (file (buffer-substring (match-beginning 3) (match-end 3))) | |
265 (path) | |
266 (dir-list smart-c-include-dirs) | |
267 (found)) | |
268 (goto-char opoint) | |
269 (setq dir-list (if (= incl-type ?<) | |
270 (append dir-list smart-c-cpp-include-dirs) | |
271 (cons (file-name-directory buffer-file-name) | |
272 dir-list))) | |
273 (while dir-list | |
274 (setq path (expand-file-name file (car dir-list)) | |
275 dir-list (if (setq found (file-exists-p path)) | |
276 nil | |
277 (cdr dir-list)))) | |
278 ;; | |
279 ;; If found, display file | |
280 ;; | |
281 (if found | |
282 (if (and (file-readable-p path) | |
283 (progn | |
284 (if (br-in-browser) | |
285 (find-file path) | |
286 (find-file-other-window path)) | |
287 (cond ((or (featurep 'cc-mode) | |
288 (featurep 'c-mode)) | |
289 t) | |
290 ((or (load "cc-mode" 'missing-ok 'nomessage) | |
291 (load "c-mode" 'missing-ok 'nomessage)) | |
292 (provide 'c-mode)) | |
293 (t | |
294 (beep) | |
295 (message | |
296 "(smart-c-include-file): c-mode undefined.") | |
297 nil | |
298 )))) | |
299 nil | |
300 (beep) | |
301 (message "(smart-c-include-file): '%s' unreadable." path)) | |
302 (beep) | |
303 (message "(smart-c-include-file): '%s' not found." file)) | |
304 path) | |
305 (goto-char opoint) | |
306 nil))) | |
307 | |
308 | |
309 ;;;###autoload | |
310 (defun smart-c++ (&optional identifier next) | |
311 "Jumps to the definition of optional C++ IDENTIFIER or the one at point. | |
312 Optional second arg NEXT means jump to next matching C++ tag. | |
313 | |
314 It assumes that its caller has already checked that the key was pressed in an | |
315 appropriate buffer and has moved the cursor to the selected buffer. | |
316 | |
317 If: | |
318 (1) on a '#include' statement, the include file is displayed; | |
319 Look for include file in directory lists 'smart-c-cpp-include-dirs' | |
320 and 'smart-c-include-dirs'. | |
321 (2) on a C++ identifier, the identifier definition is displayed, | |
322 assuming the identifier is found within an 'etags' generated tag file | |
323 in the current directory or any of its ancestor directories. | |
324 (3) if 'smart-c-use-lib-man' is non-nil, the C++ identifier is | |
325 recognized as a library symbol, and a man page is found for the | |
326 identifier, then the man page is displayed." | |
327 | |
328 (interactive) | |
329 (or | |
330 (if identifier nil (smart-c-include-file)) | |
331 (let ((tag (or identifier (smart-c++-at-tag-p)))) | |
332 ;; Set free variable tags-file-name so that next 'find-tag' command uses | |
333 ;; whatever tags file is set here. | |
334 (setq tags-file-name (smart-tags-file buffer-file-name)) | |
335 (message "Looking for '%s' in '%s'..." tag tags-file-name) | |
336 (condition-case () | |
337 (progn | |
338 (funcall (if (br-in-browser) | |
339 'find-tag 'find-tag-other-window) | |
340 tag next) | |
341 (message "Found definition for '%s'." tag)) | |
342 (error | |
343 (if (not smart-c-use-lib-man) | |
344 (progn (message "'%s' not found in '%s'." tag tags-file-name) | |
345 (beep)) | |
346 (message "Checking if '%s' is a C++ library function..." tag) | |
347 (if (smart-library-symbol tag) | |
348 (progn (message "Displaying C++ library man page for '%s'." tag) | |
349 (manual-entry tag)) | |
350 (message "'%s' not found in '%s' or C++ libraries." | |
351 tag tags-file-name) | |
352 (beep)))))))) | |
353 | |
354 ;;; The following should be called only if the OO-Browser is available. | |
355 ;;;###autoload | |
356 (defun smart-c++-oobr (&optional junk) | |
357 "Jumps to the definition of selected C++ construct via OO-Browser support. | |
358 Optional JUNK is ignored. Does nothing if the OO-Browser is not available. | |
359 | |
360 It assumes that its caller has already checked that the key was pressed in an | |
361 appropriate buffer and has moved the cursor to the selected buffer. | |
362 | |
363 If key is pressed: | |
364 (1) on a '#include' statement, the include file is displayed; | |
365 Look for include file in directory lists 'smart-c-cpp-include-dirs' | |
366 and 'smart-c-include-dirs'. | |
367 (2) within a method declaration, its definition is displayed; | |
368 (3) on a class name, the class definition is shown. | |
369 | |
370 (2) and (3) require that an OO-Browser Environment has been loaded with | |
371 the {M-x br-env-load RTN} command." | |
372 | |
373 (interactive) | |
374 (c++-to-definition 'other-win)) | |
375 | |
376 (defun smart-c++-at-tag-p () | |
377 "Return C++ tag name that point is within, else nil." | |
378 (let* ((identifier-chars "_:~<>a-zA-Z0-9") | |
379 (identifier (concat "\\([_~:<a-zA-Z][" identifier-chars "]*" | |
380 "[ \t]*[^]) \t:;.,?~{}][^[( \t:;.,~^!|?{}]?[=*]?\\)[ \t\n]*("))) | |
381 (save-excursion | |
382 (skip-chars-backward identifier-chars) | |
383 (if (looking-at identifier) | |
384 (buffer-substring (point) (match-end 1)))))) | |
385 | |
386 (defun smart-emacs-lisp-mode-p () | |
387 "Return t if in a mode which uses Emacs Lisp symbols." | |
388 (or (eq major-mode 'emacs-lisp-mode) | |
389 (eq major-mode 'lisp-interaction-mode) | |
390 (eq major-mode 'debugger-mode) | |
391 ;; Emacs Lisp symbols appear in Help buffers frequently. | |
392 (string-match "Help\\*$" (buffer-name)))) | |
393 | |
394 (defun smart-fortran (&optional identifier next) | |
395 "Jumps to the definition of optional Fortran IDENTIFIER or the one at point. | |
396 Optional second arg NEXT means jump to next matching Fortran tag. | |
397 | |
398 It assumes that its caller has already checked that the key was pressed in an | |
399 appropriate buffer and has moved the cursor to the selected buffer. | |
400 | |
401 If on a Fortran identifier, the identifier definition is displayed, | |
402 assuming the identifier is found within an 'etags' generated tag file | |
403 in the current directory or any of its ancestor directories." | |
404 (interactive) | |
405 (let ((tag (or identifier (smart-fortran-at-tag-p)))) | |
406 ;; Set free variable tags-file-name so that next 'find-tag' command uses | |
407 ;; whatever tags file is set here. | |
408 (setq tags-file-name (smart-tags-file buffer-file-name)) | |
409 (message "Looking for '%s' in '%s'..." tag tags-file-name) | |
410 (condition-case () | |
411 (progn | |
412 (funcall (if (br-in-browser) | |
413 'find-tag 'find-tag-other-window) | |
414 tag next) | |
415 (message "Found definition for '%s'." tag)) | |
416 (error | |
417 (message "'%s' not found in '%s'." tag tags-file-name) | |
418 (beep))))) | |
419 | |
420 ;;;###autoload | |
421 (defun smart-fortran-at-tag-p () | |
422 "Return Fortran tag name that point is within, else nil." | |
423 (let* ((identifier-chars "_a-zA-Z0-9") | |
424 (identifier (concat "[_a-zA-Z][" identifier-chars "]*"))) | |
425 (save-excursion | |
426 (skip-chars-backward identifier-chars) | |
427 (if (looking-at identifier) | |
428 (buffer-substring (point) (match-end 0)))))) | |
429 | |
430 (defun smart-lisp (&optional next) | |
431 "Jumps to the definition of any selected Lisp construct. | |
432 If on an Emacs Lisp require, load, or autoload clause and 'find-library' | |
433 from load-library package by Hallvard Furuseth (hallvard@ifi.uio.no) has | |
434 been loaded, jumps to library source, if possible. | |
435 | |
436 Otherwise, the construct must be found within an 'etags' generated tag file | |
437 in the current directory or any of its ancestor directories in order for its | |
438 definition to be located. | |
439 | |
440 Optional NEXT means jump to next matching Lisp tag. When matching to an Emacs | |
441 Lisp tag using 'wtags' (Bob Weiner's personal modifications to 'etags'), | |
442 there is no next tag, so display documentation for current tag instead. | |
443 | |
444 This command assumes that its caller has already checked that the key was | |
445 pressed in an appropriate buffer and has moved the cursor to the selected | |
446 buffer." | |
447 | |
448 (interactive) | |
449 ;; Handle 'require', 'load', and 'autoload' clauses in Emacs Lisp. | |
450 (or (and (fboundp 'find-library) | |
451 (smart-emacs-lisp-mode-p) | |
452 (let ((req) | |
453 (opoint (point))) | |
454 (setq req (and (search-backward "\(" nil t) | |
455 (looking-at (concat | |
456 "(\\(require\\|load\\|autoload\\)" | |
457 "[ \t]+.*['\"]" | |
458 "\\([^][() \t\n\^M`'\"]+\\)")))) | |
459 (goto-char opoint) | |
460 (if req (progn | |
461 (setq req (buffer-substring (match-beginning 2) | |
462 (match-end 2))) | |
463 (pop-to-buffer nil t) | |
464 (find-library req) | |
465 t)))) | |
466 (let ((tag (smart-lisp-at-tag-p))) | |
467 ;; Set free variable tags-file-name so that next 'find-tag' command | |
468 ;; uses whatever tags file is set here. | |
469 (setq tags-file-name (smart-tags-file default-directory)) | |
470 ;; This part only works properly for Emacs Lisp, so is conditionalized. | |
471 (if (and next (smart-emacs-lisp-mode-p) (featurep 'wtags)) | |
472 (progn (setq tag (intern tag)) | |
473 (cond ((fboundp tag) (describe-function tag)) | |
474 ((boundp tag) (describe-variable tag)) | |
475 (t (error "(smart-lisp): Unbound symbol: %s" tag)))) | |
476 (condition-case () | |
477 (funcall (if (br-in-browser) | |
478 'find-tag 'find-tag-other-window) | |
479 tag next) | |
480 (error (if (equal tags-file-name smart-emacs-tags-file) | |
481 nil | |
482 (setq tags-file-name smart-emacs-tags-file) | |
483 (funcall (if (br-in-browser) | |
484 'find-tag 'find-tag-other-window) | |
485 tag next)))))))) | |
486 | |
487 (defun smart-lisp-at-tag-p () | |
488 "Returns Lisp tag name that point is within, else nil. | |
489 Returns nil when point is on the first line of a 'def' form past the first 4 | |
490 characters." | |
491 (let* ((identifier-chars "-_*:+%$#!<>a-zA-Z0-9") | |
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 ;;; ************************************************************************ | |
593 | |
594 (defun smart-library-symbol (tag) | |
595 "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." | |
597 (let ((buf (get-buffer-create "*junk*")) | |
598 (found)) | |
599 (save-excursion | |
600 (set-buffer buf) | |
601 (setq buffer-read-only nil) | |
602 (erase-buffer) | |
603 (call-process (expand-file-name "smart-clib-sym" hyperb:dir) | |
604 nil buf nil tag) | |
605 (setq found (string-equal (buffer-substring 1 2) "1")) | |
606 (set-buffer-modified-p nil) | |
607 (kill-buffer buf) | |
608 found))) | |
609 | |
610 ;;;###autoload | |
611 (defun smart-tags-file-path (file) | |
612 "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 | |
614 cannot be expanded via a tags file." | |
615 (or (cond ((or (file-exists-p file) (file-name-absolute-p file)) file) | |
616 (t (let ((tags-file (smart-tags-file default-directory)) | |
617 (file-regexp | |
618 (concat "\^L\n\\(.*/\\)?" (regexp-quote file) ","))) | |
619 (if tags-file | |
620 (progn | |
621 (set-buffer (find-file-noselect tags-file)) | |
622 (goto-char (point-min)) | |
623 (if (re-search-forward file-regexp nil t) | |
624 (expand-file-name | |
625 (buffer-substring (1- (match-end 0)) | |
626 (progn (beginning-of-line) | |
627 (point)))))))))) | |
628 file)) | |
629 | |
630 ;;;###autoload | |
631 (defun smart-tags-file (curr-filename) | |
632 "Return appropriate tags file name for CURR-FILENAME or 'tags-file-name'." | |
633 (let ((path curr-filename) | |
634 (tags-file)) | |
635 (while (and | |
636 (stringp path) | |
637 (setq path (file-name-directory path)) | |
638 (setq path (directory-file-name path)) | |
639 ;; Not at root directory | |
640 (not (string-match ":?/\\'" path)) | |
641 ;; No tags file | |
642 (not (file-exists-p | |
643 (setq tags-file (expand-file-name "TAGS" path))))) | |
644 (setq tags-file nil)) | |
645 (if (and (not tags-file) | |
646 (stringp curr-filename) | |
647 (smart-emacs-lisp-mode-p) | |
648 (let ((path (file-name-directory curr-filename))) | |
649 (delq nil (mapcar | |
650 (function | |
651 (lambda (p) | |
652 (and p (equal (file-name-as-directory p) | |
653 path)))) | |
654 load-path)))) | |
655 (setq tags-file smart-emacs-tags-file)) | |
656 (or tags-file tags-file-name | |
657 (call-interactively 'visit-tags-table)))) | |
658 | |
659 ;;; ************************************************************************ | |
660 ;;; Private variables | |
661 ;;; ************************************************************************ | |
662 | |
663 (provide 'hmouse-tag) |