Initial Commit
[packages] / xemacs-packages / jde / lisp / jde-util.el
1 ;;; jde-util.el -- JDE utilities.
2 ;; $Revision: 1.19.2.2 $ $Date: 2006/03/08 12:09:08 $ 
3
4 ;; Author: Paul Kinnucan <paulk@mathworks.com>
5 ;; Maintainer: Paul Kinnucan
6 ;; Keywords: java, tools
7
8 ;; Copyright (C) 2001-2006 Paul Kinnucan.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Commentary:
26
27 ;; This package provides useful macros, functions, and classes
28 ;; required by multiple JDE packages. You should not put any macros,
29 ;; functions, or classes in this package that require other
30 ;; JDE packages.
31 ;; 
32 ;; This is one of a set of packages that make up the 
33 ;; Java Development Environment (JDE) for Emacs. See the
34 ;; JDE User's Guide for more information.
35
36 ;; The latest version of the JDE is available at
37 ;; <URL:http://jde.sunsite.dk>.
38
39 ;; Please send any comments, bugs, or upgrade requests to
40 ;; Paul Kinnucan at pkinnucan@comcast.net.
41
42 ;;; Code:
43
44 (require 'efc)
45
46 (if (featurep 'xemacs)
47      (load "arc-mode")
48   (require 'arc-mode))
49
50 (defsubst jde-line-beginning-position (&optional n)
51   (if (featurep 'xemacs)
52       (save-excursion (beginning-of-line n) (point))
53     (line-beginning-position n)))
54
55 (defsubst jde-line-end-position (&optional n)
56   (if (featurep 'xemacs)
57       (save-excursion (end-of-line n) (point))
58     (line-end-position)))
59
60 (defun jde-require (feature)
61    "Require FEATURE, either pre-installed or from the distribution.
62  That is, first try to load the FEATURE library. Then try to load the
63  jde-FEATURE library from the JDEE's distribution.
64  Signal an error if FEATURE can't be found."
65    (condition-case nil
66       ;; If the library if available, use it.
67        (require feature)
68      (error
69       ;; Try to use the one from the JDEE's distribution.
70       (require feature (format "jde-%s" feature)))))
71
72 (defmacro jde-assert-source-buffer ()
73   "Asserts that the current buffer is a
74 Java source or a debug buffer."
75   '(assert  (eq major-mode 'jde-mode) nil 
76     "This command works only in a Java source or debug buffer."))
77
78
79 ;; Provided for XEmacs compatibility.
80 (if (not (fboundp 'subst-char-in-string))
81     (defun subst-char-in-string (fromchar tochar string &optional inplace)
82       "Replace FROMCHAR with TOCHAR in STRING each time it occurs.
83 Unless optional argument INPLACE is non-nil, return a new string."
84       (let ((i (length string))
85             (newstr (if inplace string (copy-sequence string))))
86         (while (> i 0)
87           (setq i (1- i))
88           (if (eq (aref newstr i) fromchar)
89               (aset newstr i tochar)))
90         newstr)))
91
92 (if (not (fboundp 'replace-in-string))
93     (defun replace-in-string  (string regexp newtext &optional literal)
94       "Replace REGEXP with NEWTEXT in STRIng."
95       (if (string-match regexp string)
96           (replace-match newtext nil nil string)
97         string)))                      
98
99
100 (defun jde-get-line-at-point (&optional pos)
101   "Get the number of the line at point."
102   (let* ((point (or pos (point)))
103          (ln (if (= point 1)
104                  1
105                (count-lines (point-min) point))))
106     (save-excursion
107       (goto-char point)
108       (if (eq (char-before) ?\n)
109           (1+ ln)
110         ln))))
111
112 (defmacro jde-with-file-contents (file &rest body)
113   "If FILE exists and is readable creates a temporary buffer with the contents
114 of FILE, points to beginning of buffer, evaluates BODY and return the value of
115 the last form of BODY. If FILE does not exist or is not readable nil is
116 returned.
117 Note: No major/minor-mode is activated and no local variables are evaluated
118 for FILE, but proper EOL-conversion and charcater interpretation is done!"
119   (let ((exp-filename (make-symbol "exp-filename")))
120     `(let ((,exp-filename (expand-file-name ,file)))
121        (if (and (file-exists-p ,exp-filename)
122                 (file-readable-p ,exp-filename))
123            (with-temp-buffer
124              (insert-file-contents ,exp-filename)
125              (beginning-of-buffer)
126              ,@body)
127          nil))))
128
129 (defmacro jde-normalize-paths (pathlist &optional symbol)
130   "Normalize all paths of the list PATHLIST and returns a list with the
131 expanded paths."
132   (` (mapcar (lambda (path)
133                (jde-normalize-path path (, symbol)))
134              (, pathlist))))
135
136
137 (defun jde-remove-inner-class (class) 
138   "Removes the inner class name for the class"
139   (car (split-string class "[$]")))
140
141 (defun jde-find-class-source-file (class)
142   "Find the source file for a specified class.
143 CLASS is the fully qualified name of the class. This function searchs
144 the directories and source file archives (i.e., jar or zip files)
145 specified by `jde-sourcepath' for the source file corresponding to
146 CLASS. If it finds the source file in a directory, it returns the
147 file's path. If it finds the source file in an archive, it returns a
148 buffer containing the contents of the file. If this function does not
149 find the source for the class, it returns nil."
150   (let* ((verified-name (jde-parse-class-exists class))
151          (outer-class (jde-remove-inner-class verified-name))
152          (file (concat
153                 (jde-parse-get-unqualified-name outer-class)
154                 ".java"))
155          (package (jde-parse-get-package-from-name outer-class)))
156     (catch 'found
157       (loop for path in jde-sourcepath do
158             (progn
159               (setq path (jde-normalize-path path 'jde-sourcepath))
160               (if (and (file-exists-p path)
161                        (or (string-match "\.jar$" path)
162                            (string-match "\.zip$" path)))
163                   (let* ((bufname (concat file " (" (file-name-nondirectory path) ")"))
164                          (buffer (get-buffer bufname)))
165                     (if buffer
166                           (throw 'found buffer)
167                       (let* ((pkg-path (subst-char-in-string ?. ?/ package))
168                              (class-file-name (concat  pkg-path "/" file)) 
169                              success)
170                       (setq buffer (get-buffer-create bufname))
171                       (save-excursion
172                         (set-buffer buffer)
173                         (setq buffer-file-name (expand-file-name (concat path ":" class-file-name)))
174                         (setq buffer-file-truename file)                        
175                         (let ((exit-status 
176                                (archive-extract-by-stdout path class-file-name archive-zip-extract)))
177                           (if (and (numberp exit-status) (= exit-status 0))
178                               (progn
179                                 (jde-mode)
180                                 (goto-char (point-min))
181                                 (setq buffer-undo-list nil)
182                                 (setq buffer-saved-size (buffer-size))
183                                 (set-buffer-modified-p nil)
184                                 (setq buffer-read-only t)
185                                 (throw 'found buffer))
186                           (progn
187                             (set-buffer-modified-p nil)
188                             (kill-buffer buffer))))))))
189                 (if (file-exists-p (expand-file-name file path))
190                     (throw 'found (expand-file-name file path))
191                   (let* ((pkg-path (subst-char-in-string ?. ?/ package))
192                          (pkg-dir (expand-file-name pkg-path path))
193                          (file-path (expand-file-name file pkg-dir)))
194                     (if (file-exists-p file-path)
195                         (throw 'found file-path))))))))))
196     
197
198 (defun jde-find-class-source (class &optional other-window)
199   "*Find the source file for a specified class.
200 Calls `jde-find-class-source-file' to do the search.
201 If it finds the source file, it opens the file in a buffer."
202   (interactive "sClass: ")
203   (let ((source (jde-find-class-source-file class)))
204     (if source
205         (progn
206           (if (typep source 'buffer)
207               (switch-to-buffer source)
208               ;; (pop-to-buffer source other-window)
209             (if (not (string-equal (buffer-file-name)  source))
210                 (if other-window
211                     (find-file-other-window source)
212                   (find-file source))))
213           (if (fboundp 'senator-re-search-forward)
214               (let ((inner-class-pos (string-match "\\$" class)))
215                 (if inner-class-pos
216                     (let ((inner-class (substring class (+ 1 inner-class-pos))))
217                       (when inner-class
218                         (beginning-of-buffer)
219                         (senator-parse)
220                         (senator-re-search-forward (concat "\\b" inner-class "\\b") nil t)))))))
221       (message "JDE error: Could not find source for \"%s\" in this 
222 project's source path. See `jde-sourcepath' for more information." class))))
223
224
225
226 (defun jde-root()
227   "Return the path of the root directory of this JDEE
228 installation. The root directory is the parent of the
229 directory that contains the JDEE's Lisp files. On 
230 Emacs and on XEmacs installations that use the
231 JDEE distributable, the root directory is the root
232 directory that results from unpacking the distributable.
233 On installations based on the version of the JDEE 
234 packaged with XEmacs, the root directory is 
235 xemacs-packages/lisp."
236   (let ((directory-sep-char ?/))
237     (expand-file-name 
238              "../" 
239              (file-name-directory (locate-library "jde")))))
240
241 (defun jde-find-jde-data-directory ()
242   "Return the path of the JDE data directory.
243 Returns the path of the directory containing the
244 JDE java and documentation directories;  nil if the 
245 directory cannot be found. If XEmacs, returns the location of
246 the data directory in the XEmacs distribution hierarchy. On all other Emacs versions, 
247 the JDE expects to find the documentation and Java class directories
248 in the same directory that contains the JDE lisp directory."
249   (let ((directory-sep-char ?/))
250     (if (featurep 'xemacs)
251         (let ((dir (locate-data-directory "jde")))
252           (if dir dir (jde-root)))
253       (jde-root))))
254
255 (defun jde-temp-directory ()
256 "Get the location used by the host system to store temporary files."
257   (or (if (boundp 'temporary-file-directory) temporary-file-directory)
258       (if (fboundp 'temp-directory) (temp-directory)
259         (if (member system-type '(cygwin32 cygwin))
260             (jde-cygwin-path-converter-cygpath (temp-directory))
261           (temp-directory)))))
262
263 (defun jde-get-java-source-buffers ()
264   "Return a list of Java source buffers open in the current session."
265   (delq 
266    nil 
267    (mapcar 
268     #'(lambda (buffer)
269         (with-current-buffer buffer
270           (if (eq major-mode 'jde-mode)
271               buffer)))
272     (buffer-list))))
273
274 (defun jde-get-project-source-buffers (&optional project-file) 
275   "Return a list of the Java source buffers belonging to the project
276 whose project file is PROJECT-FILE. If PROJECT-FILE is not specified,
277 this function returns the buffers belonging to the project in the
278 currently selected source buffer."
279   (let ((proj-file 
280          (or project-file
281              (if (boundp 'jde-current-project)
282                  jde-current-project))))
283     (delq 
284      nil 
285      (mapcar 
286       (lambda (buffer)
287         (with-current-buffer buffer
288          (if (equal jde-buffer-project-file proj-file)
289              buffer)))
290       (jde-get-java-source-buffers)))))
291
292 (defun jde-get-visible-source-buffers ()
293   "Return a list of visible Java source buffers."
294   (delq nil (mapcar #'(lambda (buffer) 
295                         (if (get-buffer-window buffer 'visible)
296                             buffer))
297                     (jde-get-java-source-buffers))))
298
299 (defun jde-get-selected-source-buffer ()
300   (with-current-buffer (window-buffer (selected-window))
301     (if (eq major-mode 'jde-mode)
302         (current-buffer))))
303
304
305 (provide 'jde-util)
306
307 ;; Change History 
308
309 ;;
310 ;; $Log: jde-util.el,v $
311 ;; Revision 1.19.2.2  2006/03/08 12:09:08  paulk
312 ;; Define replace-in-string if necessary.
313 ;;
314 ;; Revision 1.19.2.1  2006/03/01 05:00:58  paulk
315 ;; Fix jde-find-class-source-file to handle inner classes.
316 ;;
317 ;; Revision 1.19  2004/12/17 04:21:25  paulk
318 ;; Create infrastructure for supporting source archives in jde-sourcepath.
319 ;;
320 ;; Revision 1.18  2004/11/10 05:13:28  paulk
321 ;; Clean up jde-find-class-source-file.
322 ;;
323 ;; Revision 1.17  2004/11/09 05:11:24  paulk
324 ;; Enhance jde-find-class-source-file to find class source files stored in jar or zip files. Thanks to Christophe" <plalleme@free.fr>.
325 ;;
326 ;; Revision 1.16  2004/07/06 01:47:42  paulk
327 ;; - Move jde-get-java-source-buffers and allied functions to jde-util.el.
328 ;; - Create jde-get-project-source-buffers.
329 ;; - Replace jde-get-current-project-buffers with jde-get-project-source-buffers.
330 ;;
331 ;; Revision 1.15  2004/06/06 03:54:06  paulk
332 ;; Move subst-char-in-string definition from jde.el to here.
333 ;;
334 ;; Revision 1.14  2004/05/14 03:18:24  paulk
335 ;; Moved jde-line-beginning-position and jde-line-end-position from
336 ;; jde-db.el to jde-util.el. Ultimately, these functions should be
337 ;; replaced by line-beginning-position and line-end-position as
338 ;; jde-xemacs.el provides XEmacs definitions for both functions.
339 ;;
340 ;; Revision 1.13  2004/05/03 17:48:54  paulk
341 ;; Adds jde-require function. Thanks to David Ponce.
342 ;;
343 ;; Revision 1.12  2003/12/08 03:51:51  paulk
344 ;; Fix bug in jde-find-class-source.
345 ;;
346 ;; Revision 1.11  2003/12/08 03:00:18  paulk
347 ;; Update jde-find-class-source to work for inner classes.
348 ;;
349 ;; Revision 1.10  2003/07/15 01:18:39  paulk
350 ;; Add jde-temp-directory function.
351 ;;
352 ;; Revision 1.9  2003/06/27 04:08:11  paulk
353 ;; Expand docstring for jde-root function.
354 ;;
355 ;; Revision 1.8  2003/04/09 04:05:19  paulk
356 ;; Adds jde-root function. Rewrote jde-find-jde-data-directory to use jde-root function.
357 ;;
358 ;; Revision 1.7  2002/08/20 03:09:05  jslopez
359 ;; Fixes bug in jde-find-class-source-file that was not handling
360 ;; inner class properly.
361 ;;
362 ;; Revision 1.6  2002/06/22 06:13:29  paulk
363 ;; Fixed bug in jde-normalize-paths macro.
364 ;;
365 ;; Revision 1.5  2002/05/12 06:48:52  paulk
366 ;; Added jde-with-file-contents jde-normalize-paths jde-search-src-dirs
367 ;; jde-find-class-source-file jde-find-class-source functions.
368 ;;
369 ;; Revision 1.4  2002/03/31 07:49:49  paulk
370 ;; Renamed jde-db-source-directories. The new name is jde-sourcepath.
371 ;;
372 ;; Revision 1.3  2002/02/03 06:52:54  paulk
373 ;; Fixed quote bug in jde-assert-source-buffer macro.
374 ;;
375 ;; Revision 1.2  2002/01/19 06:42:22  paulk
376 ;; Minor updates.
377 ;;
378 ;; Revision 1.1  2002/01/04 07:15:20  paulk
379 ;; Initial revision.
380 ;;
381
382 ;; End of jde-util.el
383