1 ;; jde-import.el --- Organize Java imports
3 ;; Copyright (C) 2000, 2001, 2002, 2003, 2004 by David Ponce
4 ;; Copyright (C) 2004 by Philip Lord
6 ;; Authors: David Ponce <david@dponce.com>
7 ;; Paul Kinnucan <paulk@mathworks.com>
8 ;; Maintainers: David Ponce <david@dponce.com>
9 ;; Paul Kinnucan <paulk@mathworks.com>
10 ;; Martin Schwamberger <mschw@web.de>
11 ;; Created: 15 Nov 2000
12 ;; Version: $Revision: 1.46 $
13 ;; Keywords: java, tools
14 ;; VC: $Id: jde-import.el,v 1.46 2004/12/12 14:27:02 paulk Exp $
16 ;; This file is not part of Emacs
18 ;; This program is free software; you can redistribute it and/or
19 ;; modify it under the terms of the GNU General Public License as
20 ;; published by the Free Software Foundation; either version 2, or (at
21 ;; your option) any later version.
23 ;; This program is distributed in the hope that it will be useful, but
24 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
25 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 ;; General Public License for more details.
28 ;; You should have received a copy of the GNU General Public License
29 ;; along with this program; see the file COPYING. If not, write to
30 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
31 ;; Boston, MA 02111-1307, USA.
35 ;; This library adds commands to the JDE to insert and organize Java import
41 (require 'semantic-fw)
42 (require 'semantic-find)
43 (require 'semantic-util)
50 ;; (makunbound 'jde-import-excluded-classes)
51 (defcustom jde-import-excluded-classes
53 ("^java\\.lang\\.[^.]*$" . t)
55 ("^com\\.sun\\..*" . nil)
56 (jde-import-current-package-p . t))
57 "*Specifies classes that should not be imported into a source file.
58 \"Exclude test\" should be either a regular expression or a function
59 whose only argument is the fully qualified class name.
60 Import commands excludes any classes whose fully qualified name matches
61 \"Regexp\" and any classes for which the \"Test function\" returns non-nil.
62 If \"Exclude synonyms\" is non-nil, all classes with the same unqualified name
63 will also be excluded. This is useful for classes of packages which will be
64 imported implicitly (i.e. java.lang.* and the package of the importing class).
65 If more than one fully qualified class names match the unqualified name that you specify,
66 the command prompts you to select only the classes that are not excluded."
69 (cons :tag "Exclude rule"
70 (choice :tag "Exclude test"
71 (regexp :tag "Regexp")
72 (function :tag "Test function"))
73 (boolean :tag "Exclude synonyms"))))
75 ;; auto sorting of import statements
76 (defcustom jde-import-auto-sort nil
77 "*Automatically resort import statements after a `jde-import-import'.
78 If non-nil, the JDE automatically resorts the import statements when a new import statement is added using `jde-import-import' or `jde-import-find-and-import'."
83 (defcustom jde-import-auto-sort-function 'jde-import-sort
84 "*Function to call to automatically sort imports statements after a `jde-import-import'.
85 Usually `jde-import-sort' or `jde-import-organize'. Enabled if `jde-import-auto-sort' is not nil."
89 (defcustom jde-import-reverse-sort-group nil
90 "*Non-nil to sort each import group's packages in reverse alphabetic
91 order. See command `jde-import-organize'. Note: For sorting the
92 groups, see variable `jde-import-sorted-groups'."
96 (defcustom jde-import-sorted-groups nil
97 "*Non-nil to sort import groups in alphabetic order. Order may
98 be specified as alphabetic, reverse alphabetical or as implicitly
99 specified by `jde-import-group-of-rules'. In the latter case the
100 order of groups is the same as their appearance in
101 `jde-import-group-of-rules'.
102 See command `jde-import-organize'. Note: For sorting the packages
103 within each group, see variable `jde-import-reverse-sort-group'."
105 :type '(choice :tag "Order"
106 (const :tag "No sort" nil)
107 (const :tag "group-of-rules order" gor)
108 (const :tag "alphabetic order" asc)
109 (const :tag "reverse alphabetic order" desc)))
111 (defcustom jde-import-group-function 'jde-import-group-of
112 "*Function used to associate an import token to a group.
113 It receives one argument, the import token and must return a group
114 name string or nil if the import does not belong to any group. The
115 function `jde-import-group-of' is the default value."
119 (defcustom jde-import-group-of-rules
123 "*Import group definitions used by `jde-import-group-of'.
124 Each group definition is a pair (REGEXP . GROUP) where:
125 - - REGEXP is a regexp that import names of this group must match.
126 - - GROUP is a group name or the index of the match data returned as
127 group name or nil if REGEXP is the group name."
130 (cons :tag "Group Rule"
132 (choice :tag "Group Name"
133 (string :tag "A String")
134 (integer :tag "Match data at")
135 (const :tag "The Regexp" nil))))
136 :set '(lambda (sym val)
137 ;; delete empty entries!
138 (set-default sym (delete '("") val))))
140 (defcustom jde-import-default-group-name nil
141 "*Default group name if no group name is found.
142 If a group name is not found in `jde-import-group-of-rules' then this
143 group name is used. If nil no default group name is used."
145 :type '(choice (string :tag "A String")
146 (const :tag "none" nil)))
148 (defcustom jde-import-insert-group-names nil
149 "*If non-nil `jde-import-organize' inserts group name before imports.
150 See also the options `jde-import-group-of-rules' and
151 `jde-import-default-group-name'."
155 ;; (makunbound 'jde-import-blank-line-between-groups)
156 (defcustom jde-import-blank-line-between-groups t
157 "*If non-nil `jde-import-organize' inserts a blank line between groups.
158 See also the options `jde-import-group-of-rules' and
159 `jde-import-default-group-name'."
163 (defcustom jde-import-auto-collapse-imports nil
164 "*If non-nil jde will automatically collapse imports when imports are
169 (defun jde-import-current-package-p (class)
170 "Returns non-nil if the fully qualified classname CLASS belongs to
171 the same package as the class in the current buffer."
172 (if (jde-parse-get-package-name)
174 (concat (regexp-quote (jde-parse-get-package-name)) "\\.[^.]*$")
177 (defun jde-import-get-qualified-names (unqualified-class)
178 "Returns a list containing all qualified name for UNQUALIFIED-CLASS."
181 "jde.util.JdeUtilities.getQualifiedName(\""
182 unqualified-class "\");")))
184 (defun jde-import-get-imports ()
185 "Returns a list containing all imported classes."
187 (tags (semantic-fetch-tags))
188 (import-tags (semantic-brute-find-tag-by-class 'include tags)))
189 (dolist (import-tag import-tags)
192 (semantic-tag-name import-tag)
196 (defun jde-import-get-import (unqualified-class)
197 "Get imported name for unqualified name UNQUALIFIED-CLASS.
198 This name may have the form \"package.*\". Returns nil,
199 if there is no import statement for UNQUALIFIED-CLASS."
201 (imports (jde-import-get-imports))
202 (qualified-names (jde-import-get-qualified-names unqualified-class)))
204 (dolist (class qualified-names)
205 (if (setq import (jde-import-already-imports-class class imports))
206 (throw 'found import))))))
208 (defun jde-import-get-import-insertion-point ()
209 "Determine where to insert an import statement.
210 If the buffer contains an import statement, return
211 the beginning of the next line; otherwise, if
212 the buffer contains a package statement, insert
213 three empty lines and return the beginning of
214 the second empty line; otherwise, if the buffer
215 contains a class definition, return the beginning
216 of the line before the class definition; otherwise,
217 return the beginning of the buffer."
218 (let* ((tags (semantic-fetch-tags))
220 (car (last (semantic-brute-find-tag-by-class
222 (package-tag (car (semantic-brute-find-tag-by-class
224 (class-tag (car (semantic-brute-find-tag-by-class
228 (setq insertion-point (+ (semantic-tag-end import-tag) 1)))
231 (goto-char (semantic-tag-end package-tag))
234 (setq insertion-point (point))))
236 (setq insertion-point
237 (let ((comment-token (semantic-documentation-for-tag
240 (semantic-lex-token-start comment-token)
241 (semantic-tag-start class-tag)))))
243 (setq insertion-point 1)))
245 (goto-char insertion-point)
246 (unless (and (bolp) (eolp)) (insert "\n")))
249 (defun jde-import-import (class)
250 "*Insert an import statement for a class in the current buffer.
251 CLASS is the fully qualified name of the class to be imported. This
252 function allows you to enter an import at the head of your buffer
253 from any point in the buffer. The function does nothing if an
254 import statement for the specified class already exists.
255 The function does not exclude classes defined by `jde-import-excluded-classes'."
258 (jde-import-insert-import (list class)))
260 (defun jde-import-one-class (class)
261 "Insert an import into the buffer if not already there."
263 (if (not (jde-import-already-imports-class class (jde-import-get-imports)))
264 (jde-import-insert-imports-into-buffer (list class))))
266 ;; Contributed by David Ponce <david_ponce@mail.schneider.fr>
267 (defun jde-import-sort (&optional reverse)
268 "Sort Java import statements alphabetically. In reverse order if
272 \\[jde-import-sort] sort import statements ascending.
273 \\[universal-argument] \\[jde-import-sort] sort descending.
275 The the current buffer must be in `jde-mode'. This command uses the
276 semantic Java parser and requires JDE 2.1.6-beta24 and above."
278 (or (eq major-mode 'jde-mode)
279 (error "Invalid major mode found. Must be 'jde-mode'."))
280 (or (and (local-variable-p 'semantic--parse-table (current-buffer))
281 (symbol-value 'semantic--parse-table))
282 (error "Semantic Java parser not found."))
284 (consp current-prefix-arg)
286 (let* ((tags (semantic-fetch-tags))
287 (depends (semantic-brute-find-tag-by-class 'include tags)))
289 (let* ((first-import-tag (car depends))
290 (last-import-tag (nth (1- (length depends)) depends))
291 (start (semantic-tag-start first-import-tag))
292 (end (semantic-tag-end last-import-tag)))
293 (when (and start end)
295 (let (sort-fold-case)
296 (sort-lines reverse start end)
297 (goto-char start)))))))
299 (defun jde-import-find-and-import (class &optional no-errors no-exclude)
300 "*Insert an import statement for a class in the current buffer.
301 CLASS is an unqualified class name. This function searches
302 the classpath for a class (or classes) that match CLASS. If it
303 finds only one, it inserts an import statements for the class at the
304 head of the current buffer. If it finds more than one class that matches
305 CLASS, it prompts you to select which class to import. You can customize
306 the variable `jde-import-excluded-classes' to prevent specified classes
307 from being imported or considered for import. If the prefix argument NO-EXCLUDE
308 is non-nil, jde-import-excluded-classes will be ignored.
309 This command uses the JDE's BeanShell interpreter. It starts the interpreter
310 if it is not already running so there may be a short delay generating the first
311 import statement in the session. Note that you must explicitly include
312 any directories or jars that you want the command to search in your
313 classpath, except jars implicitly included by the jvm, e.g.,
314 rt.jar. The NO-ERRORS is used to avoid showing erros to the user."
316 (list (read-from-minibuffer "Class: "
317 (thing-at-point 'symbol))
320 (let (existing-import)
321 (setq existing-import (jde-import-get-import class))
322 (if (not (null existing-import))
323 (message "Skipping: already imported %s" existing-import)
324 (let ((imports (jde-import-get-qualified-names class)))
325 (setq imports (remove-duplicates imports :test 'equal))
327 (jde-import-insert-import imports (not no-exclude))
329 (message "Error: could not find %s." class)))))))
331 (defun jde-import-exclude-imports (imports)
332 "Remove imports from IMPORTS according to `jde-import-excluded-classes'."
333 (if jde-import-excluded-classes
334 (let (synonym-list ; synonyms to be excluded
336 ;; Exclude all imports matching an element of jde-import-excluded-classes
337 ;; and collect all synonyms to be excluded.
338 (setq remaining-imports
342 (dolist (rule jde-import-excluded-classes)
344 (string-match "[.]" import)
345 (if (functionp (car rule))
346 (funcall (car rule) import)
347 (string-match (car rule) import)))
348 (message "Excluding %s." import)
349 (when (cdr rule) ; exclude all classes having same name?
351 (cons (jde-parse-get-unqualified-name import) synonym-list)))
355 ;; Exclude all synonyms contained in synonym-list.
356 (setq remaining-imports
361 (dolist (synonym synonym-list)
362 (when (string-match (concat (regexp-quote synonym) "$") import)
363 (message "Excluding synonym %s." import)
367 ;; Remove all nil inserted instead of excluded classes.
368 (delq nil remaining-imports))
371 (defun jde-import-insert-import (new-imports &optional exclude)
372 "Asks user, if necessary, to choose one of NEW-IMPORTS and
373 inserts the selected import in the buffer."
374 (let* ((existing-imports (jde-import-get-imports))
375 (candidate-imports (if exclude
376 (jde-import-exclude-imports new-imports)
379 (if (> (length candidate-imports) 1)
380 (jde-import-choose-import candidate-imports)
381 (car candidate-imports))))
383 (if (jde-import-already-imports-class new-import existing-imports)
384 (message "This buffer already imports %s" new-import)
385 (jde-import-insert-imports-into-buffer (list new-import))))))
387 (defun jde-import-insert-imports-into-buffer (new-imports &optional exclude)
388 "Inserts imports into the correct place in the buffer."
390 (goto-char (jde-import-get-import-insertion-point))
391 (if (not jde-xemacsp) (deactivate-mark))
393 (setq new-imports (jde-import-exclude-imports new-imports)))
394 (loop for new-import in new-imports do
395 (when (> (length new-import) 0) ;; added to avoid insert empty import statements.
397 (concat "import " new-import ";\n"))
398 (message "Imported %s" new-import)))
399 (if jde-import-auto-collapse-imports
400 (let (jde-import-auto-collapse-imports) ;; setting this to avoid infinite recursion
401 (jde-import-collapse-imports)))
402 (if jde-import-auto-sort
403 (funcall jde-import-auto-sort-function))))
406 (defun jde-import-already-imports-class (class-name existing-imports)
407 "Determine if a class is already being imported."
411 :test (lambda (new existing)
412 (let ((new-package (jde-parse-get-package-from-name new))
413 (new-class (jde-parse-get-unqualified-name new))
414 (existing-package (jde-parse-get-package-from-name existing))
415 (existing-class (jde-parse-get-unqualified-name existing)))
417 (string= new-package existing-package)
419 (string= new-class existing-class)
420 (string= existing-class "*")))))))
422 (defun jde-import-strip-existing-imports (new-imports existing-imports)
423 "Exclude classes that have already been imported."
428 (unless (jde-import-already-imports-class new-import existing-imports)
432 (defun jde-import-choose-import (new-imports)
433 "Prompts the user to select a class to import from a list of similarly
437 "Select import to insert."
438 "Classes name dialog"))
440 (defun jde-import-kill-extra-imports (&optional comment)
441 "Delete extra Java import statements.
442 An import statement is considered extra if it is a duplicate,
443 imports a class from the package to which this file belongs,
444 it is not referenced in the file,
445 or imports a class belonging to an already imported package, i.e.,
446 a package already imported by an import statement ending in .*.
447 If optional argument COMMENT is non-nil, the extra import statements
448 are commented out instead of deleted.
451 \\[jde-import-kill-extra-imports]
452 to kills extra imports.
453 \\[universal-argument] \\[jde-import-kill-extra-imports]
454 to comment out extra imports.
456 The current buffer must be in `jde-mode'."
458 (or (eq major-mode 'jde-mode)
459 (error "Major mode must be 'jde-mode'"))
461 (consp current-prefix-arg)
463 (let* ((tags (semantic-fetch-tags))
464 (imports (semantic-brute-find-tag-by-class 'include tags)))
466 (message "No import found")
467 (let* ((packages (semantic-brute-find-tag-by-class 'package tags))
472 ;; Return a global import name from PACKAGE tag.
473 ;; That is add ".*" at end of tag name.
474 (concat (semantic-tag-name package) ".*"))
479 ;; Return tag name if IMPORT is global or nil if not.
480 ;; IMPORT is global if its name ends with ".*".
481 (let ((name (semantic-tag-name import)))
482 (and (string-match "[.][*]\\'" name)
485 (first-import (car imports))
489 ;; Get the list of extra imports
490 ;; Going to character zero so the the count-matches method work.
493 (let* ((import (car imports))
494 (name (semantic-tag-name import))
495 (classname (jde-import-get-classname name))
496 (case-fold-search nil)
498 (substring (count-matches
499 (concat "\\b" classname "\\b")) 0 2)))
501 ;; If name is already listed in the set
502 ;; of required imports...
503 (member name required-imports)
504 ;;or the class is not reference in the file
505 ;;and is not an import of the whole package i.e. .*
506 (and (< (string-to-number number-of-matches) 2)
507 (not (string= classname "*")))
508 ;; or imports a class in the current package...
510 ;; make sure name is not a package import, e.g., foo.bar.*
511 (not (string-match "[.][*]\\'" name))
513 ;; convert class import to equivalent package import
514 ;; e.g., foo.barClass to foo.*
519 (or (string-match "[.][^.]+\\'" name)
523 ;; add name to the list of extra imports...
524 (setq extra-imports (cons import extra-imports))
525 ;; otherwise add to the list or required imports
526 (setq required-imports (cons name required-imports))))
527 (setq imports (cdr imports)))
528 (if (not extra-imports)
529 (message "No extra imports found")
531 ;; Move the point at the beginning of the first import
532 (goto-char (semantic-tag-start first-import))
533 ;; Kill or comment out extra imports
535 (let* ((extra-import (car extra-imports))
536 (start (semantic-tag-start extra-import))
537 (end (semantic-tag-end extra-import)))
538 (setq count (1+ count))
540 (comment-region start end)
541 ;; The following assumes that there is only one import
542 ;; statement on the same line. Line end comments are deleted
549 (setq extra-imports (cdr extra-imports))))
550 (message "%d extra import%s removed"
551 count (if (= count 1) "" "s")))))))))
554 ;;;; Helper functions
557 (defun jde-import-get-classname(import)
558 "Takes as an argument an import i.e. java.util.Vector.
559 And returns the class name. In the above example it will
561 (let ((pieces (split-string import "\\.")) class)
562 (setq class (car (last pieces)))
563 (setq pieces (split-string class "\\$"))
564 (setq class (car (last pieces)))
567 (defun jde-import-group-of (import-tag)
568 "Return the group IMPORT-TAG belongs to or nil if not found.
569 A group is found as soon as the import name matches a regexp in
570 `jde-import-group-of-rules'. The returned group name depends on the
571 corresponding group definition in `jde-import-group-of-rules'."
572 (let ((import-name (semantic-tag-name import-tag))
573 (groups jde-import-group-of-rules)
574 match rule regexp group)
575 (while (and groups (not match))
576 (setq rule (car groups)
580 match (and (string-match regexp import-name)
581 (cond ((stringp group)
584 (match-string group import-name))
589 (defun jde-import-bucketize (imports)
590 "Bucketize IMPORTS tags.
591 Return a vector of buckets. Each bucket is sorted alphabetically by
592 import name or in reverse order if `jde-import-reverse-sort-group' is
593 non-nil. There is a bucket for each different group the function
594 specified by `jde-import-group-function' returns. The last extra
595 bucket contains imports that do not belong to any group."
596 (let (import group others bins bin i n)
597 ;; Sort imports into an alist of groups. Build a separate list
598 ;; for imports not in any group.
600 (setq import (car imports)
601 imports (cdr imports)
602 group (funcall (or jde-import-group-function
603 #'jde-import-group-of)
606 (setq others (cons import others))
607 (setq bin (assoc group bins))
609 (setcdr bin (cons import (cdr bin)))
610 (setq bins (cons (cons group (list import)) bins)))))
611 ;; If required sort the bins by group name
612 ;; Remember that bins are in reverse order at this point.
613 (cond ((eq jde-import-sorted-groups 'asc)
614 (setq bins (sort bins
617 (string-lessp (car bin2)
619 ((eq jde-import-sorted-groups 'desc)
620 (setq bins (sort bins
623 (string-lessp (car bin1)
625 ((eq jde-import-sorted-groups 'gor)
626 (let* ((group-list (mapcar (function
627 (lambda (item) (cdr item)))
628 jde-import-group-of-rules)))
633 (let* ((name1 (car bin1))
635 (idx1 (length (member name1 group-list)))
636 (idx2 (length (member name2 group-list))))
637 (< idx1 idx2)))))))))
638 ;; Build the vector of buckets.
642 (cons (cons jde-import-default-group-name
649 (setq bin (aref bins i))
650 (setcdr bin (if jde-import-reverse-sort-group
651 (semantic-sort-tags-by-name-decreasing (cdr bin))
652 (semantic-sort-tags-by-name-increasing (cdr bin))))
656 (defun jde-import-insert-group (group &optional skip-line name)
657 "Insert a GROUP of import texts in the current buffer.
658 If optional SKIP-LINE is non-nil skip a line before the group.
659 If optional NAME is non-nil add it as comment just before the group."
663 (if jde-import-blank-line-between-groups
665 (when (and jde-import-insert-group-names name)
666 (insert comment-start name)
669 (setq group (cdr group))
673 (setq group (cdr group)))))
680 (defun jde-import-organize (&optional force)
681 "Organize import statements of the current Java source buffer.
682 If optional FORCE is non-nil force reordering even if imports are
685 Imports are organized into groups returned by the function specified
686 by `jde-import-group-function'. Groups are inserted in the order they
687 are found unless `jde-import-sorted-groups' requires that they must be
688 alphabetically sorted. In each group imports are sorted by name
689 alphabetically or in reverse order if `jde-import-reverse-sort-group'
690 is non-nil. A blank line is inserted between groups.
693 \\[jde-import-organize] group and sort import statements.
694 \\[universal-argument] \\[jde-import-organize] to force reordering.
696 The current buffer must be in `jde-mode'. This command requires a
697 version of the JDE with the semantic parser."
699 (or (eq major-mode 'jde-mode)
700 (error "Major mode must be 'jde-mode'"))
702 (consp current-prefix-arg)
705 (let* ((tags (semantic-fetch-tags))
706 (imports (semantic-brute-find-tag-by-class 'include tags)))
708 (let* ((bins (jde-import-bucketize imports))
710 i l sl changed group bin)
713 ;; Check if imports already ordered
714 (setq sl (apply #'append (mapcar #'cdr bins))
716 (while (and (not changed) l)
717 (setq changed (not (string-equal
718 (semantic-tag-name (car l))
719 (semantic-tag-name (car sl))))
723 (message "Import statements already ordered")
724 ;; Imports need to be reordered.
725 ;; 1- Get ordered import texts
728 (setq bin (aref bins i))
729 (setcdr bin (mapcar (function
731 (buffer-substring-no-properties
732 (semantic-tag-start import)
734 (goto-char (semantic-tag-end import))
735 (end-of-line) ; keep any line comment
739 ;; 2- Keep the point at the beginning of the first import
740 (goto-char (semantic-tag-start (car imports)))
741 ;; 2b- But check if the previous line already contains the
742 ;; group name for the first group
743 (when jde-import-insert-group-names
745 (while (and (< i n) (not group))
746 (setq group (aref bins i)
750 (if (not (string< (concat comment-start (car group))
751 (thing-at-point 'line)))
754 ;; 3- Kill current imports
757 (goto-char (semantic-tag-end
758 (car (reverse imports))))
761 ;; 4- Insert ordered imports
762 ;; Insert the first group found
764 (while (and (< i n) (not group))
765 (setq group (aref bins i)
767 (jde-import-insert-group (cdr group) nil (car group))
768 ;; Insert the others with a blank line before each group
770 (setq group (aref bins i)
772 (jde-import-insert-group (cdr group) 'skip-line (car group)))))))))
774 (defcustom jde-import-collapse-imports-threshold 2
775 "Threshold level used by `jde-import-collapse-imports' to decide when a
776 package star import is used instead of single imports. If N is the number of
777 classes imported by the current buffer from a package and N is >= to the
778 threshhold, the JDEE replaces the class imports with a package import.
779 Setting the threshold to 0 causes the JDE to not collapse anything at
784 (defun jde-import-collapse-imports (&optional comments)
785 "Function that collapse multiple class imports from the same package
786 into a single .* package import. Uses
787 `jde-import-collapse-imports-threshold' to decide when a .* statement
788 is generated. Implemented by adding the package statements and then
789 invoking `jde-import-kill-extra-imports' to clean up."
791 (or (eq major-mode 'jde-mode)
792 (error "Major mode must be 'jde-mode'"))
793 (let* ((tags (semantic-fetch-tags))
794 (imports (semantic-brute-find-tag-by-class 'include tags)))
795 (if (<= jde-import-collapse-imports-threshold 0)
796 (message "Collapse threshold set to zero. No collapsing will occur.")
798 (message "No import found")
799 (let* ((package-buckets (jde-import-collapse-imports-bucketize imports))
801 (required-imports nil)
803 (while package-buckets
805 ((bucket (car package-buckets)))
806 (if (>= (length bucket) jde-import-collapse-imports-threshold)
808 (add-to-list 'extra-imports (cdr bucket))
809 ;; Add the collapsing package statement
810 (add-to-list 'new-imports (concat (car bucket) ".*")))
811 (add-to-list 'required-imports (cdr bucket))))
812 (setq package-buckets (cdr package-buckets)))
813 (jde-import-insert-imports-into-buffer new-imports)
814 (jde-import-kill-extra-imports comments))))))
817 ;; Contributed by Martin Schwamberger.
818 (defun jde-import-expand-imports (&optional no-exclude)
819 "Delete all package imports and replace them by their respective
820 class imports. The replacement is done by `jde-import-all'.
821 `jde-import-auto-collapse-imports' is temporarily disabled during the
822 execution of `jde-import-all'. The optional prefix argumet NO-EXCLUDE
823 is used by `jde-import-all'. This function is roughly the opposite of
824 `jde-import-collapse-imports'."
826 (let* ((tags (semantic-fetch-tags))
827 (imports (semantic-brute-find-tag-by-class 'include tags))
831 jde-import-auto-collapse-imports) ; disable auto collapse
832 (dolist (import imports)
833 (when package-import-start
834 ;; kill from start of package-import to beginning of following import
835 (kill-region package-import-start (semantic-tag-start import))
837 (setq package-import-start nil))
838 (when (string-match "\\.\\*" (semantic-tag-name import)) ; package-import?
839 (setq package-import-start (semantic-tag-start import))
840 (setq package-import-end (semantic-tag-end import))))
842 (when package-import-start
843 ;; kill from start of package-import to end of line
844 (kill-region package-import-start
846 (goto-char package-import-end)
848 (or (eobp) (forward-char))
852 (jde-import-all no-exclude))))
855 (defun jde-import-collapse-imports-bucketize (imports)
856 "Put all imports into a bucket named as the package they belong to."
857 (let ((package-buckets))
859 (let* ((import (car imports))
860 (name (semantic-tag-name import))
861 (packagename (jde-parse-get-package-from-name name))
863 (setq packagebin (assoc packagename package-buckets))
865 (setcdr packagebin (cons import (cdr packagebin)))
866 (setq package-buckets (cons (cons packagename (list import)) package-buckets)))
867 (setq imports (cdr imports))))
870 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
874 ;; Thanks to Philip Lord for the original idea for this command and for ;;
875 ;; contributing the initial implementation. ;;
877 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
879 (defun jde-import-all-find-classes-to-import ()
880 "Returns a list of unqualified class names to import into this
881 buffer. This function returns all the identifiers in the current
882 buffer that start with an uppercase character, have at least one lower
883 case character, and that are not included in an import statement and
884 are not the names of inner or outer classes declared in this buffer."
885 (let (declared-classes
889 ;; Get the names of classes that are already imported into this buffer.
890 (let ((import-tags (semantic-brute-find-tag-by-class 'include (current-buffer))))
895 (jde-parse-get-unqualified-name (semantic-tag-name import-tag)))
898 ;; Get the names of classes declared in this buffer.
899 (let ((buffer-class-tags (semantic-brute-find-tag-by-class 'type (current-buffer))))
900 (flet ((find-declared-classes
902 (let ((members (semantic-tag-get-attribute class-tag :members)))
903 (dolist (member members)
904 (if (eq (semantic-tag-class member) 'type)
906 (setq declared-classes
907 (append declared-classes (list (semantic-tag-name member))))
908 (find-declared-classes member)))))))
909 (dolist (class-tag buffer-class-tags)
910 (setq declared-classes (append declared-classes (list (semantic-tag-name class-tag))))
911 (find-declared-classes class-tag))))
913 ;; Sort through the Java tokens in this buffer, looking
914 ;; for identifiers that start with an uppercase character and
915 ;; do not appear in an import statement or a toplevel
916 ;; class declaration.
917 (let ((tokens (semantic-lex-buffer 1000)))
918 (dolist (token tokens classes-to-import)
919 (let ((type (car token))
922 (if (eq type 'IDENTIFIER)
923 (let (case-fold-search
924 (name (buffer-substring-no-properties start end)))
926 (string-match "^[a-z]" name)
927 (not (string-match "[a-z]" name))
928 (member name declared-classes)
929 (member name imported-classes))
930 (add-to-list 'classes-to-import name t)))))))))
932 (defun jde-import-all-show ()
933 "Display a list of the class names referenced in this
934 buffer that are not declared or explicitly imported into this
935 buffer and hence may need to be imported."
937 (let ((candidate-imports
938 (jde-import-all-find-classes-to-import)))
939 (with-output-to-temp-buffer "*jde import*"
944 candidate-imports))))
946 (defun jde-import-all-filter (unqualified-imports &optional no-exclude)
947 "Generate a list of fully qualified names of classes to
948 import from UNQUALIFIED-IMPORTS, excluding classes specified
949 by `jde-import-exclude-imports' if NO-EXCLUDE is nil."
951 (lambda (unqualified-class)
952 (let ((qualified-imports (jde-import-get-qualified-names unqualified-class)))
955 (jde-import-exclude-imports qualified-imports))))
956 unqualified-imports))
958 (defun jde-import-all-unique ()
959 "Import all classes uniquely referenced by unqualified class
960 names in the current buffer, i.e., all referenced classes for
961 which there is only one fully qualified name on the current
965 (jde-import-all-filter (jde-import-all-find-classes-to-import)))
968 ;; take single length sublists, and return item..
971 (if (= 1 (length item))
975 (if (< 0 (length retn))
976 (jde-import-insert-imports-into-buffer retn))))
978 (defclass jde-import-all-dialog(efc-multi-option-dialog) nil)
980 (defmethod initialize-instance ((this jde-import-all-dialog) &rest fields)
981 "Dialog constructor."
984 (defmethod efc-multi-option-dialog-sort ((this jde-import-all-dialog) list)
986 ;; sort the ones with the most options first...
998 (defun jde-import-all (&optional no-exclude)
999 "Imports all classes that need to be imported into the current buffer.
1000 If any of the required imports are ambiguous, this command displays a dialog
1001 box that allows you to disambiguate the references.
1002 Classes specified by `jde-import-excluded-classes' will be excluded,
1003 unless the prefix argument NO-EXCLUDE is non-nil."
1006 (jde-import-all-filter
1007 (jde-import-all-find-classes-to-import) no-exclude))
1012 (lambda (import) (if (= (length import) 1) (car import)))
1018 (lambda (import) (if (> (length import) 1) import))
1021 (if ambiguous-imports
1022 (jde-import-all-dialog
1023 "Multi Classes Option"
1024 :options ambiguous-imports
1025 :text "Select imports to insert."))))
1028 (efc-dialog-show dialog)
1029 (setq unique-imports
1030 (append unique-imports (oref dialog selection)))))
1031 (jde-import-insert-imports-into-buffer unique-imports)))
1034 (provide 'jde-import)
1039 ;; $Log: jde-import.el,v $
1040 ;; Revision 1.46 2004/12/12 14:27:02 paulk
1041 ;; Add templates provided by Ole Arndt.
1043 ;; Revision 1.45 2004/09/30 04:25:46 paulk
1044 ;; Change the default threshhold for collapsing imports to two classes. This causes the JDEE to collapse imports for any package from which the current buffer imports at least two classes.
1046 ;; Revision 1.44 2004/09/30 04:18:21 paulk
1047 ;; Expand and fix documentation for jde-import-collapse-import command.
1049 ;; Revision 1.43 2004/09/21 04:50:36 paulk
1050 ;; Include Martin Schwamberger's jde-import-expand-imports command.
1052 ;; Revision 1.42 2004/08/11 04:24:00 paulk
1053 ;; Includes enhancements contributed by Martin Schwamberger.
1055 ;; Revision 1.41 2004/05/19 04:17:45 paulk
1056 ;; Wrap all of jde-import-organize in a save-excursion form.
1058 ;; Revision 1.40 2004/05/17 14:09:21 paulk
1059 ;; Cedet compatibility fix: change reference to semantic-toplevel-bovine-table to semantic--parse-table.
1061 ;; Revision 1.39 2004/05/04 04:40:36 paulk
1062 ;; Force reparsing with semantic 1.4.
1064 ;; Revision 1.38 2004/05/03 17:55:12 paulk
1065 ;; (jde-require 'sregex) to avoid shadowing standard version. Thanks to David Ponce.
1067 ;; Revision 1.37 2004/03/22 06:23:10 paulk
1068 ;; jde-import-get-import-insertion-point takes class documention into account.
1069 ;; It no longer destroys class documentation. Also improved insertion of newlines.
1070 ;; Thanks to Martin Schwarmberger.
1072 ;; Revision 1.36 2004/03/21 03:26:50 paulk
1073 ;; Removed Philip Lord's prototype code.
1075 ;; Revision 1.35 2004/03/16 07:49:34 paulk
1076 ;; Add a jde-import-all command contributed by Philip Lord.
1078 ;; Revision 1.34 2004/03/02 06:34:50 paulk
1079 ;; Update jde-import-excluded-packages to exclude packages that start with sun and com.sun. This classes contain classes named i and packages named e, confusing the JDEE when it tries to complete Iterator instances named i and Exception instances named e.
1081 ;; Revision 1.33 2003/09/22 02:56:24 paulk
1082 ;; Cosmetic changes.
1084 ;; Revision 1.32 2003/09/07 05:19:28 paulk
1085 ;; Extend jde-import-excluded-classes to exclude classes that
1086 ;; belong to the same package as the importing class. Thanks to
1087 ;; Martin Schwamberger.
1089 ;; Revision 1.31 2003/04/09 01:25:19 jslopez
1090 ;; Updates method call from jde-import-insert-imports to jde-import-insert-import.
1092 ;; Revision 1.30 2003/04/06 08:17:12 paulk
1093 ;; Fixed regression caused by Andy's efc XEmacs compatibility
1094 ;; changes. The regression was caused by the plural in the name
1095 ;; jde-import-choose-imports which implies that it should return a list
1096 ;; of imports selected by a user when in fact it should return only
1097 ;; one. The plural misled Andy to enclose the import selected by the user
1098 ;; in a list. I removed the enclosing list and I renamed the function and
1099 ;; a set of other similarly misnamed functions to the singular, e.g.,
1100 ;; jde-import-choose-import, to reflect the fact that they actually
1101 ;; insert only a single import.
1103 ;; Revision 1.29 2003/03/28 05:33:29 andyp
1104 ;; XEmacs optimizations for JDEbug and efc.
1106 ;; Revision 1.28 2003/02/28 14:53:08 jslopez
1107 ;; Fixes bug in jde-import-insert-imports.
1108 ;; If new-imports contain only one import and this import is excluded the
1109 ;; code was importing a nil value.
1111 ;; Revision 1.27 2003/02/26 02:59:38 jslopez
1112 ;; Supresses more error messages when completing.
1114 ;; Revision 1.26 2003/02/25 05:20:25 paulk
1115 ;; Fix bug that causes jde-import-organize to insert the group name
1116 ;; multiple times when called repeatedly.
1117 ;; Thanks to Joshua Spiewak <JSpiewak@axeda.com>
1119 ;; Revision 1.25 2003/02/18 02:09:40 jslopez
1120 ;; Fixes regression bugs.
1122 ;; Revision 1.24 2003/01/17 20:58:06 jslopez
1123 ;; Fixes regression bug causing excluded imports to show in the
1125 ;; Fixes typo in jde-import-insert-imports. It was using new-imports instead
1126 ;; of candidate-imports.
1128 ;; Revision 1.23 2003/01/12 20:05:26 paulk
1129 ;; - Check whether import already exists AFTER the user selects the
1130 ;; import. This is to prevent the JDE from importing a class that
1131 ;; is already imported but from a different package.
1132 ;; - Display message when the buffer already imports the specified class.
1133 ;; - Clean up the code.
1135 ;; Revision 1.22 2003/01/10 13:27:01 paulk
1136 ;; Fix jde-import-strip-existing-imports so that it handles package import statements.
1138 ;; Revision 1.21 2002/09/06 13:07:12 jslopez
1139 ;; Fixes jde-import-get-classname to handle inner classes.
1141 ;; Revision 1.20 2002/08/07 06:36:17 paulk
1142 ;; Removed code intended to eliminate spurious warnings when byte-compiling the JDEE. The
1143 ;; removed code now resides in a separate package, jde-compat.el. Thanks to Andy Piper
1144 ;; for suggesting this restructuring. Also fixed a number of compiler warnings caused
1147 ;; Revision 1.19 2002/05/31 18:55:08 mnl
1148 ;; Added sorting of import statements according to their occurance in the
1151 ;; Revision 1.18 2002/05/30 04:43:31 paulk
1152 ;; Fixes bug in jde-import-get-import-insertion-point that
1153 ;; caused it to mishandle insertion of import statements
1154 ;; after package statements. Thanks to Phillip Lord <p.lord@russet.org.uk>.
1156 ;; Revision 1.17 2002/02/03 07:01:39 paulk
1157 ;; Adds support for inserting group names before groups. Thanks to
1158 ;; Brian Paulsmeyer and David Ponce.
1160 ;; Revision 1.16 2002/01/28 07:07:50 paulk
1161 ;; * Adds jde-import-auto-collapse-imports variable. Customizing this variable to a nonnil value
1162 ;; causes the JDE to run jde-import-collapse-imports after importing a class. Thanks to
1163 ;; "Max Rydahl Andersen" <max@eos.dk>.
1165 ;; * Also cleaned up the code to jde-import-insert-imports-into-buffer.
1167 ;; Revision 1.15 2002/01/27 04:09:57 paulk
1168 ;; Remove duplicates from import list. Thanks to Stephen Molitar.
1170 ;; Revision 1.14 2002/01/06 06:56:09 paulk
1171 ;; jde-import-choose-imports now checks for the case where the user cancels
1172 ;; the class selection dialog.
1174 ;; Revision 1.13 2001/12/08 13:55:29 jslopez
1175 ;; Updates the function jde-import-choose-imports to use
1176 ;; efc-option-dialog.
1178 ;; Revision 1.12 2001/11/30 11:13:43 jslopez
1179 ;; Rolling back my previous changes to
1180 ;; jde-import-choose-imports, to fix regression bug.
1182 ;; Revision 1.11 2001/11/28 22:50:24 jslopez
1183 ;; Fixes compilation messages.
1185 ;; Revision 1.10 2001/10/19 08:57:27 paulk
1186 ;; Adds the customization variable jde-import-auto-sort-function.
1187 ;; This variable allows you to specify the function used by
1188 ;; the JDE to sort imports. Thanks to Hugh Emberson.
1190 ;; Revision 1.9 2001/07/31 05:22:48 paulk
1191 ;; Adds jde-import-collapse-imports command. Thanks to Max Rydahl Andersen.
1193 ;; Revision 1.8 2001/07/06 02:10:43 paulk
1194 ;; Bug fix in removing unneeded import statements.
1196 ;; Revision 1.7 2001/06/07 03:35:01 paulk
1197 ;; Further fine-tuned import insertion point function.
1199 ;; Revision 1.6 2001/06/06 05:19:28 paulk
1200 ;; Improved calculation of import insertion point.
1202 ;; Revision 1.5 2001/04/27 01:33:42 paulk
1203 ;; jde-import-sort now refreshes parse cache. Thanks to Robert Mecklenburg <mecklen@cimsoft.com> for tthis fix.
1205 ;; Revision 1.4 2001/04/26 09:06:07 paulk
1206 ;; -- jde-import-kill-extra-imports now refreshes the buffer's parse cache. This fixes a bug where successive calls to the function would incorrectly remove imports.
1208 ;; -- jde-import-kill-extra-imports now removes fully qualified imports that are not referenced in the code.
1210 ;; Thanks to "Javier Lopez" <jlopez@cellexchange.com>.
1212 ;; Revision 1.3 2001/03/13 04:19:45 paulk
1213 ;; Cosmetic changes.
1215 ;; Revision 1.2 2000/11/27 06:18:40 paulk
1216 ;; Miscellaneous bug fixes and minor enhancements.
1218 ;; Revision 1.1 2000/11/20 05:15:15 paulk
1219 ;; Added jde-import-organize command. Moved all import-related code from
1220 ;; jde-wiz.el to a new package named jde-import.el.
1222 ;; Revision 1.2 2000/11/17 11:52:54 david_ponce
1223 ;; - New `jde-import-group-function' option to specify the function used
1224 ;; to associate import token to group. The default one is
1225 ;; `jde-import-group-of'. This let the user to completely handle the
1226 ;; way imports are grouped.
1228 ;; - New `jde-import-sorted-groups' option to specify if groups will be
1229 ;; sorted. Notice that the *default* group (the one that contains
1230 ;; imports not belonging to any specific group) is allways the last
1233 ;; - Improvement of the function `jde-import-group-of'. For consistency
1234 ;; `jde-import-group-rules' is now `jde-import-group-of-rules' and it
1235 ;; is now possible to associate a group regexp to a particular name.
1237 ;; Revision 1.1 2000/11/17 11:48:31 david_ponce
1238 ;; Initial Revision.
1241 ;;; jde-import.el ends here