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

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

[elpa] externals/javaimp 9b49ee1: Include inner classes in completion ca


From: Filipp Gunbin
Subject: [elpa] externals/javaimp 9b49ee1: Include inner classes in completion candidates
Date: Thu, 27 May 2021 16:05:00 -0400 (EDT)

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

    Include inner classes in completion candidates
---
 javaimp-tests.el                      | 22 +++++++++-
 javaimp-util.el                       | 52 +++++++++++++++++++++++
 javaimp.el                            | 78 +++++++++++++++++------------------
 testdata/test-get-file-classes-1.java | 60 +++++++++++++++++++++++++++
 4 files changed, 170 insertions(+), 42 deletions(-)

diff --git a/javaimp-tests.el b/javaimp-tests.el
index f382302..36b4686 100644
--- a/javaimp-tests.el
+++ b/javaimp-tests.el
@@ -6,7 +6,7 @@
 ;; Maintainer: Filipp Gunbin <fgunbin@fastmail.fm>
 
 (require 'ert)
-(require 'javaimp-maven)
+(require 'javaimp)
 
 (ert-deftest javaimp-test--maven-projects-from-xml--project ()
   (with-temp-buffer
@@ -21,3 +21,23 @@
     (let ((projects (javaimp--maven-projects-from-xml
                     (xml-parse-region (point-min) (point-max)))))
       (should (eql (length projects) 2)))))
+
+
+(ert-deftest javaimp-test--get-package ()
+  (with-temp-buffer
+    (insert "//package org.commented1;
+/*package org.commented2;*/
+  package org.foo;")
+    (should (equal (javaimp--get-package) "org.foo"))))
+
+(ert-deftest javaimp-test--get-file-classes ()
+  (should (equal (javaimp--get-file-classes
+                  (concat javaimp--basedir 
"testdata/test-get-file-classes-1.java"))
+                 '("org.foo.Top"
+                   "org.foo.Top.CInner1"
+                   "org.foo.Top.CInner1.CInner1_CInner1"
+                   "org.foo.Top.IInner1"
+                   "org.foo.Top.IInner1.IInner1_IInner1"
+                   "org.foo.Top.IInner1.IInner1_CInner1"
+                   "org.foo.Top.EInner1"
+                   "org.foo.Top.EInner1.EInner1_EInner1"))))
diff --git a/javaimp-util.el b/javaimp-util.el
index 9304fce..f2f4c00 100644
--- a/javaimp-util.el
+++ b/javaimp-util.el
@@ -157,4 +157,56 @@ buffer and returns its result"
       (setf (javaimp-node-children this-node) child-nodes)
       this-node)))
 
+
+;; Java source parsing
+
+(defun javaimp--get-package ()
+  (save-excursion
+    (save-restriction
+      (widen)
+      (goto-char (point-min))
+      (catch 'found
+        (while (re-search-forward "^\\s *package\\s +\\([^;]+\\)\\s *;" nil t)
+          (let ((state (syntax-ppss)))
+            (unless (syntax-ppss-context state)
+              (throw 'found (match-string 1)))))))))
+
+(defun javaimp--get-file-classes (file)
+  (with-temp-buffer
+    (insert-file-contents file)
+    (let ((parse-sexp-ignore-comments t)
+          (class-re (concat
+                     (regexp-opt '("class" "interface" "enum") 'words)
+                     (rx (and (+ (syntax whitespace))
+                              (group (+ (any alnum ?_)))))))
+          res)
+      (while (re-search-forward class-re nil t)
+        (let ((state (syntax-ppss))
+              curr)
+          (unless (syntax-ppss-context state)
+            (setq curr (list (match-string 2)))
+            ;; collect enclosing classes, if any
+            (save-excursion
+              (catch 'stop
+                (while (nth 1 state)
+                  ;; find innermost enclosing open-bracket
+                  (goto-char (nth 1 state))
+                  (if (and (= (char-after) ?{)
+                           (re-search-backward class-re nil t)
+                           ;; if there's no paren in between - assume
+                           ;; it's a valid class (not a method - this
+                           ;; way we exclude local classes)
+                           (not (save-match-data
+                                  (search-forward "(" (nth 1 state) t))))
+                      (progn
+                        (push (match-string 2) curr)
+                        (setq state (syntax-ppss)))
+                    (setq curr nil)
+                    (throw 'stop nil)))))
+            (when curr
+              (let ((package (javaimp--get-package)))
+                (if package (push package curr)))
+              (push (mapconcat #'identity curr ".") res)))))
+      (nreverse res))))
+
 (provide 'javaimp-util)
diff --git a/javaimp.el b/javaimp.el
index b3338c5..1ea804d 100644
--- a/javaimp.el
+++ b/javaimp.el
@@ -49,9 +49,6 @@
 ;; from the build tool again.  If a jar file was changed, its contents
 ;; are re-read.
 ;;
-;; Currently inner classes are filtered out from completion alternatives.
-;; You can always import top-level class and use qualified name.
-;;
 ;;
 ;;   Example:
 ;;
@@ -275,16 +272,24 @@ any module file."
          ;; needs to be converted appropriately.
          (javaimp-cygpath-convert-maybe file 'windows)))
       (goto-char (point-min))
-      (save-excursion
-        (while (re-search-forward "^classes/" nil t)
-         (replace-match "")))
-      (save-excursion
-        (while (search-forward "/" nil t)
-         (replace-match ".")))
-      (let (result)
-       (while (re-search-forward "^\\([[:alnum:]._]+\\)\\.class$" nil t)
-         (push (match-string 1) result))
-       result))))
+      (let (result curr)
+       (while (re-search-forward
+                (rx (and bol
+                         (? "classes/") ; prefix output by jmod
+                         (group (+ (any alnum "_/$")))
+                         ".class"
+                         eol))
+                nil t)
+          (setq curr (match-string 1))
+          (unless (or (string-suffix-p "module-info" curr)
+                      (string-suffix-p "package-info" curr)
+                      ;; like Provider$1.class
+                      (string-match-p "\\$[[:digit:]]" curr))
+            (push
+             (string-replace "/" "."
+                             (string-replace "$" "." curr))
+             result)))
+        result))))
 
 
 ;; Tree search routines
@@ -353,12 +358,11 @@ subdirectory - fallback to reading all jar files in 
lib-dir.
 sits 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.
+current module's classes.  If there's no current module, then add
+all 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
@@ -426,38 +430,30 @@ prefix arg is given, don't do this filtering."
           (user-error "JRE lib dir \"%s\" doesn't exist" dir))))))
 
 (defun javaimp--get-module-classes (module)
-  "Returns list of top-level classes in current module"
+  "Returns list of classes in current module"
   (append
    ;; source dirs
-   (seq-mapcat (lambda (dir)
-                 (and (file-accessible-directory-p dir)
-                     (javaimp--get-directory-classes dir)))
+   (seq-mapcat #'javaimp--get-directory-classes
                (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))))
+                 (javaimp--get-directory-classes
+                  (concat (javaimp-module-build-dir module)
+                          (file-name-as-directory rel-dir))))
                javaimp-additional-source-dirs)))
 
 (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)))))
+  (let ((package (javaimp--get-package)))
+    (when package
+      (string-remove-suffix
+       (mapconcat #'file-name-as-directory
+                  (split-string package "\\." 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\\'")))
+  (if (file-accessible-directory-p dir)
+      (seq-mapcat #'javaimp--get-file-classes
+                  (directory-files-recursively dir "\\.java\\'"))))
 
 
 ;; Organizing imports
diff --git a/testdata/test-get-file-classes-1.java 
b/testdata/test-get-file-classes-1.java
new file mode 100644
index 0000000..ba36d31
--- /dev/null
+++ b/testdata/test-get-file-classes-1.java
@@ -0,0 +1,60 @@
+package org.foo;
+
+public class Top {
+    public static class CInner1<T, S> {
+        public void foo_bar() {
+            if (true) {
+                class CInner1_CLocal1 implements Serializable {
+                    void foo_bar() {
+                        System.out.println("");
+                        if (true) {
+                            class CInner1_CLocal1_CLocal1 extends Object {
+                                public void foo_bar() {
+                                    System.out.println("");
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            class CInner1_CLocal2 extends Object {
+                void foo_bar() {
+                    System.out.println("");
+                }
+            }
+        }
+
+        private Object obj = new Object();
+        class CInner1_CInner1 {
+        }
+    }
+
+    interface IInner1 {
+        interface IInner1_IInner1 extends A<B, C>, Serializable {
+            void foo_bar();
+        }
+
+        static class IInner1_CInner1 {
+            public void foo_bar() {
+                if (true) {
+                    System.out.println("");
+                }
+            }
+        }
+    }
+
+    enum EInner1 {
+        A("a"),
+        B("b");
+        private EInner1() {
+        }
+        public void foo_bar() {
+            System.out.println("");
+        }
+
+        enum EInner1_EInner1 {
+            C, D
+        }
+    }
+}



reply via email to

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