[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] javaimp_devel 4b918c0: in progress
From: |
Filipp Gunbin |
Subject: |
[elpa] javaimp_devel 4b918c0: in progress |
Date: |
Thu, 07 Apr 2016 20:13:30 +0000 |
branch: javaimp_devel
commit 4b918c0bc257c6d3f608c7514051826051b0cc42
Author: Filipp Gunbin <address@hidden>
Commit: Filipp Gunbin <address@hidden>
in progress
---
packages/javaimp/javaimp.el | 371 ++++++++++++++++++-------------------------
1 files changed, 152 insertions(+), 219 deletions(-)
diff --git a/packages/javaimp/javaimp.el b/packages/javaimp/javaimp.el
index fcca837..a2ab7c4 100644
--- a/packages/javaimp/javaimp.el
+++ b/packages/javaimp/javaimp.el
@@ -12,7 +12,7 @@
;; Allows to manage Java import statements in Maven projects.
;;
;; Quick start: customize `javaimp-import-group-alist', `javaimp-jdk-home'
-;; and call `javaimp-maven-visit-root', then in a Java buffer visiting a
+;; and call `javaimp-maven-visit-project', then in a Java buffer visiting a
;; file under that module or one of its submodules call
;; `javaimp-organize-imports' or `javaimp-add-import'. `javaimp-add-import'
;; will provide you a helpful completion, and the default value (the one
@@ -56,7 +56,7 @@
;;
;; Details on commands.
;;
-;; `javaimp-maven-visit-root' is the first command you should issue to
+;; `javaimp-maven-visit-project' is the first command you should issue to
;; use this module. It reads the pom structure recursively and records
;; which files belong to which module. Maven help:effective-pom command is
;; used to do that.
@@ -74,7 +74,7 @@
;; '("\\`\\(my\\.company\\.\\|my\\.company2\\.\\)" . 80))
;;
;; (setq javaimp-jdk-home (getenv "JAVA_HOME"))
-;; (setq javaimp-include-current-project-classes t)
+;; (setq javaimp-include-current-module-classes t)
;; (setq javaimp-additional-source-dirs '("generated-sources/thrift"))
;;
;; (add-hook 'java-mode-hook
@@ -85,10 +85,10 @@
;;
;; TODO before version 1.0:
;;
-;; - correct submodule tree for each top-level project (now top-level projects
-;; hold linear submodule list and this prevents modification checking for
parent
-;; poms). If a project doesn't have any children, then it should be in the
list
-;; by itself.
+;; - correct submodule tree for each top-level project (now top-level
+;; projects hold linear submodule list and this prevents modification
+;; checking for parent poms). Each project should represented as (NAME
+;; OBJECT . CHILDREN).
;;
;; - cl-defstruct for data
;;
@@ -102,17 +102,26 @@
;; calling `cygpath'. See https://cygwin.com/ml/cygwin/2013-03/msg00228.html.
;;
;; - include <packaging> into module info
+;;
+;; - each module's parent should be set according to its "parent" node
+;;
+;; - when a module has a parent but do not inherits, its jars are not added
+;;
+;; - save/restore state
+;;
+;; - API functions should check pom file modifications and refresh if needed
;;
;;; Code:
+(require 'cl-macs)
(require 'seq)
;;; User options
(defgroup javaimp ()
- "Add and reorder Java import statements in Maven projects.")
+ "Add and reorder Java import statements in Maven projects")
(defcustom javaimp-import-group-alist '(("\\`javax?\\." . 10))
"Specifies how to group classes and how to order resulting
@@ -130,7 +139,10 @@ The order of classes which were not matched is defined by
`javaimp-import-group-alist'")
(defcustom javaimp-jdk-home nil
- "Path to the JDK")
+ "Path to the JDK. If you have JAVA_HOME environment variable
+set up, this variable can be set like this:
+
+(setq javaimp-jdk-home (getenv \"JAVA_HOME\"))")
(defcustom javaimp-additional-source-dirs nil
"List of directories where additional (e.g. generated)
@@ -152,13 +164,14 @@ supported yet.")
(defcustom javaimp-mvn-program "mvn"
"Path to the `mvn' program")
-(defcustom javaimp-cygpath-program "cygpath"
+(defcustom javaimp-cygpath-program
+ (if (eq system-type 'cygwin) "cygpath")
"Path to the `cygpath' program")
(defcustom javaimp-jar-program "jar"
"Path to the `jar' program")
-(defcustom javaimp-include-current-project-classes t
+(defcustom javaimp-include-current-module-classes t
"If non-nil, current project's classes are included into completion
alternatives.
@@ -167,11 +180,11 @@ Only top-level classes are included.")
;;; Variables and constants
-(defvar javaimp-maven-root-modules nil
- "Loaded root Maven modules")
+(defvar javaimp-project-forest nil
+ "Visited projects")
-(defvar javaimp-jar-classes-cache nil
- "Jar classes cache")
+(defvar javaimp-jar-cache nil
+ "Cache for jar contents")
(defconst javaimp-debug-buf-name "*javaimp-debug*")
@@ -195,121 +208,60 @@ Only top-level classes are included.")
(car (cddr el)))
-;;; Data representation
-
-;; FIXME: use cl-defstruct!
-
-;; Module
-
-(defsubst javaimp-make-mod (artifact pom-file source-dir test-source-dir
build-dir
- pom-file-mod-ts jars-list parent parent-ts
final-name)
- (list artifact pom-file source-dir test-source-dir build-dir
- pom-file-mod-ts jars-list parent parent-ts final-name))
-
-(defsubst javaimp-get-mod-artifact (module)
- (nth 0 module))
-
-(defsubst javaimp-get-mod-pom-file (module)
- (nth 1 module))
-(defsubst javaimp-set-mod-pom-file (module value)
- (setcar (nthcdr 1 module) value))
-
-(defsubst javaimp-get-mod-source-dir (module)
- (nth 2 module))
-
-(defsubst javaimp-get-mod-test-source-dir (module)
- (nth 3 module))
-
-(defsubst javaimp-get-mod-build-dir (module)
- (nth 4 module))
-
-(defsubst javaimp-get-mod-pom-mod-ts (module)
- (nth 5 module))
-(defsubst javaimp-set-mod-pom-mod-ts (module value)
- (setcar (nthcdr 5 module) value))
-
-(defsubst javaimp-get-mod-pom-deps (module)
- (nth 6 module))
-(defsubst javaimp-set-mod-pom-deps (module value)
- (setcar (nthcdr 6 module) value))
-
-(defsubst javaimp-get-mod-parent (module)
- (nth 7 module))
-(defsubst javaimp-set-mod-parent (module value)
- (setcar (nthcdr 7 module) value))
-
-(defsubst javaimp-get-mod-parent-ts (module)
- (nth 8 module))
-(defsubst javaimp-set-mod-parent-ts (module value)
- (setcar (nthcdr 8 module) value))
-
-(defsubst javaimp-get-mod-final-name (module)
- (nth 9 module))
-(defsubst javaimp-set-mod-final-name (module value)
- (setcar (nthcdr 9 module) value))
+;; Structs
-;; Artifact
+(cl-defstruct javaimp-node
+ parent children contents)
-(defsubst javaimp-make-artifact (group-id artifact-id version)
- (list group-id artifact-id version))
+(cl-defstruct javaimp-module
+ id file file-ts final-name
+ source-dir test-source-dir build-dir
+ dep-jars)
-(defsubst javaimp-artifact-group-id (artifact)
- (car artifact))
-
-(defsubst javaimp-artifact-artifact-id (artifact)
- (cadr artifact))
-
-(defsubst javaimp-artifact-version (artifact)
- (nth 2 artifact))
-
-(defun javaimp-artifact-to-string (artifact)
+(defun javaimp-print-id (id)
(format "%s:%s:%s"
- (javaimp-artifact-artifact-id artifact)
- (javaimp-artifact-group-id artifact)
- (javaimp-artifact-version artifact))) ;FIXME: `artifact' is not a
function!
-
-(defun javaimp-parse-artifact (artifact)
- (apply #'javaimp-make-artifact (split-string artifact ":")))
-
-
-;; JAR
-
-(defsubst javaimp-make-jar (jar-path jar-mod-ts classes-list)
- (cons jar-path (cons jar-mod-ts classes-list)))
-
-(defsubst javaimp-get-jar-path (jar)
- (car jar))
-
-(defsubst javaimp-get-jar-mod-ts (jar)
- (cadr jar))
+ (javaimp-id-artifact id)
+ (javaimp-id-group id)
+ (javaimp-id-version id)))
-(defsubst javaimp-set-jar-mod-ts (jar value)
- (setcar (cdr jar) value))
+(cl-defstruct (javaimp-id
+ (:print-function #'javaimp-print-id))
+ group artifact version)
-(defsubst javaimp-get-jar-classes-list (jar)
- (cddr jar))
-
-(defsubst javaimp-set-jar-classes-list (jar value)
- (setcdr (cdr jar) value))
+(cl-defstruct javaimp-jar
+ file file-ts classes)
-;;; Loading Maven projects tree
+;;; Loading Maven projects
+
+;; TODO if it's already there?
;;;###autoload
-(defun javaimp-maven-visit-root (path)
- "Loads all modules starting from root module identified by
-PATH. PATH should point to a directory containing pom.xml."
- (interactive "DVisit maven root project: ")
- (let* ((root-pom (expand-file-name
- (concat (file-name-as-directory path) "pom.xml")))
- (modules (if (file-readable-p root-pom)
- (javaimp-maven-load-module-tree root-pom)
- (error "Cannot read root pom: %s" root-pom)))
- (root-project (assoc root-pom javaimp-maven-root-modules)))
- (if root-project
- (setcdr root-project modules)
- (push (cons root-pom modules) javaimp-maven-root-modules))
- (message "Loaded modules for %s" path)))
+(defun javaimp-maven-visit-project (path)
+ "Loads a project and its submodules. PATH should point to a
+directory containing pom.xml."
+ (interactive "DVisit maven project: ")
+ (let ((file (expand-file-name
+ (concat (file-name-as-directory path) "pom.xml"))))
+ (unless (file-readable-p file)
+ (error "Cannot read file: %s" file))
+ (push (javaimp-maven-load-tree file) javaimp-project-forest)
+ (message "Loaded tree for %s" file)))
+
+(defun javaimp-maven-load-tree (file)
+ ;; TODO
+ "Creates a tree of Maven projects starting from FILE"
+ (let* ((effective-pom (javaimp-parse-effective-pom pom))
+ (project-elts
+ (cond ((assq 'projects effective-pom) ;project contains <module>
tag(s)
+ (javaimp-xml-child-list (assq 'projects effective-pom)
'project))
+ ((assq 'project effective-pom) ;single-module project
+ (list (assq 'project effective-pom)))
+ (t
+ (error "Cannot find projects in XML tree"))))
+ (modules-alist (javaimp-maven-process-projects project-elts)))
+ (javaimp-fill-pom-file-paths modules-alist pom)
+ modules-alist))
(defun javaimp-parse-effective-pom (pom)
"Calls `mvn help:effective:pom and returns XML parse tree"
@@ -333,26 +285,13 @@ PATH. PATH should point to a directory containing
pom.xml."
(match-end 0)))))
(xml-parse-region xml-start-pos xml-end-pos)))))
-(defun javaimp-maven-load-module-tree (pom)
- "Returns an alist of all Maven modules in a hierarchy starting
-with POM"
- (let* ((effective-pom (javaimp-parse-effective-pom pom))
- (project-elts
- (cond ((assq 'projects effective-pom) ;project contains <module>
tag(s)
- (javaimp-xml-child-list (assq 'projects effective-pom)
'project))
- ((assq 'project effective-pom) ;single-module project
- (list (assq 'project effective-pom)))
- (t
- (error "Cannot find projects in XML tree"))))
- (modules-alist (javaimp-maven-process-projects project-elts)))
- (javaimp-fill-pom-file-paths modules-alist pom)
- modules-alist))
+
(defun javaimp-fill-pom-file-paths (modules pom)
"Subroutine of `javaimp-maven-load-module-tree'"
(let ((artifact-alist (javaimp-traverse-pom-tree (list pom))))
(dolist (module modules)
- (let* ((artifact (javaimp-get-mod-artifact module))
+ (let* ((artifact (javaimp-mod-artifact module))
(path
(cdr (or (seq-find (lambda (el)
(equal artifact (car el)))
@@ -376,6 +315,8 @@ with POM"
(car (process-lines javaimp-cygpath-program "-u" path))
path))
+;; todo set everything immediately
+
(defun javaimp-maven-process-projects (projects-elts)
(mapcar
(lambda (project-elt)
@@ -462,22 +403,18 @@ platform default format."
the temporary buffer and returns its result"
(message "Calling \"mvn %s\" on pom: %s" target pom-file)
(with-temp-buffer
- (let* ((pom-file (if (eq system-type 'cygwin)
- (car (process-lines javaimp-cygpath-program
- "-m" pom-file))
- pom-file))
+ (let* ((pom-file (javaimp-cygpath-convert-maybe pom-file))
(status
- ;; FIXME on GNU/Linux Maven strangely outputs ^M chars. Check
- ;; also jar output with the same var binding below.
- (let ((coding-system-for-read (when (eq system-type 'cygwin)
'utf-8-dos)))
+ ;; FIXME check Maven output on Gnu/Linux
+ (let ((coding-system-for-read
+ (if (eq system-type 'cygwin) 'utf-8-dos)))
(process-file javaimp-mvn-program nil t nil "-f" pom-file
target)))
- (output-buf (current-buffer)))
+ (b (current-buffer)))
(with-current-buffer (get-buffer-create javaimp-debug-buf-name)
(erase-buffer)
- (insert-buffer-substring output-buf))
+ (insert-buffer-substring b))
(or (and (numberp status) (= status 0))
- (error "Maven target \"%s\" failed with status \"%s\""
- target status))
+ (error "Maven target \"%s\" failed with status \"%s\"" target status))
(goto-char (point-min))
(funcall handler))))
@@ -487,7 +424,7 @@ the temporary buffer and returns its result"
(defun javaimp-maven-fetch-module-deps (module)
"Returns list of dependency jars for MODULE"
(javaimp-call-mvn
- (javaimp-get-mod-pom-file module) "dependency:build-classpath"
+ (javaimp-mod-pom-file module) "dependency:build-classpath"
(lambda ()
(let (deps-line)
(goto-char (point-min))
@@ -512,51 +449,44 @@ the temporary buffer and returns its result"
(not (equal (float-time curr-ts) (float-time last-ts)))
(javaimp-any-file-ts-updated (cdr files))))))
-(defun javaimp-get-dep-jars-cached (module parent)
+(defun javaimp-get-deps-cached (module parent)
"Returns a list of dependency jar file paths for a MODULE.
Both MODULE and PARENT poms are checked for updates because
PARENT pom may have some versions which are inherited by the
MODULE."
(when (javaimp-any-file-ts-updated
- (remq nil (list (cons (javaimp-get-mod-pom-file module)
- (javaimp-get-mod-pom-mod-ts module))
+ (remq nil (list (cons (javaimp-mod-pom-file module)
+ (javaimp-mod-pom-mod-ts module))
(when parent
(cons
- (javaimp-get-mod-pom-file parent)
+ (javaimp-mod-pom-file parent)
;; here we check the saved parent ts because it
;; matters what version we had when we were
;; reloading this pom the last time
- (javaimp-get-mod-parent-ts module))))))
+ (javaimp-mod-parent-ts module))))))
;; (re-)fetch dependencies
(javaimp-set-mod-pom-deps
module (javaimp-maven-fetch-module-deps module))
;; update timestamps
(javaimp-set-mod-pom-mod-ts
- module (javaimp-get-file-ts (javaimp-get-mod-pom-file module)))
+ module (javaimp-get-file-ts (javaimp-mod-pom-file module)))
(when parent
(javaimp-set-mod-parent-ts
- module (javaimp-get-file-ts (javaimp-get-mod-pom-file parent)))))
- (javaimp-get-mod-pom-deps module))
+ module (javaimp-get-file-ts (javaimp-mod-pom-file parent)))))
+ (javaimp-mod-pom-deps module))
(defun javaimp-get-jdk-jars ()
- "Returns list of jars from the jre/lib subdirectory of the JDK
-directory"
- (when javaimp-jdk-home
- (directory-files (concat (file-name-as-directory javaimp-jdk-home)
- (file-name-as-directory "jre/lib"))
- t "\\.jar$")))
+ (if javaimp-jdk-home
+ (let ((jre-lib-dir
+ (concat (file-name-as-directory javaimp-jdk-home)
+ (file-name-as-directory "jre")
+ (file-name-as-directory "lib"))))
+ (directory-files jre-lib-dir t "\\.jar\\'"))))
-(defun javaimp-get-jar-classes-cached (jar)
- (let ((current-jar-mod-ts
- (nth 5 (file-attributes (javaimp-get-jar-path jar)))))
- (unless (equal (float-time (javaimp-get-jar-mod-ts jar))
- (float-time current-jar-mod-ts))
- (javaimp-set-jar-classes-list jar (javaimp-fetch-jar-classes jar))
- (javaimp-set-jar-mod-ts jar current-jar-mod-ts))
- (javaimp-get-jar-classes-list jar)))
+;; Working with jar and its cache
(defun javaimp-fetch-jar-classes (jar)
- (let ((jar-file (javaimp-get-jar-path jar))
+ (let ((jar-file (javaimp-jar-path jar))
result)
(message "Reading classes in jar: %s" jar-file)
(with-temp-buffer
@@ -572,42 +502,41 @@ directory"
result))
result)))
-(defun javaimp-collect-jar-classes (jar-paths)
+(defun javaimp-get-jar-classes-cached (jar)
+ (let ((current-jar-mod-ts
+ (nth 5 (file-attributes (javaimp-jar-path jar)))))
+ (unless (equal (float-time (javaimp-jar-mod-ts jar))
+ (float-time current-jar-mod-ts))
+ (javaimp-set-jar-classes-list jar (javaimp-fetch-jar-classes jar))
+ (javaimp-set-jar-mod-ts jar current-jar-mod-ts))
+ (javaimp-jar-classes-list jar)))
+
+(defun javaimp-collect-classes (jar-paths)
(let (result jar)
(dolist (jar-path jar-paths result)
- (setq jar (assoc jar-path javaimp-jar-classes-cache))
+ (setq jar (assoc jar-path javaimp-jar-cache))
(unless jar
(setq jar (javaimp-make-jar jar-path nil nil))
- (push jar javaimp-jar-classes-cache))
+ (push jar javaimp-jar-cache))
(setq result (append (javaimp-get-jar-classes-cached jar) result)))))
-(defun javaimp-get-module-from-root (roots predicate)
- (if (null roots)
- nil
- (let ((result (javaimp-get-module (cdr (car roots)) predicate)))
- (or result
- (javaimp-get-module-from-root (cdr roots) predicate)))))
-
-(defun javaimp-get-module (modules predicate)
- (cond ((null modules)
- nil)
- ((funcall predicate (car modules))
- (car modules))
- (t
- (javaimp-get-module (cdr modules) predicate))))
-
-(defun javaimp-get-module-by-file (file)
- (javaimp-get-module-from-root
- javaimp-maven-root-modules
- (lambda (mod)
- (or (string-prefix-p (javaimp-get-mod-source-dir mod) file)
- (string-prefix-p (javaimp-get-mod-test-source-dir mod) file)))))
-
-(defun javaimp-get-module-by-artifact (artifact)
- (javaimp-get-module-from-root
- javaimp-maven-root-modules
- (lambda (mod)
- (equal (javaimp-get-mod-artifact mod) artifact))))
+;; Searching and navigating through projects
+
+(defun javaimp-find-module (predicate)
+ (javaimp--find-module javaimp-project-forest predicate))
+
+(defun javaimp--find-module (projects predicate)
+ (if projects
+ (let ((project (car projects)))
+ (or (javaimp--get-module (cdr project) predicate)
+ (javaimp--find-module (cdr projects) predicate)))))
+
+(defun javaimp--get-module (modules predicate)
+ (if modules
+ (let ((module (car modules)))
+ (if (funcall predicate module)
+ module
+ (javaimp--get-module (cdr modules) predicate)))))
;;; Some functions for use in other programs
@@ -615,17 +544,20 @@ directory"
(defun javaimp-get-source-directories ()
(append
(mapcar (lambda (root)
- (mapcar #'javaimp-get-mod-source-dir (cdr root)))
- javaimp-maven-root-modules)))
+ (mapcar #'javaimp-mod-source-dir (cdr root)))
+ javaimp-project-forest)))
(defun javaimp-get-all-modules ()
"Returns flat list of all child modules."
(apply #'seq-concatenate 'list
- (mapcar #'cdr javaimp-maven-root-modules)))
+ (mapcar #'cdr javaimp-project-forest)))
;;; Adding and organizing imports
+;; TODO without prefix arg narrow alternatives by local name; with prefix
+;; arg - include all classes in alternatives
+
;;;###autoload
(defun javaimp-add-import (classname)
"Imports CLASSNAME in the current file. Interactively,
@@ -636,27 +568,28 @@ module."
(let* ((file (expand-file-name
(or buffer-file-name
(error "Buffer is not visiting a file!"))))
- (module (or (javaimp-get-module-by-file file)
- (error "Cannot determine module for file: %s" file)))
- (parent (javaimp-get-module-by-artifact
- (javaimp-get-mod-parent module))))
+ (module (or (javaimp-find-module
+ (lambda (m)
+ (or (string-prefix-p (javaimp-mod-source-dir m) file)
+ (string-prefix-p (javaimp-mod-test-source-dir m)
file))))
+ (error "Cannot find module by file: %s" file))))
(list (completing-read
"Import: "
(append
- (javaimp-collect-jar-classes
- (append (javaimp-get-dep-jars-cached module parent)
- (javaimp-get-jdk-jars)))
- (and javaimp-include-current-project-classes
- (javaimp-get-module-classes module)))
+ (let ((jars (append (javaimp-get-deps-cached module)
+ (javaimp-get-jdk-jars))))
+ (javaimp-collect-classes jars))
+ (and javaimp-include-current-module-classes
+ (javaimp-classes-from-source module)))
nil t nil nil (symbol-name (symbol-at-point))))))
(javaimp-organize-imports classname))
-(defun javaimp-get-module-classes (module)
+(defun javaimp-classes-from-source (module)
"Scans current project and returns a list of top-level classes in both the
source directory and test source directory"
- (let ((src-dir (javaimp-get-mod-source-dir module))
- (test-src-dir (javaimp-get-mod-test-source-dir module))
- (build-dir (javaimp-get-mod-build-dir module)))
+ (let ((src-dir (javaimp-mod-source-dir module))
+ (test-src-dir (javaimp-mod-test-source-dir module))
+ (build-dir (javaimp-mod-build-dir module)))
(append
(and javaimp-additional-source-dirs
(seq-mapcat
@@ -774,12 +707,12 @@ argument is a list of additional classes to import."
(defun javaimp-invalidate-jar-classes-cache ()
"Resets jar classes cache (debugging only)"
(interactive)
- (setq javaimp-jar-classes-cache nil))
+ (setq javaimp-jar-cache nil))
(defun javaimp-forget-all-visited-modules ()
- "Resets `javaimp-maven-root-modules' (debugging only)"
+ "Resets `javaimp-project-forest' (debugging only)"
(interactive)
- (setq javaimp-maven-root-modules nil))
+ (setq javaimp-project-forest nil))
(defun javaimp-reset ()
"Resets all data (debugging only)"
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [elpa] javaimp_devel 4b918c0: in progress,
Filipp Gunbin <=