From 4197630a21aa9fd54580875228a5714f4e60b012 Mon Sep 17 00:00:00 2001 From: expez Date: Fri, 1 May 2015 19:55:20 +0200 Subject: [PATCH] Add ns-path op This op returns the file path to the file containing some ns on classpath. This op is meant to be the basis for cider-find-ns --- README.md | 2 +- src/cider/nrepl/middleware/ns.clj | 61 +++++++++++++++++++-- test/clj/cider/nrepl/middleware/ns_test.clj | 5 ++ 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f775aed65..cdc26b37a 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ Middleware | Op(s) | Description `wrap-info` | `info/eldoc` | File/line, arglists, docstrings and other metadata for vars. `wrap-inspect` |`inspect-(start/refresh/pop/push/reset)` | Inspect a Clojure expression. `wrap-macroexpand`| `macroexpand/macroexpand-1/macroexpand-all` | Macroexpand a Clojure form. -`wrap-ns` | `ns-list/ns-vars` | Namespace browsing. +`wrap-ns` | `ns-list/ns-vars/ns-to-path` | Namespace browsing. `wrap-pprint` | | Adds pretty-printing support to code evaluation. It also installs a dummy `pprint-middleware` op. Thus `wrap-pprint` is discoverable through the `describe` op `wrap-refresh` | `refresh/refresh-all` | Code reloading. `wrap-resource` | `resource` | Return resource path. diff --git a/src/cider/nrepl/middleware/ns.clj b/src/cider/nrepl/middleware/ns.clj index 042265c92..056110a2f 100644 --- a/src/cider/nrepl/middleware/ns.clj +++ b/src/cider/nrepl/middleware/ns.clj @@ -1,9 +1,16 @@ (ns cider.nrepl.middleware.ns - (:require [clojure.tools.nrepl.transport :as transport] - [clojure.tools.nrepl.middleware :refer [set-descriptor!]] - [clojure.tools.nrepl.misc :refer [response-for]] - [cider.nrepl.middleware.util.cljs :as cljs] - [cljs-tooling.util.analysis :as cljs-analysis])) + (:require [cider.nrepl.middleware.util.cljs :as cljs] + [cljs-tooling.util.analysis :as cljs-analysis] + [clojure.java.classpath :as cp] + [clojure.java.io :as io] + [clojure.tools.namespace + [file :refer [read-file-ns-decl]] + [find :refer [clojure-sources-in-jar find-clojure-sources-in-dir]]] + [clojure.tools.nrepl + [middleware :refer [set-descriptor!]] + [misc :refer [response-for]] + [transport :as transport]]) + (:import java.util.jar.JarFile)) (defn ns-list-clj [] (->> (all-ns) @@ -51,6 +58,43 @@ (transport/send transport (response-for msg :ns-vars (ns-vars msg))) (transport/send transport (response-for msg :status :done))) +(defn- jar-file? + "Returns true if file is a normal file with a .jar or .JAR extension." + [f] + (let [file (io/file f)] + (and (.isFile file) + (or (.endsWith (.getName file) ".jar") + (.endsWith (.getName file) ".JAR"))))) + +(defn- get-clojure-sources-in-jar + [^JarFile jar] + (let [path-to-jar (.getName jar)] + (map #(str "jar:file:" path-to-jar "!/" %) (clojure-sources-in-jar jar)))) + +(defn- all-clj-files-on-cp [] + (let [dirs-on-cp (filter #(.isDirectory %) (cp/classpath)) + jars-on-cp (map #(JarFile. %) (filter jar-file? (cp/classpath)))] + (concat (->> dirs-on-cp + (mapcat find-clojure-sources-in-dir) + (map #(.getAbsolutePath %))) + (mapcat get-clojure-sources-in-jar jars-on-cp)))) + +(defn ns-path + [{:keys [ns]}] + (let [ns (symbol ns)] + (loop [paths (all-clj-files-on-cp)] + (when (seq paths) + (let [file-ns (second (read-file-ns-decl (first paths)))] + (if (= file-ns ns) + (first paths) + (recur (rest paths)))))))) + +(defn- ns-path-reply + [{:keys [transport] :as msg}] + (when-let [path (ns-path msg)] + (transport/send transport (response-for msg :path (ns-path msg)))) + (transport/send transport (response-for msg :status :done))) + (defn wrap-ns "Middleware that provides ns listing/browsing functionality." [handler] @@ -58,6 +102,7 @@ (case op "ns-list" (ns-list-reply msg) "ns-vars" (ns-vars-reply msg) + "ns-path" (ns-path-reply msg) (handler msg)))) (set-descriptor! @@ -70,4 +115,8 @@ "ns-vars" {:doc "Returns a sorted list of all vars in a namespace." :requires {"ns" "The namespace to browse"} - :returns {"status" "done"}}}})) + :returns {"status" "done"}} + "ns-path" + {:doc "Returns the path to the file containing ns" + :requires {"ns" "The namespace to find"} + :return {"status" "done" "path" "The path to the file containing ns"}}}})) diff --git a/test/clj/cider/nrepl/middleware/ns_test.clj b/test/clj/cider/nrepl/middleware/ns_test.clj index 7e36a8998..608173f63 100644 --- a/test/clj/cider/nrepl/middleware/ns_test.clj +++ b/test/clj/cider/nrepl/middleware/ns_test.clj @@ -25,3 +25,8 @@ :ns "clojure.walk"}))] (is (sequential? ns-vars)) (is (every? string? ns-vars)))) + +(deftest ns-path-integration-test + (let [path (:path (session/message {:op "ns-path" + :ns "cider.nrepl.middleware.ns"}))] + (is (.endsWith path "cider/nrepl/middleware/ns.clj"))))