Initial Commit
[packages] / xemacs-packages / jde / lisp / jde-open-source.el
1 ;; jde-open-source.el -- Open class source files
2 ;;
3 ;; $Revision: 1.15 $
4 ;;
5 ;; Author: Klaus Berndl
6
7 ;; Keywords: java, open files
8
9 ;; Copyright (C) 2002, 2003, 2004 Klaus Berndl
10
11 ;; This package follows the GNU General Public Licence (GPL), see the
12 ;; COPYING file that comes along with GNU Emacs. This is free software,
13 ;; you can redistribute it and/or modify it under the GNU GPL terms.
14 ;;
15 ;; Java is a registered trademark of Sun Microsystem, Inc.
16 ;;
17 ;;; Commentary:
18
19 ;; This is one of a set of packages that make up the
20 ;; Java Development Environment (JDE) for Emacs. See the
21 ;; JDE User's Guide for more information.
22
23 ;; This package allows to open the class at point.
24
25 ;; Known bugs/problems :
26 ;;
27 ;; TODO
28 ;;
29 ;; The latest version of the JDE is available at
30 ;; <URL:http://jde.sunsite.dk>.
31 ;; <URL:http://www.geocities.com/SiliconValley/Lakes/1506/>
32
33 ;; Please send any comments, bugs, or upgrade requests to
34 ;; Paul Kinnucan at pkinnucan@mediaone.net
35
36 (require 'jde-parse)
37 (require 'jde-util)
38 (require 'senator)
39
40 (defcustom jde-open-class-at-point-find-file-function 'find-file-other-window
41   "Define the function for opening the class at point. See
42 `jde-open-class-at-point'`. Default is `find-file-other-window'. A function
43 defined here must have the same signature as `find-file' means the first
44 argument is the filename and the second optional argument is a
45 wildcard-pattern."
46   :group 'jde-project
47   :type '(function :tag "Function to open class at point"))
48
49 (defvar jde-open-cap-ff-function-temp-override nil
50   "Maybe some tools needs to temporally override the value of
51 `jde-open-class-at-point-find-file-function'. Cause of the auto. resetting
52 mechanism of JDE for defcustom-variables this is not possible with the
53 defcustom version. So, if you need to override the value of
54 `jde-open-class-at-point-find-file-function' from within your elisp code you
55 can use the variable `jde-open-cap-ff-function-temp-override'.
56 `jde-open-class-at-point' checks first if this variable is not nil and uses
57 then this value. Only if this variable is nil it uses the value of
58 `jde-open-class-at-point'!
59 This variable is NOT for user customizing, but only for use within elisp!")
60
61 (defmacro jde-with-file-contents (file &rest body)
62   "If FILE exists and is readable creates a temporary buffer with the contents
63 of FILE, points to beginning of buffer, evaluates BODY and return the value of
64 the last form of BODY. If FILE does not exist or is not readable nil is
65 returned.
66 Note: No major/minor-mode is activated and no local variables are evaluated
67 for FILE, but proper EOL-conversion and charcater interpretation is done!"
68   (let ((exp-filename (make-symbol "exp-filename")))
69     `(let ((,exp-filename (expand-file-name ,file)))
70        (if (and (file-exists-p ,exp-filename)
71                 (file-readable-p ,exp-filename))
72            (with-temp-buffer
73              (insert-file-contents ,exp-filename)
74              (beginning-of-buffer)
75              ,@body)
76          nil))))
77
78 (defun jde-open-get-class-to-open (pair parsed-symbol)
79   "Evaluates PARSE-SYMBOL to check if it is a variable name or a class name.
80 If this fails point is on a method or an attribute of a class in the current
81 buffer or in a superclass. In this cases we check first if the parsed-symbol
82 is a possible member of the current class(\"this\") and if this fails it
83 checks if it is a member of the base class(\"super\")."
84  (if (and (stringp (car pair)) 
85           (> (length (car pair)) 0))
86      ;; if we got a pair all should work fine.
87      (jde-parse-eval-type-of (car pair))
88    (or (condition-case () 
89            (jde-parse-eval-type-of parsed-symbol)
90          (error nil))
91        (if (jde-parse-find-completion-for-pair 
92             `("this" ,parsed-symbol) nil jde-complete-private)
93            (jde-parse-eval-type-of "this")
94          nil)
95        (if (jde-parse-find-completion-for-pair 
96             `("super" ,parsed-symbol) nil jde-complete-private)
97            (jde-parse-eval-type-of "super")
98          nil))))
99
100
101 (defun jde-open-functions-exist ()
102   "Checks if the functions `jde-parse-java-variable-at-point',
103 `jde-parse-eval-type-of', and `jde-parse-find-completion-for-pair' are defined"
104   (and (fboundp 'jde-parse-java-variable-at-point)
105        (fboundp 'jde-parse-eval-type-of)
106        (fboundp 'jde-parse-find-completion-for-pair)))
107
108
109 (defun jde-open-jump-to-class (parsed-symbol class-name) 
110   "Place the cursor in the parsed variable"
111   (let* (tags super-class (first-time t))
112     (search-forward "{" nil t)
113     (setq tags (semantic-tag-type-superclasses
114                   (semantic-current-tag-of-class 'type)))
115     (setq super-class (car tags))
116     (message "Superclass of %s is %s" class-name super-class)
117     ;; Now let´s jump to the thing-of-interest. If this is a
118     ;; variable-name then we will not find this with senator in
119     ;; the opened java-file so we search for the definiton of
120     ;; the class itself. This feature is only available if we
121     ;; have senator!
122     (when (and (fboundp 'senator-search-forward) (not (string= parsed-symbol "")))
123       (beginning-of-buffer)
124       (setq xtags (semantic-fetch-tags))
125       (senator-parse)
126       (setq parsed-symbol (concat "\\b" parsed-symbol "\\b"))
127       (while (not (senator-re-search-forward parsed-symbol nil t))
128         (message "Could not find %s in %s" parsed-symbol (buffer-name))
129         ;; searching for the thing-of-interest has failed 
130         ;; let's try in the base class
131           (progn
132             (let ((jde-open-cap-ff-function-temp-override 'find-file))
133               (jde-show-superclass-source-2 tags))
134             (beginning-of-buffer)
135             (senator-parse)
136             (search-forward "{" nil t)
137             (setq tags (semantic-tag-type-superclasses
138                           (semantic-current-tag-of-class 'type)))
139             ;;if it is the first time try in the class definition
140             ;;itself.
141             (if first-time
142                 (progn 
143                   (setq first-time nil)
144                   (senator-re-search-forward
145                    (progn
146                      (string-match ".*\\.\\([^.]+\\)$"
147                                    (concat "." class-name))
148                      (match-string 1 (concat "." class-name)))
149                    nil t)))
150             (if (not super-class)
151                 (error "Method not found"))
152             (setq super-class (car tags)))))))
153
154 (defun jde-open-class-at-point ()
155   "Opens the source file that defines the class of the symbol at point and
156 scrolls the source file to the definition of the symbol, which can be the name of
157 a variable, class, method, or attribute. This function has the
158 same requirements as the JDEE's field/method completion commands. See, for example,
159 `jde-complete-menu'. The JDEE searches for the source file first in
160 `jde-sourcepath', then in `jde-global-classpath', then in
161 $CLASSPATH, then in the current directory."
162   (interactive)
163   (if (jde-open-functions-exist)
164       (let* ((thing-of-interest (thing-at-point 'symbol))
165              (pair (save-excursion 
166                      (end-of-thing 'symbol)
167                      (jde-parse-java-variable-at-point)))
168              (class-to-open (jde-open-get-class-to-open
169                              pair thing-of-interest)))
170         (if (and class-to-open 
171                  (stringp class-to-open))
172             ;; Handle the case where the definition of the symbol is in the current buffer.
173             (let ((pos 
174                    (and 
175                     (string= (car pair) "")
176                     (jde-parse-find-declaration-of thing-of-interest))))
177               (if pos 
178                   (goto-char pos)
179               ;; Handle the case where the definition is in another buffer or an 
180               ;; unopened source file.
181                 (let ((source 
182                        (jde-find-class-source-file class-to-open)))
183                   (if source
184                       ;; we have found the source file. So let´s open it and
185                       ;; then jump to the thing-of-interest
186                       (progn
187                         (if (typep source 'buffer)
188                           (let ((pop-up-frames t)) 
189                             (set-buffer source)
190                             (display-buffer source)
191                             ;; (jde-mode)
192                             ;; (semantic-new-buffer-fcn)
193                             ;; (semantic-fetch-tags)
194                             )
195                           ;; (switch-to-buffer source)
196                           ;; (pop-to-buffer source other-window)
197                           ;; if the current buffer contains java-file-name do not try to
198                           ;; open the file
199                           (if (not (string-equal (buffer-file-name) source))
200                               (funcall (or jde-open-cap-ff-function-temp-override
201                                            jde-open-class-at-point-find-file-function)
202                                        source)))
203                         (jde-open-jump-to-class thing-of-interest class-to-open))
204                     (message "Can not find the source for \"%s\"." class-to-open)))))
205           (message "Cannot determine the class of \"%s\"." thing-of-interest)))
206     (message "You need JDEE >= 2.2.6 and Senator to use this command.")))
207
208 (defun jde-open-class-source ( &optional unqual-class )
209   "Displays source of the class whose name appears at point in the current
210 Java buffer. This command finds only classes that reside in the source paths
211 specified by `jde-sourcepath'. You should provide a global setting
212 for this variable in your .emacs file to accommodate source files that are
213 not associated with any project."
214   (interactive)
215   (condition-case err
216       (let* ((unqualified-name 
217               (or unqual-class
218                   (read-from-minibuffer "Class: " (thing-at-point 'symbol))))
219              (class-names 
220               ;;expand the names into full names, or a list of names
221               (jde-jeval-r 
222                (concat 
223                 "jde.util.JdeUtilities.getQualifiedName(\"" 
224                 unqualified-name "\");"))))
225         ;;Check return value of QualifiedName
226         (if (or (eq class-names nil)
227                 (not (listp class-names)))
228             (error "Cannot find %s" unqualified-name))
229         ;; Turn off switching project settings to avoid 
230         ;; resetting jde-sourcepath.
231         (let ((old-value jde-project-context-switching-enabled-p))
232           (setq jde-project-context-switching-enabled-p nil)
233           ;;If the list is only one long
234           (if (eq 1 (length class-names))
235               ;;then show it
236               (progn(other-window 1)
237                     (jde-find-class-source (car class-names)))
238                   ;;else let the user choose
239             (let ((class (efc-query-options class-names "Which class?")))
240                   (if class
241                       (jde-find-class-source class))))
242           (setq jde-project-context-switching-enabled-p old-value)))
243     (error
244      (message "%s" (error-message-string err)))))
245
246 (defalias 'jde-show-class-source 'jde-open-class-source)
247
248 ;; Thanks to Sandip Chitale <sandip.chitale@blazesoft.com>
249 (defun jde-show-superclass-source-2 (tags)
250   (if tags
251       (if (= (length tags) 1)
252           (jde-show-class-source (car tags))
253         (let ((parent (efc-query-options tags "Which super class?")))
254           (if parent
255               (jde-show-class-source parent))))
256     (jde-show-class-source "Object")))
257
258 (defun jde-show-superclass-source () 
259   "Show the source for the parent of the class at point."
260   (interactive)
261   (let ((tags (semantic-tag-type-superclasses
262                  (semantic-current-tag-of-class 'type))))
263     (jde-show-superclass-source-2 tags)))
264 ;; Thanks to Sandip Chitale <sandip.chitale@blazesoft.com>
265     
266 (defun jde-show-interface-source () 
267   "Show the source for the interface implemented by the class at point.
268 If the class implements more than one interface, this command prompts
269 you to select one of the interfaces to show."
270   (interactive)
271   (let ((tags (semantic-tag-type-interfaces
272                  (semantic-current-tag-of-class 'type))))
273     (if tags
274         (if (= (length tags) 1)
275             (jde-show-class-source (car tags))
276           (let ((interface (efc-query-options tags "Which interface?")))
277             (if interface 
278                 (jde-show-class-source interface)))))))
279
280
281 (provide 'jde-open-source)
282
283 ;; $Log: jde-open-source.el,v $
284 ;; Revision 1.15  2004/12/17 04:21:26  paulk
285 ;; Create infrastructure for supporting source archives in jde-sourcepath.
286 ;;
287 ;; Revision 1.14  2004/07/09 04:29:45  paulk
288 ;; Update to reflect new nomenclature in semantic 2.0.
289 ;;
290 ;; Revision 1.13  2004/01/13 06:15:25  paulk
291 ;; Some additional tweaks to jde-open-class-at-point.
292 ;;
293 ;; Revision 1.12  2004/01/13 06:07:25  paulk
294 ;; Rewrote jde-open-class-at-point to be more succinct and clear.
295 ;;
296 ;; Revision 1.11  2003/10/06 12:30:37  jslopez
297 ;; Fixes several broken cases with jde-open-class-at-point.
298 ;;
299 ;; Revision 1.10  2003/07/19 05:44:48  paulk
300 ;; Make error message for jde-open-class-at-point more meaningful.
301 ;;
302 ;; Revision 1.9  2003/01/03 16:24:25  jslopez
303 ;; Fixes bug handling finding method definition in a super class.
304 ;; The code was parsing the java file from where it was invoked instead
305 ;; of the class file that was pertinent.
306 ;;
307 ;; Revision 1.8  2002/08/22 04:15:17  jslopez
308 ;; Fixes jde-open-class-at-point to loop through
309 ;; all the super classes looking for the given token.
310 ;;
311 ;; Revision 1.7  2002/07/27 13:21:30  jslopez
312 ;; Fixes regression in jde-open-class-at-point.
313 ;;
314 ;; Revision 1.6  2002/07/27 13:03:19  jslopez
315 ;; Substitute obsolete call to jde-open-base-class-source.
316 ;;
317 ;; Revision 1.5  2002/07/01 04:52:11  paulk
318 ;; - Moved jde-open-class-source, jde-show-superclass-source, jde-show-interface-source from jde-help.el
319 ;;   to jde-open-source.el.
320 ;;
321 ;; - Removed jde-open-source-for-symbol because it has been superceded by jde-open-class-at-point.
322 ;;
323
324 ;; end jde-open-source.el