I updated jde-import.el so that you can customize whether or not it
prompts you before removing imports (hey, I trust that it works and the
compiler will catch it when it for some odd reason doesn't). Once again
my changes are marked with JVL tags. The customization variable is
jde-import-non-interactive-import-removing. Just set it to "t" to
disable the dialog.
;;; jde-import.el --- Utility functions for Java import statements.
;; $Revision: 1.1 $
;; $Date: 2000/05/27 21:38:13 $
;; This file is not part of Emacs
;; Author: Juan Leon Lahoz Garcia <[EMAIL PROTECTED]>
;; Author: Phillip Lord<[EMAIL PROTECTED]>
;; Author: Jim LoVerde<[EMAIL PROTECTED]>
;; COPYRIGHT NOTICE
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;;
;; This package provides two utilities functions for Java import
;; statements. `jde-import-sort-imports' performs an alphabetic sort
;; of the imports, whilst `jde-import-remove-unused-imports' checks
;; that the import statements are actually required in the class.
;;; Limitations:
;;
;; 1) `jde-import-remove-unused-imports' requires some sort of
;; syntactic analysis of the class. As this would be rather
;; complicated to code, the only check done when searchin occurrences
;; of a class is to see if they are into a comment or a quoted string.
;; If there are variables or methods named as classes that are not
;; used but imported, some import sentences could be not removed. Good
;; naming conventions avoid this minor problem.
;;
;; 2) jde-import-remove-unused-imports can not cope with
;; imports with wildcard "*"'s in them.
;;; Tips & Tricks:
;;
;; An easy mode of having your import sentences always sorted (well,
;; if you use `jde-wiz-find-and-import') is to include this in one of
;; your configuration files:
;;
;; (defadvice jde-wiz-insert-imports-into-buffer
;; (after jde-wiz-find-and-import activate)
;; "Runs sort function after import so that functions are always
sorted.
;; Would make more algorithmic sense to put the import at the right
place,
;; but this is easiest"
;; (jde-import-sort-imports))
;;
;; If you wanna to use both functions at once you can use
;; `jde-import-clean-imports-sentences' or
;; `jde-import-clean-imports-sentences-in-file'. These functions are
;; very useful for batch processing lots of java files.
;;; History:
;;
;; First release
;;; Code:
;; BEGIN JVL
(defcustom jde-import-non-interactive-import-removing nil
"Specifies whether or not the import cleanup should prompt the user
with a dialog. Set to nil to support dialogs in interactive mode, t
otherwise."
:group 'jde-import
:type 'string)
;; END JVL
;(defvar jde-import-non-interactive-import-removing nil
; "Non-niil means suppress the confirmation dialog.
;This is meant for use in batch processing of import statements")
(defun jde-import-remove-some-unused-imports()
"Remove some import sentences of a java buffer. The sentences
removed are the imports of classes that are not used in the buffer.
Since this function uses `jde-import-class-used-maybe', not all the
unused imports are removed.
Note: this function doesn't works properly on \"import Foo.*\;\"
sentences, but if you don't care about using this type of import
sentences, then you don't care about unused imports and you'll never
use this function
See also `jde-import-class-used-maybe'"
(interactive)
(let((unused-imports nil))
(save-excursion
(goto-char (point-min))
(while (re-search-forward "^import.*\\(\\.\\| \\)\\(\\w+\\);" nil
t)
(let ((class (match-string 2))
(import-statement (match-string 0))
(used t))
(if (not (jde-import-class-used-maybe class))
(setq unused-imports (cons import-statement
unused-imports))))))
(if (and (not jde-import-non-interactive-import-removing)
(not unused-imports))
(message "No unused imports detected")
(if jde-import-non-interactive-import-removing
(jde-import-remove-imports-from-buffer unused-imports
(current-buffer))
(jde-import-remove-imports-dialog unused-imports
(current-buffer))))))
(defun jde-import-class-used-maybe (class)
"Check if a CLASS is used in a java buffer.
The check is not perfect: if the class is used (and if there isn't a
bug) the function returns true, but if the class is not used this
function may be fooled if there is an instance of any class called
like the class."
(save-excursion
(let ((founded nil)
(classregexp
(concat "\\b" class "\\b" )))
;;now check all the other times the type occurs as a word
(while (and (not founded) (re-search-forward classregexp nil t))
(setq founded
;;if we are not in a comment or quoted then we have what
;;we need
(not (jde-import-comment-or-quoted-p))))
founded)))
; (defun jde-import-comment-or-string-p()
; "Are we on a string or a comment?"
; (let ((faces (get-text-property (point) 'face)))
; ;;I can never get the hang of whether faces is returning a
; ;;list or what. Make sure that it is
; (if (not (listp faces))
; (setq faces (list faces)))
; (or (memq 'font-lock-comment-face faces)
; (memq 'font-lock-string-face faces))))
;; This function was stolen from jde-cflow...!
(defun jde-import-comment-or-quoted-p ()
"Returns t if point is in a comment or a quoted string. nil otherwise"
(interactive "p")
;; limit our analysis to the current line.
(let ((beg (save-excursion (beginning-of-line) (point))))
(if
(or
;; are we in a javadoc comment?
(save-excursion
(re-search-backward
"^[ \t]*/?\\*"
beg t))
;; are we in a '//' or a '/*' style comment?
;; note that /* or /** on a line with only leading whitespace
;; will have matched in the previous regex. We check again
here
;; because the above case needs to allow for a line with
;; the continuation of a comment (using only a '*') whereas
this
;; requires the presence of a '/' in front of the '*' so as to
;; distinguish a comment from a '*' operator.
;; To make a long story short,
;; the first regex matches
;; /* a comment */
;; and
;; /**
;; * a comment
;; */
;; while the second one matches
;; System.out.println(foo); /* a comment */
;; but not
;; i = 3 * 5;
;; if you do something like following, you're on your own:
;; i = 3
;; * 5;
;; Suggestions for improving the robustness of this algorithm
;; gratefully accepted.
(save-excursion
(re-search-backward
"\\(//\\|/\\*\\)"
beg t))
;; are we in a quoted string?
(save-excursion
(re-search-backward
"\"" ;;
beg t)))
t ;; return true if we had any matches; nil otherwise
nil)))
(defvar jde-import-remove-import-imports nil)
(defvar jde-import-remove-import-buffer nil)
(defun jde-import-remove-imports-dialog (unused-imports buffer)
"Prompts the user with all the imports that it is intended to remove.
Argument UNUSED-IMPORTS imports to remove.
Argument BUFFER buffer from which to remove."
(let ((buf (get-buffer-create "*Confirm Import Removal*")))
(setq jde-import-remove-import-imports unused-imports)
(setq jde-import-remove-import-buffer buffer)
(set-buffer buf)
(erase-buffer)
(widget-insert "The following import statements have been marked \n"
)
(widget-insert "for removal. Please deselect any that you want to
retain \n" )
(widget-insert "and then click the OK button. \n" )
(let (i n)
(setq i 0)
(setq n (length jde-import-remove-import-imports))
(while (< i n)
(let* ((import-to-kill (nth i jde-import-remove-import-imports))
(args (list
;;type of widget
'checkbox
;;properties of this widget
:value import-to-kill
:format "\n %[%v%] %t"
:tag import-to-kill
;;what to do on activate/deactivate
:notify (lambda (widget &rest ignore)
(let ((value (widget-get widget ':tag)))
;;if its there remove it
(if (find value
jde-import-remove-import-imports)
(progn (setq
jde-import-remove-import-imports
(delq value
jde-import-remove-import-imports))
(message "You have
deselected:
%s" value))
;else we need to add it
(progn (setq
jde-import-remove-import-imports
(nconc (list value)
jde-import-remove-import-imports))
(message "You have selected:
%s"
value))))))))
(apply 'widget-create args)
(setq i (+ i 1)))))
(widget-insert "\n")
(widget-create 'push-button
:notify (lambda (&rest ignore)
(let ((dialog-buffer
(current-buffer)))
(delete-window)
(kill-buffer dialog-buffer)
(if jde-import-remove-import-imports
(progn
(jde-import-remove-imports-from-buffer
jde-import-remove-import-imports
jde-import-remove-import-buffer)
(message "Removed imports"))
(message "No imports removed" ))))
"Ok")
(widget-create 'push-button
:notify (lambda (&rest ignore)
(let ((dialog-buffer
(current-buffer)))
(delete-window)
(kill-buffer dialog-buffer)
))
"Cancel")
(use-local-map widget-keymap)
(widget-setup)
;;default to "Ok"
(beginning-of-line)
(pop-to-buffer buf)))
(defun jde-import-remove-imports-from-buffer (imports buffer)
"Actually kill IMPORTS statements from BUFFER."
(save-excursion
(set-buffer buffer)
(jde-import-log-removal-new-buffer buffer)
;; BEGIN JVL
(let (i n)
;; END JVL
(setq i 0)
(setq n (length imports))
(while (< i n)
(goto-char (point-min))
(search-forward (nth i imports) nil t)
(beginning-of-line)
(kill-line 1)
(jde-import-log-remove-import (nth i imports))
(setq i (+ 1 i)))
;; BEGIN JVL
n)))
;; END JVL
(defun jde-import-log-removal-new-buffer (buffer)
"Reports import removal from a new BUFFER."
(save-excursion
(set-buffer (get-buffer-create "*Jde Imports Removal Log*"))
(goto-char (point-max))
(insert "Removing Imports from " (buffer-file-name buffer) "\n")))
(defun jde-import-log-remove-import (import)
"Reports removal of IMPORT from a file."
(save-excursion
(set-buffer (get-buffer-create "*Jde Imports Removal Log*"))
(goto-char (point-max))
(insert "Removing " import "\n")))
(defun jde-import-sort-imports()
"Sort the \"import\" sentences in a file"
(interactive)
(save-excursion
(goto-char (point-min))
(search-forward-regexp "^import.*;")
(let ((beg-imports (match-beginning 0)))
(goto-char (point-max))
(search-backward-regexp "^import.*;")
(let ((end-imports (match-end 0)))
(sort-lines nil beg-imports end-imports)))))
(defun jde-import-clean-imports-sentences()
"Do some cleanup in current buffer's import sentences"
(interactive)
(let (num-removed)
(if noninteractive
(setq jde-import-non-interactive-import-removing t))
(jde-import-sort-imports)
;; BEGIN JVL
(setq num-removed (jde-import-remove-some-unused-imports))
(message "removed %s imports" num-removed)))
;; END JVL
(defun jde-import-clean-imports-sentences-in-file(file)
"Do some cleanup in a file import sentences. Useful for batch
processing files"
(interactive)
(find-file file)
(jde-import-clean-imports-sentences)
(save-buffer))
(provide 'jde-import)
;;; jde-import.el ends here