emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/javaimp 8a25b39: Support Java 9+


From: Filipp Gunbin
Subject: [elpa] externals/javaimp 8a25b39: Support Java 9+
Date: Fri, 2 Apr 2021 19:25:01 -0400 (EDT)

branch: externals/javaimp
commit 8a25b3954ddd9904f8af46696a1fd5acbe66e438
Author: Filipp Gunbin <fgunbin@fastmail.fm>
Commit: Filipp Gunbin <fgunbin@fastmail.fm>

    Support Java 9+
    
    * javaimp.el (javaimp--get-jdk-classes): New function.
    (javaimp--jdk-classes): New variable.
    (javaimp-reset): Also reset it.
    (javaimp-add-import): Improve javadoc, support basic completion on
    top-level classes without Maven/Gradle.  Narrow completion candidates
    based on symbol-at-point.
    (javaimp--get-directory-classes): Simplify using
    directory-files-recursively.
    (javaimp--dir-above-current-package): New function.
    * javaimp-util.el (javaimp--get-jdk-jars): Remove.
    * Update copyright year in all files.
---
 javaimp-gradle.el |   2 +-
 javaimp-maven.el  |   2 +-
 javaimp-tests.el  |   2 +-
 javaimp-util.el   |  11 +---
 javaimp.el        | 178 ++++++++++++++++++++++++++++++++++++------------------
 5 files changed, 124 insertions(+), 71 deletions(-)

diff --git a/javaimp-gradle.el b/javaimp-gradle.el
index 2241da5..4d683ab 100644
--- a/javaimp-gradle.el
+++ b/javaimp-gradle.el
@@ -1,6 +1,6 @@
 ;;; javaimp-gradle.el --- javaimp gradle support  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2019  Free Software Foundation, Inc.
+;; Copyright (C) 2019-2021  Free Software Foundation, Inc.
 
 ;; Author: Filipp Gunbin <fgunbin@fastmail.fm>
 ;; Maintainer: Filipp Gunbin <fgunbin@fastmail.fm>
diff --git a/javaimp-maven.el b/javaimp-maven.el
index 524aa77..054bf11 100644
--- a/javaimp-maven.el
+++ b/javaimp-maven.el
@@ -1,6 +1,6 @@
 ;;; javaimp-maven.el --- javaimp maven support  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2019  Free Software Foundation, Inc.
+;; Copyright (C) 2019-2021  Free Software Foundation, Inc.
 
 ;; Author: Filipp Gunbin <fgunbin@fastmail.fm>
 ;; Maintainer: Filipp Gunbin <fgunbin@fastmail.fm>
diff --git a/javaimp-tests.el b/javaimp-tests.el
index 0dbe86f..f382302 100644
--- a/javaimp-tests.el
+++ b/javaimp-tests.el
@@ -1,6 +1,6 @@
 ;;; javaimp-tests.el --- javaimp tests  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2016-2019  Free Software Foundation, Inc.
+;; Copyright (C) 2016-2021  Free Software Foundation, Inc.
 
 ;; Author: Filipp Gunbin <fgunbin@fastmail.fm>
 ;; Maintainer: Filipp Gunbin <fgunbin@fastmail.fm>
diff --git a/javaimp-util.el b/javaimp-util.el
index c03414d..303e43c 100644
--- a/javaimp-util.el
+++ b/javaimp-util.el
@@ -1,6 +1,6 @@
 ;;; javaimp-util.el --- javaimp util  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2019  Free Software Foundation, Inc.
+;; Copyright (C) 2019-2021  Free Software Foundation, Inc.
 
 ;; Author: Filipp Gunbin <fgunbin@fastmail.fm>
 ;; Maintainer: Filipp Gunbin <fgunbin@fastmail.fm>
@@ -83,15 +83,6 @@ the program is not on `exec-path'."
           (javaimp-id-group id)
           (javaimp-id-version id)))
 
-(defun javaimp--get-jdk-jars ()
-  (and javaimp-java-home
-       (file-accessible-directory-p javaimp-java-home)
-       (let ((lib-dir
-             (concat (file-name-as-directory javaimp-java-home)
-                     (file-name-as-directory "jre")
-                     (file-name-as-directory "lib"))))
-        (directory-files lib-dir t "\\.jar\\'"))))
-
 
 ;; TODO use functions `cygwin-convert-file-name-from-windows' and
 ;; `cygwin-convert-file-name-to-windows' when they are available
diff --git a/javaimp.el b/javaimp.el
index cd340f4..aabb4a7 100644
--- a/javaimp.el
+++ b/javaimp.el
@@ -1,6 +1,6 @@
 ;;; javaimp.el --- Add and reorder Java import statements in Maven/Gradle 
projects  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2014-2019  Free Software Foundation, Inc.
+;; Copyright (C) 2014-2021  Free Software Foundation, Inc.
 
 ;; Author: Filipp Gunbin <fgunbin@fastmail.fm>
 ;; Maintainer: Filipp Gunbin <fgunbin@fastmail.fm>
@@ -110,9 +110,9 @@ The order of classes which were not matched is defined by
   :type 'integer)
 
 (defcustom javaimp-java-home (getenv "JAVA_HOME")
-  "Path to the JDK.  Directory jre/lib underneath this path is
-searched for JDK libraries.  By default, it is initialized from
-the JAVA_HOME environment variable."
+  "Path to the JDK.  Should contain subdirectory
+\"jre/lib\" (pre-JDK9) or just \"lib\".  By default, it is
+initialized from the JAVA_HOME environment variable."
   :group 'javaimp
   :type 'string)
 
@@ -159,6 +159,8 @@ to the completion alternatives list."
   "Alist of cached jars.  Each element is of the form (FILE
   . CACHED-JAR).")
 
+(defvar javaimp--jdk-classes 'need-init)
+
 
 
 ;;;###autoload
@@ -212,7 +214,7 @@ any module file."
                             (float-time (javaimp--get-file-ts 
(javaimp-module-file-orig cur)))
                           -1))
                   (float-time (javaimp-module-load-ts module)))
-           (message "Reloading dependencies for %s (some build-file changed)"
+           (message "Will reload dependencies for %s (some build-file changed)"
                      (javaimp-module-id cur))
            (setq need-update t)))
        (setq tmp (javaimp-node-parent tmp))))
@@ -311,76 +313,134 @@ any module file."
 
 ;;; Adding imports
 
-;; TODO narrow alternatives by class local name
-
 ;;;###autoload
 (defun javaimp-add-import (classname)
-  "Imports classname in the current file.  Interactively,
-asks for a class to import, adds import statement and calls
-`javaimp-organize-imports'.  Import statements are not
-duplicated.  Completion alternatives are constructed based on
-this module's dependencies' classes, JDK classes and top-level
-classes in the current module."
+  "Imports classname in the current file by asking for input (with
+completion) and calling `javaimp-organize-imports'.
+
+Completion alternatives are constructed as follows:
+
+- If `javaimp-java-home' is set then add JDK classes.  lib-dir is
+\"jre/lib\" or \"lib\" subdirectory.  First, attempt to read
+\"lib-dir/classlist\" file.  If there's no such file - fallback
+to reading all jar files in lib-dir.
+
+- If current module can be determined, then add all classes from
+its dependencies.
+
+- If `javaimp-include-current-module-classes' is set, then add
+current module's top-level classes.  If there's no current
+module, then add all top-level classes from the current file
+tree: if there's a \"package\" directive in the current file and
+it matches last components of the file name, then file tree
+starts in the parent directory of the package, otherwise just use
+current directory.
+
+- Keep only candidates whose class simple name (last component of
+a fully-qualified name) matches current `symbol-at-point'.  If a
+prefix arg is given, don't do this filtering."
   (interactive
    (let* ((file (expand-file-name (or buffer-file-name
                                      (error "Buffer is not visiting a 
file!"))))
-         (node (or (javaimp--find-node
-                    (lambda (m)
-                       (seq-some (lambda (dir)
-                                   (string-prefix-p dir file))
-                                 (javaimp-module-source-dirs m))))
-                   (error "Cannot find module by file: %s" file))))
-     (javaimp--update-module-maybe node)
-     (let ((module (javaimp-node-contents node)))
-       (list (completing-read
-             "Import: "
-             (append
-              ;; we're not caching full list of classes coming from module
-              ;; dependencies because jars may change and we need to reload
-              ;; them
-              (let ((jars (append (javaimp-module-dep-jars module)
-                                  (javaimp--get-jdk-jars))))
-                (apply #'seq-concatenate 'list
-                       (mapcar #'javaimp--get-jar-classes jars)))
-              (and javaimp-include-current-module-classes
-                   (javaimp--get-module-classes module)))
-             nil t nil nil (symbol-name (symbol-at-point)))))))
-  (barf-if-buffer-read-only)
+         (node (javaimp--find-node
+                (lambda (m)
+                   (seq-some (lambda (dir)
+                               (string-prefix-p dir file))
+                             (javaimp-module-source-dirs m)))))
+          (module (when node
+                    (javaimp--update-module-maybe node)
+                    (javaimp-node-contents node)))
+          (classes
+           (append
+            ;; jdk
+            (progn
+              (when (eq javaimp--jdk-classes 'need-init)
+                (setq javaimp--jdk-classes (javaimp--get-jdk-classes)))
+              javaimp--jdk-classes)
+            ;; module dependencies
+            (when module
+             ;; We're not caching full list of classes coming from
+             ;; module dependencies because jars may change and we
+             ;; need to reload them
+             (apply #'append
+                    (mapcar #'javaimp--get-jar-classes
+                             (javaimp-module-dep-jars module))))
+            ;; current module or source tree
+            (when javaimp-include-current-module-classes
+              (if module
+                  (javaimp--get-module-classes module)
+                (javaimp--get-directory-classes
+                 (or (javaimp--dir-above-current-package) default-directory))))
+            ))
+          (completion-regexp-list
+           (and (not current-prefix-arg)
+                (symbol-at-point)
+                (let ((prefix (regexp-quote (symbol-name (symbol-at-point)))))
+                  (list (concat "\\." prefix "[^.]*$\\|^" prefix "[^.]*$"))))))
+     (list (completing-read "Import: " classes nil t nil nil
+                            (symbol-name (symbol-at-point))))))
   (javaimp-organize-imports (cons classname 'ordinary)))
 
+(defun javaimp--get-jdk-classes ()
+  (when javaimp-java-home
+    (or (file-accessible-directory-p javaimp-java-home)
+        (user-error "Java home directory \"%s\" is not accessible" 
javaimp-java-home))
+    (let ((lib-dir
+           (mapconcat #'file-name-as-directory
+                      (list javaimp-java-home "jre" "lib") nil))) ;pre-java9
+      (unless (file-directory-p lib-dir)
+        (setq lib-dir
+              (mapconcat #'file-name-as-directory
+                         (list javaimp-java-home "lib") nil)) ;java9 and later
+        (or (file-directory-p lib-dir)
+            (user-error "JDK lib dir \"%s\" doesn't exist" lib-dir)))
+      (if (file-exists-p (concat lib-dir "classlist"))
+          ;; If classlist exists, read it
+          (with-temp-buffer
+            (insert-file-contents (concat lib-dir "classlist"))
+            (while (search-forward "/" nil t)
+             (replace-match "."))
+            (split-string (buffer-string) "\n" t))
+        ;; Otherwise, read jars, if any.  In pre-jdk9 versions, they
+        ;; used to contain actual classes.
+        (message "classlist file not found, fallback to reading jars from 
\"%s\"" lib-dir)
+        (apply #'append
+              (mapcar #'javaimp--get-jar-classes
+                       (directory-files lib-dir t "\\.jar\\'")))))))
+
 (defun javaimp--get-module-classes (module)
   "Returns list of top-level classes in current module"
   (append
    ;; source dirs
    (seq-mapcat (lambda (dir)
                  (and (file-accessible-directory-p dir)
-                     (javaimp--get-directory-classes dir nil)))
+                     (javaimp--get-directory-classes dir)))
                (javaimp-module-source-dirs module))
    ;; additional source dirs
    (seq-mapcat (lambda (rel-dir)
                  (let ((dir (concat (javaimp-module-build-dir module)
                                     (file-name-as-directory rel-dir))))
                   (and (file-accessible-directory-p dir)
-                       (javaimp--get-directory-classes dir nil))))
+                        (javaimp--get-directory-classes dir))))
                javaimp-additional-source-dirs)))
 
-(defun javaimp--get-directory-classes (dir prefix)
-  (append
-   ;; .java files in current directory
-   (mapcar (lambda (file)
-            (concat prefix (file-name-sans-extension (car file))))
-          (seq-filter (lambda (file) (null (cadr file))) ;only files
-                      (directory-files-and-attributes dir nil "\\.java\\'" t)))
-   ;; descend into subdirectories
-   (apply #'seq-concatenate 'list
-         (mapcar (lambda (subdir)
-                   (let ((name (car subdir)))
-                     (javaimp--get-directory-classes
-                      (concat dir (file-name-as-directory name)) (concat 
prefix name "."))))
-                 (seq-filter (lambda (file)
-                               (and (eq (cadr file) t) ;only directories
-                                    (null (member (car file) '("." "..")))))
-                             (directory-files-and-attributes dir nil nil 
t))))))
+(defun javaimp--dir-above-current-package ()
+  (save-excursion
+    (save-restriction
+      (widen)
+      (goto-char (point-min))
+      (when (re-search-forward "^\\s *package\\s +\\([^;]+\\)\\s *;" nil t)
+        (string-remove-suffix
+         (mapconcat #'file-name-as-directory
+                    (split-string (match-string 1) "\\." t) nil)
+         default-directory)))))
+
+(defun javaimp--get-directory-classes (dir)
+  (mapcar (lambda (filename)
+            (replace-regexp-in-string
+             "[/\\]+" "."
+             (string-remove-prefix dir (file-name-sans-extension filename))))
+          (directory-files-recursively dir "\\.java\\'")))
 
 
 ;; Organizing imports
@@ -400,7 +460,7 @@ the beginning of buffer.
 Classes within a single group are ordered in a lexicographic
 order.  Imports not matched by any regexp in `javaimp-import-group-alist'
 are assigned a default order defined by
-`javaimp-import-default-order'.
+`javaimp-import-default-order'.  Duplicate imports are squashed.
 
 NEW-IMPORTS is a list of additional imports; each element should
 be of the form (CLASS . TYPE), where CLASS is a string and TYPE
@@ -450,7 +510,7 @@ is `ordinary' or `static'.  Interactively, NEW-IMPORTS is 
nil."
 (defun javaimp--parse-imports ()
   "Returns (FIRST LAST . IMPORTS)"
   (let (first last imports)
-    (while (re-search-forward 
"^\\s-*import\\s-+\\(static\\s-+\\)?\\([._[:word:]]+\\)" nil t)
+    (while (re-search-forward "^\\s *import\\s +\\(static\\s 
+\\)?\\([._[:word:]]+\\)" nil t)
       (let ((type (if (match-string 1) 'static 'ordinary))
            (class (match-string 2)))
        (push (cons class type) imports))
@@ -462,7 +522,7 @@ is `ordinary' or `static'.  Interactively, NEW-IMPORTS is 
nil."
   (cond (start
         ;; if there were any imports, we start inserting at the same place
         (goto-char start))
-       ((re-search-forward "^\\s-*package\\s-" nil t)
+       ((re-search-forward "^\\s *package\\s " nil t)
         ;; if there's a package directive, insert one blank line below and
         ;; leave point after it
         (end-of-line)
@@ -498,11 +558,13 @@ is `ordinary' or `static'.  Interactively, NEW-IMPORTS is 
nil."
        (insert (format pattern (caar import)) ?\n)
        (setq last-order order)))))
 
+
 (defun javaimp-reset (arg)
   "Forget loaded trees state.  With prefix arg, also reset jars
 cache."
   (interactive "P")
-  (setq javaimp-project-forest nil)
+  (setq javaimp-project-forest nil
+        javaimp--jdk-classes 'need-init)
   (when arg
     (setq javaimp-cached-jars nil)))
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]