diff --git a/CHANGELOG.md b/CHANGELOG.md index 969a25c..8636db0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/src/compliment/sources/namespaces_and_classes.clj b/src/compliment/sources/namespaces_and_classes.clj index 40ab636..24a5b78 100644 --- a/src/compliment/sources/namespaces_and_classes.clj +++ b/src/compliment/sources/namespaces_and_classes.clj @@ -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 [{:keys [^String ns-str, ^String 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. diff --git a/src/compliment/utils.clj b/src/compliment/utils.clj index 2376155..2e66cb8 100644 --- a/src/compliment/utils.clj +++ b/src/compliment/utils.clj @@ -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." @@ -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." @@ -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)))))) diff --git a/test/compliment/sources/t_namespaces_and_classes.clj b/test/compliment/sources/t_namespaces_and_classes.clj index 67d38b6..2d4aec2 100644 --- a/test/compliment/sources/t_namespaces_and_classes.clj +++ b/test/compliment/sources/t_namespaces_and_classes.clj @@ -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} diff --git a/test/compliment/t_core.clj b/test/compliment/t_core.clj index ea62665..6789fd3 100644 --- a/test/compliment/t_core.clj +++ b/test/compliment/t_core.clj @@ -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}) diff --git a/test/compliment/t_utils.clj b/test/compliment/t_utils.clj index 863e028..319466d 100644 --- a/test/compliment/t_utils.clj +++ b/test/compliment/t_utils.clj @@ -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? (set (namespaces&files-on-classpath)) + {:ns-str "compliment.t-utils" :file "compliment/t_utils.clj"})) + (is (contains? (set (namespaces&files-on-classpath)) + {:ns-str "dummy" :file "dummy.cljs"}))) diff --git a/test/dummy.cljs b/test/dummy.cljs new file mode 100644 index 0000000..ee91602 --- /dev/null +++ b/test/dummy.cljs @@ -0,0 +1,2 @@ +;; To test compliment.utils/namespaces&files-on-classpath +(ns dummy)