I've tested this a bit now, and I really like it. I have found one slight
problem, and I have one request for a possible improvement:
1. It doesn't detect the need to import List with the following class:
----
public class Hej {
public Hej() {
}
public List hejsan() {
}
}
----
I guess it doesn't check for return types? It may seem like a non-valid use
case, but in my case, I had a method that instantiated a LinkedList but with
a signature returning a List.
2. If possible, and this is something that I have always wanted for the
dialogs, I would like the cursor to be positioned on the Ok button by
default. That way, I can just hit return to confirm the selection. That
probably is only valid in the "one-hit" case here, not when the user
actually has to go through and select lots of stuff, so it's not really a
big deal.
Thanks for a very nice feature!
Petter
> -----Original Message-----
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On
> Behalf Of Phillip Lord
> Sent: den 12 mars 2004 11:41
> To: [EMAIL PROTECTED]
> Subject: Re: jde-import-all
>
>
>
> Here is the latest version of jde-import-all, which works with
> jde-2.3.3.
>
>
>
> Cheers
>
> Phil
>
>
> ;;; jde-import-all.el --- Import everything at once.
>
> ;; Copyright (C) 2004 Phillip Lord
>
> ;; Author: Phillip Lord <[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:
> ;;
> ;; Build imports for all types in the buffer. This package has two
> ;; entry points. `jde-import-all' finds all declared types in the
> ;; buffer, then presents the user with a nice dialog which they can
> ;; then choose as many as they wish. `jde-import-all-unambiguous'
> ;; finds all the declared types in the buffer, and then imports
> ;; without asking the user any imports which identify a class
> ;; unambigiously.
> ;;
> ;; There are not user options other than those in `jde-import' which
> ;; this respects.
> ;;
> ;; This package is really meant for rolling into jde-import. There's
> ;; also a dialog near the end which uses the efc namespace, because it
> ;; probably belongs there.
> ;;
> ;; This package uses regexp searching to find all the types, as the
> ;; semantic grammar doesn't appear to go deep enough for use
> ;; here. Like other parts of JDE it depends on use of coding
> standards
> ;; (upper case for types). It will miss types not conforming to this.
>
> ;;; Bugs:
> ;;
> ;; This does not correctly identifer InnerClasses which need to be
> ;; imported via their parent. Probably requires both lisp and
> ;; beanshell support.
> ;;
>
> ;;; History:
> ;;
> ;; - fixed bug with regexp, which failed to pick up "implements"
> ;; types, or multiple types after extends
> ;;
>
> ;;; Code:
>
>
> (require 'sregex)
> (require 'jde-import)
>
> (defun jde-import-all-regexp()
> "Get the regexp set to find all types."
> (let ((white-nl
> '(1+ (or (syntax ?-) "\n")))
> (white-nl-0
> '(0+ (or (syntax ?-) "\n")))
> (non-identifier
> '(1+ wordchar))
> ;; match an upper case begining word, which we will take as a
> ;; type.
> (identifier
> '(group
> (char (?A . ?Z))
> (1+ wordchar))))
> (list
> (cons
> ;; match anything following instanceof, new, or extends. These
> ;; are keywords, so are guarenteed to be classes
> (sregex '(or "new" "instanceof" "throws")
> white-nl
> '(group (1+ wordchar)))
> 1)
> (cons
> ;; match anything following extends or implements. This will
> ;; then be split on commas. Both extends and implements can
> ;; carry multiple Class names after them, as Interfaces can
> ;; extend multiple other interfaces.
> (sregex '(or "extends" "implements")
> white-nl-0
> `(group
> (1+ (or ,identifier "," (syntax ?-)))))
> 'jde-import-match-comma-split)
> (cons
> ;; match anything in between parens and starting with upper
> ;; case. This picks up casts. This will also pick up things like
> ;; debugGraphics.setDebugOptions(FLASH_OPTIONS); where
> ;; FLASH_OPTIONS is actually a static. Generally this won't be a
> ;; problem because it shouldn't resolve as a class. `
> (sregex '(char ?( )
> identifier
> '(char ?)))
> 1)
> ;; match an .class type thing..
> (cons
> (sregex identifier ".class")
> 1)
> ;; match variable declaration
> (cons
> (sregex white-nl
> identifier
> white-nl
> non-identifier
> white-nl-0
> '(or ";" "="))
> 1)
> ;; match formal parameters
> (cons
> (sregex '(or "(" ",")
> white-nl-0
> identifier
> white-nl
> non-identifier
> white-nl-0
> '(or "," ")"))
> 1)
> )))
>
>
> (defun jde-import-all-get-types()
> "Return all the types in the current buffer.
>
> The result is a list with no duplicates."
> (let ((elements))
> (mapcar
> (lambda(matcher)
> (let ((matches
> (jde-import-all-gather matcher)))
> (mapcar
> (lambda(match)
> (add-to-list 'elements match))
> matches)))
> (jde-import-all-regexp))
> elements))
>
> (defun jde-import-all-gather(matcher)
> "Get all matches in the current buffer.
>
> MATCHER is a cons (regexp . group). Looks for matches to the regexp
> and stores the match in the group. Only matches not in strings are
> accepted. This list can contain duplicates."
> (let ((regexp (car matcher))
> (group (cdr matcher))
> (case-fold-search nil)
> (retn))
> (save-excursion
> (goto-char (point-min))
> (while (re-search-forward
> regexp
> (point-max) t)
> (setq retn
> (append
> (if (numberp group)
> (jde-import-default-match group)
> (funcall group))
> retn))))
> retn))
>
> (defun jde-import-default-match(group)
> (goto-char (match-end group))
> (unless
> (jde-parse-comment-or-quoted-p)
> (list
> (match-string-no-properties group))))
>
> (defun jde-import-match-comma-split()
> (goto-char (match-end 1))
> (unless
> (jde-parse-comment-or-quoted-p)
> (split-string
> (match-string-no-properties 1)
> "[ ,]+")))
>
> (defun jde-import-all-import-types(list)
> "Import all types.
>
> Accepts a list of Strings of unqualified classes"
> ;; we have a list of strings
> (setq list
> (jde-import-all-expand-strip-exclude list))
> ;; so we now have a list of lists of strings. We want to over a
> ;; dialog showing all of these one after the other..
> (let ((dialog
> (jde-import-all-dialog
> "Multi Classes Option"
> :options list
> :text "Select imports to insert."))
> (selection))
> (efc-dialog-show dialog)
> (setq selection
> (delq nil (oref dialog selection)))
> (if (and selection
> (< 0 (length selection)))
> (jde-import-insert-imports-into-buffer selection))))
>
> (defun jde-import-all-expand-strip-exclude(list)
> "Qualifies, strips and excludes imports.
>
> This function takes in a list of imports. It removes all the existing
> imports, qualifies them and then strips excluded imports. It returns a
> list of lists of strings. And all in one function."
> (delq nil
> (mapcar
> (lambda(unqualified-class)
> ;; we want to remove any imports which already exists
> (if (jde-import-get-existing-import unqualified-class)
> nil
> (jde-import-exclude-imports
> ;; we want to kill of the java.lang
> ;; packges. exclude-imports will probably do this for
> ;; us. But this is not good as it will leave the other
> ;; possibilities. So "String" will be imported as
> ;; "apache.xpath.String" (on my machine) which is almost
> ;; exactly the wrong behaviour
> ;;
> ;; I'm not really happy with this but what can you do.
> (jde-import-all-kill-lang-classes
> ;; we want to expand any unqualified names,
> this returns
> ;; a list of string possibilities
> (jde-jeval-r
> (concat "jde.util.JdeUtilities.getQualifiedName(\""
> unqualified-class "\");"))))))
> list)))
>
> (defun jde-import-all-kill-lang-classes(list)
> (let ((ismatch nil))
> (mapc
> (lambda(item)
> (if (string-match "^java\\.lang\\.[^.]*$" item)
> (setq ismatch t)))
> list)
> (if ismatch
> nil
> list)))
>
> (defun jde-import-all-unambiguous()
> "Import all unambigious imports.
>
> This function imports all imports for which the name identifies a
> unique class in the classpath. This avoids presenting the user with a
> large dialog, which can take a while to build if there are many
> imports."
> (interactive)
> (let ((list
> (jde-import-all-expand-strip-exclude
> (jde-import-all-get-types)))
> (retn))
> (delq nil
> ;; take single length sublists, and return item..
> (mapcar
> (lambda(item)
> (if (= 1 (length item))
> (add-to-list 'retn
> (car item))))
> list))
> (if (< 0 (length retn))
> (jde-import-insert-imports-into-buffer retn))))
>
>
> (defun jde-import-all()
> "Attempt to import all types in the current buffer.
>
> The user will be prompted with an interactive dialog, prompting
> for alternatives."
> (interactive)
> (jde-import-all-import-types
> (jde-import-all-get-types)))
>
>
>
> ;; define a nifty option dialog for asking for multiple options.
> ;; I've never used eieio before. Very cute...
> (defclass efc-multi-option-dialog (efc-option-dialog)
> ((options :initarg :options
> :documentation
> "Option of options from which to choose")
> (radio-buttons :initarg :radio-buttons
> :documentation
> "Buttons for selecting options")
> (text :initarg :text
> :type string
> :initform "Select option."
> :documentation
> "Text at top")
> (build-message :initarg :text
> :type string
> :initform "Building Dialog"
> :documentation
> "Warning message while building dialog, as
> this can be slow")
> (selection :initarg :selection
> :documentation
> "Options choosen."))
> "Provides a dialog with several sets of OPTIONS.
> The dialog sets SELECTION to the options selected by the user.")
>
> (defmethod initialize-instance ((this
> efc-multi-option-dialog) &rest fields)
> "Dialog constructor."
> (call-next-method))
>
> (defmethod efc-dialog-create ((this efc-multi-option-dialog))
> (message "%s..." (oref this build-message))
> (widget-insert (oref this text))
> (widget-insert "\n\n")
> ;; use radio buttons slot as list of radio buttons rather than.
> (oset this radio-buttons
> (mapcar
> (lambda(list)
> (prog1
> (widget-create
> (list
> 'radio-button-choice
> :value
> (efc-multi-option-dialog-default this list)
> :args (mapcar
> (lambda (x)
> (list 'item x))
> list)))
> (widget-insert "\n")))
> (efc-multi-option-dialog-sort this
> (oref this options))))
> (widget-insert "\n")
> (message "%s...done" (oref this text)))
>
> (defmethod efc-dialog-ok((this efc-multi-option-dialog))
> ;; set the selection up as a list rather a simple result
> (oset this selection
> (mapcar
> (lambda(widget)
> (widget-value widget))
> (oref this radio-buttons)))
> (delete-window)
> (set-buffer (oref this initbuf))
> (pop-to-buffer (oref this initbuf))
> (kill-buffer (oref this buf))
> (exit-recursive-edit))
>
> (defmethod efc-multi-option-dialog-default ((this
> efc-multi-option-dialog) list)
> "Pick the default from a collection of options."
> (if (= 1 (length list))
> (car list)))
>
> (defmethod efc-multi-option-dialog-sort ((this
> efc-multi-option-dialog) list)
> "Sort the options."
> ;; sort the ones with the most options first...
> (sort list
> (lambda(a b)
> (> (length a)
> (length b)))))
>
>
> ;; define a more specific dialog, which searches things differently.
>
> (defclass jde-import-all-dialog(efc-multi-option-dialog) nil)
>
> (defmethod initialize-instance ((this jde-import-all-dialog)
> &rest fields)
> "Dialog constructor."
> (call-next-method))
>
> (defmethod efc-multi-option-dialog-sort ((this
> jde-import-all-dialog) list)
> "Sort the options."
> ;; sort the ones with the most options first...
> (sort list
> (lambda(a b)
> ;; sort lexically
> (if (= (length a)
> (length b))
> (string< (car a)
> (car b))
> ;; or by length
> (> (length a)
> (length b))))))
>
>
> ;;; code to kill lots of extra imports in many different buffers. This
> ;;; is a bit of a hack at the moment.
> (defun jde-import-all-search-path()
> "Find source root directories.
> This code is chopped straight from `jde-find' which is a little
> unfortunate."
> (read-from-minibuffer
> "Search directories: "
> (cons
> (mapconcat
> (lambda (x) x)
> (cond
> (jde-sourcepath
> (mapcar
> (lambda (path)
> (jde-normalize-path path 'jde-sourcepath))
> jde-sourcepath))
> (jde-compile-option-sourcepath
> (mapcar
> (lambda (path)
> (jde-normalize-path path 'jde-compile-option-sourcepath))
> jde-compile-option-sourcepath))
> (jde-compile-option-classpath
> (mapcar
> (lambda (path)
> (jde-normalize-path path 'jde-compile-option-classpath))
> jde-compile-option-classpath))
> (jde-global-classpath
> (mapcar
> (lambda (path)
> (jde-normalize-path path 'jde-global-classpath))
> jde-global-classpath))
> (t
> (list default-directory)))
> " ")
> 0)
> nil nil 'jde-find-root-history))
>
> (defun jde-import-all-find-internal (buffer &optional dirs)
> (if (not (executable-find
> (if (eq system-type 'windows-nt) "find.exe" "find")))
> (error (list "This command requires the Unix find utility.")))
> (let* ((directories-option
> (if dirs dirs "."))
> (cmd
> (format "find %s -type f -name \"%s\""
> directories-option
> (car jde-find-file-regexp))))
> (shell-command cmd buffer)))
>
> (put 'jde-import-all-kill-extra-imports 'disabled
> "It is not possible to undo this action")
>
> (defun jde-import-all-kill-extra-imports()
> "Kill extraneous imports in many buffers.
>
> This function uses the unix find command to discover all java files
> in the current project and then removes all extranous import
> statements
> from them.
>
> This function is a little bit scary and may not behave correctly.
> Even if it does it can't be undone. And even if you don't want to
> undo it, its user interface is very poor as it's very noisy telling
> you lots of things you don't want to know, and nothing that you
> actually want to know. In short its a hack."
> (interactive)
> (save-some-buffers)
> (with-temp-buffer
> (let ((files-buffer (current-buffer))
> (current-buffers (buffer-list))
> (total-files)
> (onfile 0))
> (message "Discovering files...")
> (jde-import-all-find-internal
> files-buffer
> (jde-import-all-search-path))
> (message "Discovering files...done")
> (setq total-files
> (count-lines (point-min) (point-max)))
> (dolist (file (split-string (buffer-string)))
> (message "On %s from %s file %s"
> (incf onfile) total-files
> file)
> (jde-import-all-kill-imports file current-buffers)))))
>
> (defun jde-import-all-kill-imports(file current-buffers)
> (let ((file-buffer (find-file-noselect file)))
> (save-excursion
> (set-buffer file-buffer)
> (jde-import-kill-extra-imports)
> (save-buffer)
> (if (not (member file-buffer current-buffers))
> (kill-buffer (current-buffer))))))
>
>
>
> ;; test functions...
> (defun jde-import-find-all-java()
> (interactive)
> (jde-import-all-find-internal
> (jde-import-all-search-path)))
>
> (defun jde-import-all-search-path-test()
> (interactive)
> (message "search path is %s"
> (jde-import-all-search-path)))
>
>
> (defun jde-import-all-show-gather()
> "Show all of the type declarations shown in a special buffer"
> (interactive)
> (save-excursion
> (set-buffer (get-buffer-create "*jde import*"))
> (erase-buffer))
> (mapcar
> (lambda(matcher)
> (let ((matches
> (jde-import-all-gather matcher)))
> (save-excursion
> (set-buffer "*jde import*")
> (insert (format "Matching %s" matcher))
> (insert "\n")
> (mapcar
> (lambda(match)
> (insert (concat match "\n")))
> matches))))
> (jde-import-all-regexp))
> (switch-to-buffer-other-window "*jde import*"))
>
> (defun jde-import-all-show()
> "Show all of the type declarations"
> (interactive)
> (let ((import
> (jde-import-all-get-types)))
> (save-excursion
> (set-buffer (get-buffer-create "*jde import*"))
> (erase-buffer)
> (mapcar
> (lambda(match)
> (insert match)
> (insert "\n"))
> import))))
>
>
>
> (provide 'jde-import-all)
>
> ;;; jde-import-all.el ends here
>
>