Initial Commit
[packages] / xemacs-packages / jde / lisp / jde-package.el
1 ;; jde-package.el -- Java package statement generator
2 ;; $Id: jde-package.el,v 1.10 2002/12/19 06:39:44 paulk Exp $
3
4 ;; Copyright (C) 1998, 2000, 2001, 2002 by David Ponce
5
6 ;; Author:       David Ponce <david@dponce.com>
7 ;; Maintainer:   David Ponce <david@dponce.com>
8 ;;               Paul Kinnucan <paulk@mediaone.net>
9 ;; Created:      September 28 1998
10
11 ;; This file is not part of Emacs
12
13 ;; This program is free software; you can redistribute it and/or
14 ;; modify it under the terms of the GNU General Public License as
15 ;; published by the Free Software Foundation; either version 2, or (at
16 ;; your option) any later version.
17
18 ;; This program is distributed in the hope that it will be useful, but
19 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 ;; General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with this program; see the file COPYING.  If not, write to
25 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
27
28 ;;; Commentary:
29 ;;
30 ;; This package automatically generates a Java package statement.  The
31 ;; package name is deducted from the current classpath setting of
32 ;; JDE.  When a directory found in classpath is a root of the current
33 ;; buffer default directory, the relative path of the default
34 ;; directory from the classpath one becomes the package name by
35 ;; substituting directory separators by '.'.
36 ;;
37 ;; For example:
38 ;;
39 ;;   The JDE classpath setting is:
40 ;;
41 ;;    ("~/java")
42 ;;
43 ;;   For the file "~/java/FR/test/MyClass.java", the package name
44 ;;   generated will be "FR.test".
45 ;;
46 ;;   The JDE classpath setting is:
47 ;;
48 ;;    ("~/java" "~/java/test")
49 ;;
50 ;;   For the file "~/java/test/MyClass.java",
51 ;;   `jde-package-default-package-comment' will be generated because
52 ;;   the default package can be used.
53 ;;
54 ;;   The JDE classpath setting is:
55 ;;
56 ;;    ("~/java")
57 ;;
58 ;;   For the file "/usr/java/MyClass.java", no package name will be
59 ;;   generated because the directory "/usr/java" is not accessible
60 ;;   from classpath.
61 ;;
62 ;; Usage:
63 ;;
64 ;; M-x `jde-package-update' to update the Java package statement or
65 ;; insert a new one at beginning of current buffer.
66 ;;
67 ;; The function `jde-package-generate-package-statement' should be
68 ;; used in Java template to automatically generate the package
69 ;; statement.
70 ;;
71 ;; Customization:
72 ;;
73 ;; The following variables could be set:
74 ;;
75 ;; - `jde-package-load-hook' hook run when package has been loaded.
76 ;;
77 ;; - `jde-package-package-comment' Java line comment appended to the
78 ;;   generated package statement.  Default is " // Generated package
79 ;;   name"
80 ;;
81 ;; - `jde-package-default-package-comment' Java line comment generated
82 ;;   when the default package is used.  Default is "// Default package
83 ;;   used"
84 ;;
85 ;; - `jde-package-search-classpath-variables' list of variables where
86 ;;   to search the current classpath list.  Default is
87 ;;   '(`jde-compile-option-classpath' `jde-global-classpath')
88
89 ;;; History:
90 ;;
91 ;; See at end of this file.
92
93 ;;; Code:
94 (defconst jde-package-unknown-package-name
95   "*unknown*"
96   "The string returned when a package name can't be generated.")
97
98 (defconst jde-package-package-regexp
99   "package .*;.*$"
100   "The regexp used to find the Java package statement.")
101
102 (defgroup jde-package nil
103   "jde-package package customization"
104   :group 'jde
105   :prefix "jde-package-")
106
107 (defcustom jde-package-load-hook nil
108   "*Hook run when package has been loaded."
109   :group 'jde-package
110   :type 'hook)
111
112 (defcustom jde-package-package-comment
113   " // Generated package name"
114   "*Java line comment appended to the generated package statement.
115 An empty string suppress the generation of this comment."
116   :group 'jde-package
117   :type 'string)
118
119 (defcustom jde-package-default-package-comment
120   "// Default package used"
121   "*Java line comment generated when the default package is used.
122 An empty string suppress the generation of this comment."
123   :group 'jde-package
124   :type 'string)
125
126 (defcustom jde-package-search-classpath-variables
127   '(jde-compile-option-classpath jde-global-classpath)
128   "*Specify the variables where to search the current classpath list.
129 The first one which has a non nil value will be used by jde-package."
130   :group 'jde-package
131   :type '(repeat variable))
132
133
134 (defun jde-package-get-classpath ()
135   "Return the current classpath list.
136 That is to say the first non-nil value found in the variables given by
137 `jde-package-search-classpath-variables'."
138   (let ((search-in jde-package-search-classpath-variables)
139         (classpath))
140     (while (and search-in (not classpath))
141       (setq classpath (symbol-value (car search-in))
142             search-in (cdr search-in)))
143     classpath))
144
145 (defun jde-package-get-directories-in-classpath ()
146   "Return the list of directories found in classpath."
147   (mapcan
148    (lambda (path)
149        (if (or jde-resolve-relative-paths-p
150               (not   (string= path "."))) ; "." is ignored in classpath         
151            (let ((path (jde-normalize-path path)))
152              (if (file-directory-p path)
153                  (list (file-name-as-directory path))))))
154    (jde-package-get-classpath)))
155
156
157 (defun jde-package-seach-package-directories ()
158   "Return a list of package directory candidates or nil if not found."
159   (let ((dir (jde-normalize-path default-directory))
160         ;; case-insensitive for Windows
161         (case-fold-search (eq system-type 'windows-nt)))
162     (mapcan
163      (lambda (root)
164          (let ((root (regexp-quote root)))
165            (message "Seaching %S in %S..." root dir)
166            (and (string-match root dir)
167                 (list (substring dir (match-end 0))))))
168      (append (jde-package-get-directories-in-classpath)
169              (mapcar
170               (lambda (p)
171                 (file-name-as-directory 
172                  (jde-normalize-path p 'jde-sourcepath)))
173               jde-sourcepath)))))
174
175 (defun jde-package-best-package-candidate (candidates)
176   "Return the best package directory candidate from CANDIDATES.
177 The best is the shortest one that could be found."
178   (car (sort candidates
179              (lambda (dir1 dir2)
180                  (string-match (regexp-quote dir1) dir2)))))
181
182 (defun jde-package-get-package-directory ()
183   "Return the package directory, if found; otherwise,
184 `jde-package-unknown-package-name'."
185   (or (jde-package-best-package-candidate
186        (jde-package-seach-package-directories))
187       jde-package-unknown-package-name))
188
189
190 (defun jde-package-convert-directory-to-package (dir)
191   "Convert directory path DIR to a valid Java package name.
192 Replace ?/ by ?. and remove extra ?/ at end."
193   (if (string= dir "")
194       ""
195     (subst-char-in-string
196      ?/ ?.
197      (substring (file-name-as-directory dir) 0 -1)
198      t)))
199
200 (defun jde-package-generate-package-statement ()
201   "Generate a Java package statement for the Java source file in the
202 current buffer, if the package name can be determined; otherwise,
203 an empty string."
204   (let* (
205          ;; The JDE always uses ?/ as directory separator so ensure
206          ;; [X]Emacs uses the same one when running on Windows!
207          (directory-sep-char ?/)
208          (package-name (jde-package-get-package-directory)))
209     (cond
210      ((string= package-name jde-package-unknown-package-name)
211       (message
212        "The current directory is not accessible from classpath.")
213       "")
214      ((string= package-name "")
215       (message "Default package used.")
216       jde-package-default-package-comment)
217      (t
218       (message "package %s;%s"
219                (jde-package-convert-directory-to-package package-name)
220                jde-package-package-comment)))))
221
222 ;;;###autoload
223 (defun jde-package-update ()
224   "Create or update the package statement in the current Java source
225 file buffer based on the file's location relative to the root of
226 the package directory as specified by one of the entries in
227 `jde-package-search-classpath-variables' or `jde-sourcepath'.
228 If these variables do not specify the root of the package directory,
229 this command does nothing. This command signals an error if the
230  major mode of the current buffer is not `jde-mode'."
231   (interactive)
232   (or (eq major-mode 'jde-mode)
233       (error "Invalid major mode found.  Must be `jde-mode'"))
234   (let ((package (jde-package-generate-package-statement)))
235     (unless (string= package "")
236       (goto-char (point-min))
237       (if (re-search-forward jde-package-package-regexp nil t)
238           (replace-match package)
239         (insert package)
240         (newline)))))
241
242 ;; Register and initialize the customization variables defined
243 ;; by this package.
244 (jde-update-autoloaded-symbols)
245
246 (provide 'jde-package)
247 (run-hooks 'jde-package-load-hook)
248
249 ;;; Change History:
250
251 ;;
252 ;; $Log: jde-package.el,v $
253 ;; Revision 1.10  2002/12/19 06:39:44  paulk
254 ;; Update customization variables when jde-package.el is loaded.
255 ;;
256 ;; Revision 1.9  2002/12/19 06:13:15  paulk
257 ;; Fixed a bug caused by treating "." as a standard relative path character
258 ;; instead of a project file relative path character.
259 ;; Fixed and expanded some doc strings.
260 ;;
261 ;; Revision 1.8  2002/05/29 04:18:03  paulk
262 ;; Add the directories from jde-sourcepath to the
263 ;; directories considered when trying to derive a package name.
264 ;; Thanks to Michael N. Lipp <mnl@mnl.de>.
265 ;;
266 ;; Revision 1.7  2002/03/04 02:36:22  jslopez
267 ;; Removes extra log entries.(it was duplicated)
268 ;;
269 ;; Revision 1.6  2001/06/07 03:31:00  paulk
270 ;; Fixed NT/XEmacs incompatibility caused by XEmacs' use of back slash as the directory path separator. Thanks to David Ponce.
271 ;;
272 ;; Revision 1.5  2001/04/09 05:01:03  paulk
273 ;; Fixed bug in jde-package-get-directories-in-classpath that caused it to return t instead of a list when the classpath contained ".".
274 ;;
275 ;; Revision 1.4  2001/03/30 07:10:31  paulk
276 ;; Minor code improvement and cleanup and many checkdoc related
277 ;; cosmetic changes contributed by David Ponce.
278 ;;
279 ;; Revision 1.3  2001/03/13 04:23:58  paulk
280 ;; Cosmetic changes.
281 ;;
282 ;; Revision 1.2  2001/02/22 03:36:30  paulk
283 ;; Removed require for jde to fix infinite recursion loading bug.
284 ;;
285 ;; Revision 1.1  2001/02/21 05:52:02  paulk
286 ;; Initial revision.
287 ;;
288
289 ;;; jde-package.el ends here.