Skip to content

Commit

Permalink
namespaces-on-classpath yields also cljc candidates
Browse files Browse the repository at this point in the history
...and introduce namespaces&files-on-classpath that yields collection of
maps with e.g. :file.

Fixes #90
  • Loading branch information
eval committed Jun 17, 2023
1 parent 0539ce7 commit e5d31fa
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 22 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
- Complete fully-qualified classnames by their shortname prefix anywhere in the
file (previously worked only in the `:import` section of the `ns` form).
- Fix ' and #' being swallowed when completing vars prefixed by them.
- [#91](https://github.com/alexander-yakushev/compliment/pull/91): `compliment.utils/namespaces-on-classpath` (now deprecated) takes cljc files into account.
Add replacement `compliment.utils/namespaces&files-on-classpath` that yields a collection of maps containing the filename.

### 0.3.14 (2022-07-11)

Expand Down
11 changes: 6 additions & 5 deletions src/compliment/sources/namespaces_and_classes.clj
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,12 @@
(get-all-full-names prefix))
;; If prefix doesn't contain a period, using fuziness produces too many
;; irrelevant candidates.
(for [^String ns-str (utils/namespaces-on-classpath)
:when (if has-dot
(nscl-matches? prefix ns-str)
(.startsWith ns-str prefix))]
{:candidate ns-str, :type :namespace})
(for [{^String ns-str :ns-str, ^String file :file} (utils/namespaces&files-on-classpath)
:when (and (re-find #"\.cljc?$" file)
(if has-dot
(nscl-matches? prefix ns-str)
(.startsWith ns-str prefix)))]
{:candidate ns-str, :type :namespace, :file file})
;; Fuzziness is too slow for all classes, so only startsWith. Also, if no
;; period in prefix, only complete root package names to maintain good
;; performance and not produce too many candidates.
Expand Down
33 changes: 19 additions & 14 deletions src/compliment/utils.clj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
Note that should always have the same value, regardless of OS."
"/")

(defn- ensure-no-leading-slash [file]
(if (.startsWith file File/separator)
(.substring file 1) file))

(defn fuzzy-matches?
"Tests if symbol matches the prefix when symbol is split into parts on
separator."
Expand Down Expand Up @@ -181,25 +185,27 @@ Note that should always have the same value, regardless of OS."
(->> (for [^String file (all-files-on-classpath classpath)
:when (and (.endsWith file ".class") (not (.contains file "__"))
(not (.contains file "$")))]
(.. (if (.startsWith file File/separator)
(.substring file 1) file)
(.. (ensure-no-leading-slash file)
(replace ".class" "")
;; Address the issue #79 , on Windows, for prefix such
;; as "java.util.", the list of candidates was empty.
(replace resource-separator ".")))
(group-by #(subs % 0 (max (.indexOf ^String % ".") 0)))))))

(defn namespaces-on-classpath
"Returns the list of all Clojure namespaces obtained by classpath scanning."
(defn namespaces&files-on-classpath
"Returns a collection of maps (e.g. `{:ns-str \"some.ns\", :file \"some/ns.cljs\"}`) of all clj/cljc/cljs namespaces obtained by classpath scanning."
[]
(let [classpath (classpath)]
(cache-last-result ::namespaces-on-classpath classpath
(set (for [^String file (all-files-on-classpath classpath)
:when (and (.endsWith file ".clj")
(not (.startsWith file "META-INF")))
:let [[_ ^String nsname] (re-matches #"[^\w]?(.+)\.clj" file)]
:when nsname]
(.. nsname (replace resource-separator ".") (replace "_" "-")))))))
(for [file (all-files-on-classpath classpath)
:let [file (ensure-no-leading-slash file)
[_ ^String nsname] (re-matches #"[^\w]?(.+)\.clj[sc]?$" file)]
:when nsname]
(let [ns-str (.. nsname (replace resource-separator ".") (replace "_" "-"))]
{:ns-str ns-str, :file file})))))

(defn ^:deprecated namespaces-on-classpath []
(transduce (map :ns-str) conj #{} (namespaces&files-on-classpath)))

(defn project-resources
"Returns a list of all non-code files in the current project."
Expand All @@ -208,9 +214,8 @@ Note that should always have the same value, regardless of OS."
(cache-last-result ::project-resources classpath
(for [path classpath
^String file (list-files path false)
:when (not (or (empty? file) (.endsWith file ".clj")
(.endsWith file ".jar") (.endsWith file ".class")))]
:when (not (or (empty? file)
(re-find #"\.(clj[cs]?|jar|class)$" file)))]
;; resource pathes always use "/" regardless of platform
(.. (if (.startsWith file File/separator)
(.substring file 1) file)
(.. (ensure-no-leading-slash file)
(replace File/separator resource-separator))))))
4 changes: 2 additions & 2 deletions test/compliment/sources/t_namespaces_and_classes.clj
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
=> (just ["src"])

(src/candidates "clojure.java." (-ns) nil)
=> (contains #{{:candidate "clojure.java.browse", :type :namespace}
{:candidate "clojure.java.shell", :type :namespace}} :gaps-ok)
=> (contains #{{:candidate "clojure.java.browse", :type :namespace, :file "clojure/java/browse.clj"}
{:candidate "clojure.java.shell", :type :namespace, :file "clojure/java/shell.clj"}} :gaps-ok)

(src/candidates "java.io.Stri" (-ns) nil)
=> (contains #{{:candidate "java.io.StringReader", :type :class}
Expand Down
2 changes: 1 addition & 1 deletion test/compliment/t_core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@

;; Test for not required namespaces
(core/completions "cl.test.ta" {}) =>
(just [{:type :namespace, :candidate "clojure.test.tap"}])
(just [{:type :namespace, :candidate "clojure.test.tap" :file "clojure/test/tap.clj"}])

;; Test for aliases
(core/completions "cor" {:ns 'compliment.t-core})
Expand Down
6 changes: 6 additions & 0 deletions test/compliment/t_utils.clj
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,9 @@
(is (contains? all-classes "java.lang.Thread"))
(is (contains? all-classes "java.io.File"))
(is (contains? all-classes "java.nio.channels.FileChannel"))))

(deftest namespaces&files-on-classpath-test
(is (contains? (namespaces&files-on-classpath)
{:ns-str "compliment.t-utils" :file "compliment/t_utils.clj"}))
(is (contains? (namespaces&files-on-classpath)
{:ns-str "dummy" :file "dummy.cljs"})))
2 changes: 2 additions & 0 deletions test/dummy.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
;; To test compliment.utils/namespaces&files-on-classpath
(ns dummy)

0 comments on commit e5d31fa

Please sign in to comment.