├── .gitignore
├── Makefile
├── Cask
├── .travis.yml
├── test
└── java-imports-test.el
├── README.org
└── java-imports.el
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled and temporary files
2 | *.elc
3 | *~
4 |
5 | # Cask
6 | /.cask
7 | dist
8 |
9 | # Ecukes
10 | /features/project/.cask
11 | /features/project/test/*.el
12 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | CASK ?= cask
2 | EMACS ?= emacs
3 |
4 | all: test
5 |
6 | test: unit
7 |
8 | unit:
9 | ${CASK} exec ert-runner
10 |
11 | ecukes:
12 | ${CASK} exec ecukes
13 |
14 | install:
15 | ${CASK} install
16 |
--------------------------------------------------------------------------------
/Cask:
--------------------------------------------------------------------------------
1 | (source gnu)
2 | (source melpa)
3 |
4 | (package-file "java-imports.el")
5 |
6 | (depends-on "s")
7 | (depends-on "pcache")
8 |
9 | (development
10 | (depends-on "cask-package-toolset")
11 | (depends-on "f")
12 | (depends-on "ecukes")
13 | (depends-on "ert-runner")
14 | (depends-on "s")
15 | (depends-on "pcache")
16 | (depends-on "el-mock"))
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: generic
2 | sudo: false
3 | before_install:
4 | - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh
5 | - evm install $EVM_EMACS --use --skip
6 | - cask
7 | env:
8 | - EVM_EMACS=emacs-24.4-travis
9 | - EVM_EMACS=emacs-24.5-travis
10 | script:
11 | - emacs --version
12 | - make test
13 |
14 | notifications:
15 | email: false
16 |
--------------------------------------------------------------------------------
/test/java-imports-test.el:
--------------------------------------------------------------------------------
1 | ;;; java-imports-test.el --- tests for java imports
2 |
3 | ;; Copyright (C) 2015 Matthew Lee Hinman
4 |
5 | ;;; Code:
6 |
7 | (require 'ert)
8 | (load-file "java-imports.el")
9 |
10 |
11 | (ert-deftest t-import-for-line ()
12 | (with-temp-buffer
13 | (insert "import java.util.List;")
14 | (should (equal (java-imports-import-for-line)
15 | "java.util.List")))
16 | (with-temp-buffer
17 | (insert " import org.writequit.Thingy; ")
18 | (should (equal (java-imports-import-for-line)
19 | "org.writequit.Thingy"))))
20 |
21 |
22 | (ert-deftest t-go-to-imports-start ()
23 | ;; both package and imports present? Goto to the first import line beginning
24 | (with-temp-buffer
25 | (insert "package mypackage;\n")
26 | (insert "\n")
27 | (insert "import java.util.List;\n")
28 | (insert "import java.util.ArrayList;\n")
29 | (insert "\n\n")
30 | (java-imports-go-to-imports-start)
31 | (should (equal (line-number-at-pos) 3)))
32 |
33 | ;; no package and imports present? First import line
34 | (with-temp-buffer
35 | (insert "\n")
36 | (insert "\n")
37 | (insert "\n")
38 | (insert "import java.util.List;\n")
39 | (insert "import java.util.ArrayList;\n")
40 | (insert "\n\n")
41 | (java-imports-go-to-imports-start)
42 | (should (equal (line-number-at-pos) 4)))
43 |
44 | ;; package present, no imports? Add a correct import place, keeping the empty
45 | ;; lines
46 | (with-temp-buffer
47 | (insert "\n")
48 | (insert "package mypackage;\n")
49 | (insert "\n")
50 | (insert "\n")
51 | (insert "class A {}\n")
52 | (java-imports-go-to-imports-start)
53 | (should (equal (line-number-at-pos) 4))
54 | (should (equal (count-lines (point-min) (point-max)) 7)))
55 |
56 | ;; no package, no imports? Stay in the beginning, add lines required
57 | (with-temp-buffer
58 | (insert "\n")
59 | (insert "\n")
60 | (insert "\n")
61 | (insert "class A {}\n")
62 | (java-imports-go-to-imports-start)
63 | (should (equal (line-number-at-pos) 1))
64 | (should (equal (count-lines (point-min) (point-max)) 5))))
65 |
66 | (ert-deftest t-add-imports ()
67 | (with-temp-buffer
68 | (setq-local java-imports-find-block-function
69 | #'java-imports-find-place-after-last-import)
70 | (insert "package mypackage;\n\n")
71 | (insert "import java.util.List;\n\n\n")
72 | (java-imports-add-import-with-package "ArrayList" "java.util")
73 | (should
74 | (equal
75 | (buffer-string)
76 | (concat
77 | "package mypackage;\n\n"
78 | "import java.util.List;\n"
79 | "import java.util.ArrayList;\n\n\n"))))
80 |
81 | ;; Test for annotation importing
82 | (with-temp-buffer
83 | (insert "package mypackage;\n\n")
84 | (insert "import java.util.List;\n\n\n")
85 | (java-imports-add-import-with-package "@MyAnnotation" "org.foo")
86 | (should
87 | (equal
88 | (buffer-string)
89 | (concat
90 | "package mypackage;\n\n"
91 | "import java.util.List;\n"
92 | "import org.foo.MyAnnotation;\n\n\n"))))
93 |
94 | (with-temp-buffer
95 | (setq-local java-imports-find-block-function
96 | #'java-imports-find-place-sorted-block)
97 | (insert "package mypackage;\n\n")
98 | (insert "import java.util.List;\n\n\n")
99 | (java-imports-add-import-with-package "ArrayList" "java.util")
100 | (should
101 | (equal
102 | (buffer-string)
103 | (concat
104 | "package mypackage;\n\n"
105 | "import java.util.ArrayList;\n"
106 | "import java.util.List;\n\n\n")))))
107 |
108 | (ert-deftest t-list-imports ()
109 | (with-temp-buffer
110 | (insert "package mypackage;\n")
111 | (insert "\n")
112 | (insert "import org.Thing;\n")
113 | (insert "\n")
114 | (insert "import java.util.List;\n")
115 | (insert "import java.util.ArrayList;\n")
116 | (insert "\n")
117 | (insert "public class Foo {}")
118 | (should
119 | (equal
120 | (java-imports-list-imports)
121 | '("org.Thing" "java.util.List" "java.util.ArrayList")))))
122 |
123 | (ert-deftest t-pkg-and-class-from-import ()
124 | (should
125 | (equal (java-imports-get-package-and-class "java.util.Map")
126 | '("java.util" "Map")))
127 | (should
128 | (equal (java-imports-get-package-and-class "org.foo.bar.baz.ThingOne")
129 | '("org.foo.bar.baz" "ThingOne"))))
130 |
131 | ;; End:
132 | ;;; java-imports-test.el ends here
133 |
--------------------------------------------------------------------------------
/README.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Emacs Java Imports
2 | #+AUTHOR: Lee Hinman
3 | #+EMAIL: leehinman@fastmail.com
4 | #+LANGUAGE: en
5 | #+PROPERTY: header-args :results code replace :exports both :noweb yes :tangle no
6 | #+HTML_HEAD:
7 | #+EXPORT_SELECT_TAGS: export
8 | #+EXPORT_EXCLUDE_TAGS: noexport
9 | #+OPTIONS: H:4 num:nil toc:t \n:nil @:t ::t |:t ^:{} -:t f:t *:t
10 | #+OPTIONS: skip:nil d:(HIDE) tags:not-in-toc
11 | #+STARTUP: fold nodlcheck lognotestate showall
12 |
13 | * Introduction
14 |
15 | [[https://travis-ci.org/dakrone/emacs-java-imports][file:https://travis-ci.org/dakrone/emacs-java-imports.svg]]
16 | [[http://melpa.org/#/java-imports][file:http://melpa.org/packages/java-imports-badge.svg]]
17 |
18 | I needed a way to import java classes easily in Emacs. I also didn't want a
19 | package that was tied to a particular tool like maven or gradle (especially a
20 | potentially long startup time tool).
21 |
22 | This adds the =import-java-class= function, which will prompt for the class at
23 | point, then the package, then add the required import statement for the class
24 | and cache a "class-name -> package" relationship for any future importing of the
25 | class.
26 |
27 | It does this because I didn't want to drop into Intellij to add all the import
28 | statements for my Java code, I just want to hit a key and have an import
29 | statement added for the class under the point.
30 |
31 | * Installation
32 |
33 | =java-imports= is available in the MELPA repository.
34 |
35 | Do this, if MELPA isn't already in your sources:
36 |
37 | #+BEGIN_SRC emacs-lisp
38 | (require 'package)
39 | (add-to-list 'package-archives
40 | '("MELPA" . "https://melpa.org/packages/" ))
41 | #+END_SRC
42 |
43 | Then run =M-x package-refresh-contents= to load the contents of the new
44 | repository, and =M-x package-install RET java-imports RET= to install
45 | =java-imports=.
46 |
47 | * Usage
48 |
49 | #+BEGIN_SRC emacs-lisp
50 | (require 'java-imports)
51 |
52 | ;; whatever you want to bind it to
53 | (define-key java-mode-map (kbd "M-I") 'java-imports-add-import-dwim)
54 |
55 | ;; See customization below for where to put java imports
56 | (setq java-imports-find-block-function 'java-imports-find-place-sorted-block)
57 | #+END_SRC
58 |
59 | I also recommend having java-imports automatically add any seen imports to the
60 | import cache by adding:
61 |
62 | #+BEGIN_SRC emacs-lisp
63 | (add-hook 'java-mode-hook 'java-imports-scan-file)
64 | #+END_SRC
65 |
66 | ** Functions
67 |
68 | Functions you may want to bind to a key in Java-mode:
69 |
70 | | Function | Use |
71 | |--------------------------------+--------------------------------------------------------|
72 | | =java-imports-add-import-dwim= | Add import for the symbol at point (or ask if none) |
73 | | =java-imports-add-import= | Add import for symbol at point, confirming class first |
74 | | =java-imports-scan-file= | Scan imports in the file, adding them to the cache |
75 |
76 | Other useful functions for writing your own tools:
77 |
78 | | Function |
79 | |----------------------------------------|
80 | | =java-imports-add-import-with-package= |
81 | | =java-imports-list-imports= |
82 |
83 | ** Customization
84 |
85 | *** Saving buffer automatically after adding an import
86 |
87 | =java-imports= will default to saving the buffer after adding an import, but you
88 | can customize =java-imports-save-buffer-after-import-added= to change this.
89 |
90 | *** Caching
91 |
92 | By default packages are cached the first time they're manually entered, if you
93 | want to overwrite what's in the cache you can invoke =java-imports-add-import=
94 | with the prefix key (=C-u=).
95 |
96 | To disable caching, set =java-imports-use-cache= to =nil=.
97 |
98 | *** Import style
99 |
100 | You can customize =java-imports-find-block-function=, either setting it to a
101 | custom function, or one of the included ones:
102 |
103 | - =java-imports-find-place-after-last-import= (default)
104 |
105 | Simply appends the import to the end of the list of imports
106 |
107 | - =java-imports-find-place-sorted-block=
108 |
109 | Places the import alphabetically sorted into the list of imports, so they will
110 | go into:
111 |
112 | #+BEGIN_SRC fundamental
113 |
114 |
115 |
116 |
117 |
118 |
119 | public class Whatever {
120 | ...
121 | }
122 | #+END_SRC
123 |
124 | For example:
125 |
126 | #+BEGIN_SRC java
127 | package org.writequit;
128 |
129 | import org.writequit.Strings;
130 |
131 | import java.util.ArrayList;
132 | import java.util.List;
133 |
134 | class Foo {
135 | public void main() {
136 | String[] s = Strings.EMPTY_ARRAY;
137 | List = new ArrayList<>();
138 | }
139 | }
140 | #+END_SRC
141 |
142 | *** Cache name
143 |
144 | By default java-imports will use "=java-imports=" as the name of the cache of
145 | class->package names, however, if you want to have separate caches per project,
146 | you can customize =java-imports-cache-name= to have a separate String name
147 | (perhaps in a =.dir-locals.el= for per-project imports).
148 |
149 | * Things to do:
150 |
151 | - [X] Avoid importing packages that already have import statements
152 | - [X] Handle annotations correctly
153 | - [ ] Handle =*= imports
154 | - [ ] Inner classes?
155 | - [X] Scan java files for classes and add to the cache
156 | - [X] Add tests
157 | - [X] Hook up to travis-ci
158 |
--------------------------------------------------------------------------------
/java-imports.el:
--------------------------------------------------------------------------------
1 | ;;; java-imports.el --- Code for dealing with Java imports
2 |
3 | ;; Copyright (C) 2015 Matthew Lee Hinman
4 |
5 | ;; Author: Lee Hinman
6 | ;; URL: http://www.github.com/dakrone/emacs-java-imports
7 | ;; Version: 0.1.1
8 | ;; Keywords: java kotlin
9 | ;; Package-Requires: ((emacs "24.4") (s "1.10.0") (pcache "0.5.1"))
10 |
11 | ;; This file is not part of GNU Emacs.
12 |
13 | ;;; Commentary:
14 |
15 | ;; Provides a way to easily add `import' statements for Java classes
16 |
17 | ;;; Usage:
18 |
19 | ;; (require 'java-imports)
20 | ;; (define-key java-mode-map (kbd "M-I") 'java-imports-add-import)
21 |
22 | ;;; License:
23 |
24 | ;; This program is free software; you can redistribute it and/or
25 | ;; modify it under the terms of the GNU General Public License
26 | ;; as published by the Free Software Foundation; either version 3
27 | ;; of the License, or (at your option) any later version.
28 | ;;
29 | ;; This program is distributed in the hope that it will be useful,
30 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
31 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 | ;; GNU General Public License for more details.
33 | ;;
34 | ;; You should have received a copy of the GNU General Public License
35 | ;; along with GNU Emacs; see the file COPYING. If not, write to the
36 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
37 | ;; Boston, MA 02110-1301, USA.
38 |
39 | ;;; Code:
40 |
41 | (require 'cl-lib)
42 | (require 'thingatpt)
43 | (require 'subr-x)
44 | (require 's)
45 | (require 'pcache)
46 |
47 | (defgroup java-imports nil
48 | "Customization for java imports package"
49 | :group 'languages)
50 |
51 | (defcustom java-imports-save-buffer-after-import-added t
52 | "`t' to save the current buffer after inserting an import statement."
53 | :group 'java-imports
54 | :type 'boolean)
55 |
56 | (defcustom java-imports-use-cache t
57 | "Whether packages for classes should be cached"
58 | :group 'java-imports
59 | :type 'boolean)
60 |
61 | (defcustom java-imports-find-block-function 'java-imports-find-place-after-last-import
62 | "A function that should find a proper insertion place within
63 | the block of import declarations."
64 | :group 'java-imports
65 | :type 'function)
66 |
67 | (defcustom java-imports-cache-name "java-imports"
68 | "Name of the cache to be used for the ClassName to Package
69 | mapping cache."
70 | :group 'java-imports
71 | :type 'string)
72 |
73 | (defcustom java-imports-default-packages
74 | '(("List" . "java.util")
75 | ("Collection" . "java.util")
76 | ("Set" . "java.util")
77 | ("Queue" . "java.util")
78 | ("Deque" . "java.util")
79 | ("HashSet" . "java.util")
80 | ("TreeSet" . "java.util")
81 | ("ArrayList" . "java.util")
82 | ("LinkedList" . "java.util")
83 | ("ArrayDeque" . "java.util")
84 | ("PriorityQueue" . "java.util")
85 | ("HashMap" . "java.util")
86 | ("TreeMap" . "java.util")
87 | ("Iterator" . "java.util"))
88 | "An alist mapping class names to probable packages of the
89 | classes."
90 | :group 'java-imports
91 | :type '(alist :key-type string :value-type string))
92 |
93 | (defun java-imports-go-to-imports-start ()
94 | "Go to the point where java import statements start or should
95 | start (if there are none)."
96 | (goto-char (point-min))
97 | ;; package declaration is always in the beginning of a file, so no need to
98 | ;; reset the point after the first search
99 | (let ((package-decl-point (re-search-forward "package .*;" nil t))
100 | (import-decl-point (re-search-forward "import .*;" nil t)))
101 | ;; 1. If there are imports in the file - go to the first one
102 | ;;
103 | ;; 2. No imports, and the package declaration is available - go to the end
104 | ;; of the declaration
105 | ;;
106 | ;; 3. Neither package nor import declarations are present - just go to the
107 | ;; first line
108 | (cond (import-decl-point (goto-char import-decl-point)
109 | (beginning-of-line))
110 | (package-decl-point (goto-char package-decl-point)
111 | (forward-line)
112 | (open-line 2)
113 | (forward-line))
114 | (t (goto-char (point-min))
115 | (open-line 1)))))
116 |
117 | (defun java-imports-get-import (line)
118 | "Return the fully-qualified package for the given import line."
119 | (when line
120 | (cadr (s-match "import \\\(.*?\\\);?$"
121 | (string-trim line)))))
122 |
123 | (defun java-imports-get-package-and-class (import)
124 | "Explode the import and return (pkg . class) for the given import.
125 |
126 | Example 'java.util.Map' returns '(\"java.util\" \"Map\")."
127 | (when import
128 | (cl-subseq (s-match "\\\(.*\\\)\\\.\\\([A-Z].+?\\\)\\\(?:;\\\|$\\\)" import) 1)))
129 |
130 | (defun java-imports-import-for-line ()
131 | "Returns the fully-qualified class name for the import line."
132 | (java-imports-get-import (thing-at-point 'line)))
133 |
134 | (defun java-imports-import-exists-p (full-name)
135 | "Checks if the import already exists"
136 | (save-excursion
137 | (goto-char (point-min))
138 | (re-search-forward (concat "^[ \t]*import[ \t]+" full-name "[ \t]*;") nil t)))
139 |
140 | (defun java-imports-find-place-sorted-block (full-name class-name package)
141 | "Finds the insertion place within a sorted import block.
142 |
143 | Follows a convention where non-JRE imports are separated from JRE
144 | imports by a single line, and both blocks are always present."
145 |
146 | ;; Skip builtin imports if not a JRE import
147 | (and (not (s-starts-with? "java." (java-imports-import-for-line)))
148 | (when (s-starts-with? "java." full-name)
149 | (re-search-forward "^$" nil t)
150 | (forward-line 1)))
151 |
152 | ;; Search for a proper place within a block
153 | (while (and (java-imports-import-for-line)
154 | (string< (java-imports-import-for-line) full-name))
155 | (forward-line 1))
156 | (open-line 1))
157 |
158 | (defun java-imports-find-place-after-last-import (full-name class-name package)
159 | "Finds the insertion place by moving past the last import declaration in the file."
160 | (while (re-search-forward "import[ \t]+.+[ \t]*;" nil t))
161 | (beginning-of-line)
162 | (unless (equal (point-at-bol) (point-at-eol))
163 | (forward-line)
164 | (open-line 1)))
165 |
166 | (defun java-imports-read-package (class-name cached-package)
167 | "Reads a package name for a class, offers default values for
168 | known classes"
169 | (or (car (s-match ".*\\\..*" class-name))
170 | (and (not current-prefix-arg)
171 | cached-package)
172 | (let* ((default-package (cdr (assoc-string class-name java-imports-default-packages)))
173 | (default-prompt (if default-package
174 | (concat "[" default-package "]") ""))
175 | (prompt (concat "Package " default-prompt ": ")))
176 | (read-string prompt nil nil default-package))))
177 |
178 | ;;;###autoload
179 | (defun java-imports-scan-file ()
180 | "Scans a java-mode or kotlin-mode buffer, adding any import class -> package
181 | mappings to the import cache. If called with a prefix arguments
182 | overwrites any existing cache entries for the file."
183 | (interactive)
184 | (when (member major-mode '(java-mode kotlin-mode))
185 | (let* ((cache (pcache-repository java-imports-cache-name)))
186 | (dolist (import (java-imports-list-imports))
187 | (let ((pkg-class-list (java-imports-get-package-and-class import)))
188 | (when pkg-class-list
189 | (let* ((pkg (car pkg-class-list))
190 | (class (intern (cadr pkg-class-list)))
191 | (exists-p (pcache-get cache class)))
192 | (when (or current-prefix-arg (not exists-p))
193 | (message "Adding %s -> %s to the java imports cache" class pkg)
194 | (pcache-put cache class pkg))))))
195 | (pcache-save cache))))
196 |
197 | ;;;###autoload
198 | (defun java-imports-list-imports ()
199 | "Return a list of all fully-qualified packages in the current
200 | Java-mode or Kotlin-mode buffer"
201 | (interactive)
202 | (cl-mapcar
203 | #'java-imports-get-import
204 | (cl-remove-if-not (lambda (str) (s-matches? "import[ \t]+.+?[ \t]*;?" str))
205 | (s-lines (buffer-string)))))
206 |
207 | ;;;###autoload
208 | (defun java-imports-add-import-with-package (class-name package)
209 | "Add an import for the class for the name and package. Uses no caching."
210 | (interactive (list (read-string "Class name: " (thing-at-point 'symbol))
211 | (read-string "Package name: " (thing-at-point 'symbol))))
212 | (save-excursion
213 | (let ((class-name (s-chop-prefix "@" class-name))
214 | (full-name (or (car (s-match ".*\\\..*" class-name))
215 | (concat package "." class-name))))
216 | (when (java-imports-import-exists-p full-name)
217 | (user-error "Import for '%s' already exists" full-name))
218 |
219 | ;; Goto the start of the imports block
220 | (java-imports-go-to-imports-start)
221 |
222 | ;; Search for a proper insertion place within the block of imports
223 | (funcall java-imports-find-block-function full-name class-name package)
224 |
225 | ;; The insertion itself. Note that the only thing left to do here is to
226 | ;; insert the import.
227 | (insert "import " (concat package "." class-name) ";")
228 | full-name)))
229 |
230 | ;;;###autoload
231 | (defun java-imports-add-import (class-name)
232 | "Import the Java class for the symbol at point. Uses the symbol
233 | at the point for the class name, ask for a confirmation of the
234 | class name before adding it.
235 |
236 | Checks the import cache to see if a package entry exists for the
237 | given class. If found, adds an import statement for the class. If
238 | not found, prompts for the package and saves it to the cache.
239 |
240 | If called with a prefix argument, overwrites the package for an
241 | already-existing class name."
242 | (interactive (list (read-string "Class name: " (thing-at-point 'symbol))))
243 | (save-excursion
244 | (let* ((class-name (s-chop-prefix "@" class-name))
245 | (key (intern class-name))
246 | (cache (pcache-repository java-imports-cache-name))
247 | ;; Check if we have seen this class's package before
248 | (cached-package (and java-imports-use-cache
249 | (pcache-get cache key)))
250 | ;; If called with a prefix, overwrite the cached value always
251 | (add-to-cache? (or current-prefix-arg
252 | (eq nil cached-package)))
253 | (package (java-imports-read-package class-name cached-package))
254 | (full-name (java-imports-add-import-with-package
255 | class-name package)))
256 |
257 | ;; Optionally save the buffer and cache the full package name
258 | (when java-imports-save-buffer-after-import-added
259 | (save-buffer))
260 | (when add-to-cache?
261 | (message "Adding %s -> %s to java imports cache"
262 | class-name package)
263 | (pcache-put cache key package)
264 | (pcache-save cache))
265 | full-name)))
266 |
267 | ;;;###autoload
268 | (defun java-imports-add-import-dwim ()
269 | "Add an import statement for the class at point. If no class is
270 | found, prompt for the class name. If the class's package already
271 | exists in the cache, add it and return, otherwise prompt for the
272 | package and cache it for future statements."
273 | (interactive)
274 | (let ((class (or (thing-at-point 'symbol)
275 | (read-string "Class name: "))))
276 | (java-imports-add-import (s-chop-prefix "@" class))))
277 |
278 | ;;;###autoload
279 | (defun java-imports-scan-local-jars (&optional local-repo)
280 | "scan the local repository, find local jars and add them to the cache.
281 | if a class is found in multiple packages, any such package may be registered
282 | for that class in the cache.
283 | This is currently a synchronous and potentially slow operation, but
284 | hopefully faster than adding imports manually or using eclipse"
285 | (interactive)
286 | (cl-labels ((shell-command-to-lines
287 | (cmd)
288 | (s-split "\n" (shell-command-to-string cmd) t)))
289 | (let* ((local-repo (or local-repo (expand-file-name
290 | "~/.m2/repository/")))
291 | (jars (shell-command-to-lines
292 | (format "find '%s' -name '*.jar'"
293 | local-repo)))
294 | (cache (pcache-repository java-imports-cache-name)))
295 | (dolist (jar jars)
296 | (dolist (line (shell-command-to-lines (concat "jar -tf " jar)))
297 | (when (string-match "\\(.*\\)/\\(.*\\)[.]class" line)
298 | (let ((class (intern (match-string 2 line)))
299 | (package-name
300 | (replace-regexp-in-string "/" "." (match-string 1 line))))
301 | (if (pcache-get cache class)
302 | (message "skipping %s -> %s" class package-name)
303 | (progn (message "adding %s -> %s..." class package-name)
304 | (pcache-put cache class package-name))))))))))
305 |
306 | (provide 'java-imports)
307 |
308 | ;;; java-imports.el ends here
309 |
--------------------------------------------------------------------------------