1 ;; jde-open-source.el -- Open class source files
5 ;; Author: Klaus Berndl
7 ;; Keywords: java, open files
9 ;; Copyright (C) 2002, 2003, 2004 Klaus Berndl
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.
15 ;; Java is a registered trademark of Sun Microsystem, Inc.
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.
23 ;; This package allows to open the class at point.
25 ;; Known bugs/problems :
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/>
33 ;; Please send any comments, bugs, or upgrade requests to
34 ;; Paul Kinnucan at pkinnucan@mediaone.net
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
47 :type '(function :tag "Function to open class at point"))
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!")
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
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))
73 (insert-file-contents ,exp-filename)
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)
91 (if (jde-parse-find-completion-for-pair
92 `("this" ,parsed-symbol) nil jde-complete-private)
93 (jde-parse-eval-type-of "this")
95 (if (jde-parse-find-completion-for-pair
96 `("super" ,parsed-symbol) nil jde-complete-private)
97 (jde-parse-eval-type-of "super")
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)))
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
122 (when (and (fboundp 'senator-search-forward) (not (string= parsed-symbol "")))
123 (beginning-of-buffer)
124 (setq xtags (semantic-fetch-tags))
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
132 (let ((jde-open-cap-ff-function-temp-override 'find-file))
133 (jde-show-superclass-source-2 tags))
134 (beginning-of-buffer)
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
143 (setq first-time nil)
144 (senator-re-search-forward
146 (string-match ".*\\.\\([^.]+\\)$"
147 (concat "." class-name))
148 (match-string 1 (concat "." class-name)))
150 (if (not super-class)
151 (error "Method not found"))
152 (setq super-class (car tags)))))))
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."
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.
175 (string= (car pair) "")
176 (jde-parse-find-declaration-of thing-of-interest))))
179 ;; Handle the case where the definition is in another buffer or an
180 ;; unopened source file.
182 (jde-find-class-source-file class-to-open)))
184 ;; we have found the source file. So let´s open it and
185 ;; then jump to the thing-of-interest
187 (if (typep source 'buffer)
188 (let ((pop-up-frames t))
190 (display-buffer source)
192 ;; (semantic-new-buffer-fcn)
193 ;; (semantic-fetch-tags)
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
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)
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.")))
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."
216 (let* ((unqualified-name
218 (read-from-minibuffer "Class: " (thing-at-point 'symbol))))
220 ;;expand the names into full names, or a list of names
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))
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?")))
241 (jde-find-class-source class))))
242 (setq jde-project-context-switching-enabled-p old-value)))
244 (message "%s" (error-message-string err)))))
246 (defalias 'jde-show-class-source 'jde-open-class-source)
248 ;; Thanks to Sandip Chitale <sandip.chitale@blazesoft.com>
249 (defun jde-show-superclass-source-2 (tags)
251 (if (= (length tags) 1)
252 (jde-show-class-source (car tags))
253 (let ((parent (efc-query-options tags "Which super class?")))
255 (jde-show-class-source parent))))
256 (jde-show-class-source "Object")))
258 (defun jde-show-superclass-source ()
259 "Show the source for the parent of the class at point."
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>
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."
271 (let ((tags (semantic-tag-type-interfaces
272 (semantic-current-tag-of-class 'type))))
274 (if (= (length tags) 1)
275 (jde-show-class-source (car tags))
276 (let ((interface (efc-query-options tags "Which interface?")))
278 (jde-show-class-source interface)))))))
281 (provide 'jde-open-source)
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.
287 ;; Revision 1.14 2004/07/09 04:29:45 paulk
288 ;; Update to reflect new nomenclature in semantic 2.0.
290 ;; Revision 1.13 2004/01/13 06:15:25 paulk
291 ;; Some additional tweaks to jde-open-class-at-point.
293 ;; Revision 1.12 2004/01/13 06:07:25 paulk
294 ;; Rewrote jde-open-class-at-point to be more succinct and clear.
296 ;; Revision 1.11 2003/10/06 12:30:37 jslopez
297 ;; Fixes several broken cases with jde-open-class-at-point.
299 ;; Revision 1.10 2003/07/19 05:44:48 paulk
300 ;; Make error message for jde-open-class-at-point more meaningful.
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.
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.
311 ;; Revision 1.7 2002/07/27 13:21:30 jslopez
312 ;; Fixes regression in jde-open-class-at-point.
314 ;; Revision 1.6 2002/07/27 13:03:19 jslopez
315 ;; Substitute obsolete call to jde-open-base-class-source.
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.
321 ;; - Removed jde-open-source-for-symbol because it has been superceded by jde-open-class-at-point.
324 ;; end jde-open-source.el