diff --git a/src/babashka/nrepl/impl/server.clj b/src/babashka/nrepl/impl/server.clj index 4466806..b97af12 100644 --- a/src/babashka/nrepl/impl/server.clj +++ b/src/babashka/nrepl/impl/server.clj @@ -119,9 +119,10 @@ completions (keep (fn [entry] (match alias->ns ns->alias query entry)) svs) - completions (mapv (fn [[namespace name]] - {"candidate" (str name) "ns" (str namespace) #_"type" #_"function"}) - completions)] + completions (->> (map (fn [[namespace name]] + {"candidate" (str name) "ns" (str namespace) #_"type" #_"function"}) + completions) + set)] (when debug (prn "completions" completions)) (utils/send o (utils/response-for msg {"completions" completions "status" #{"done"}}) opts)) @@ -141,34 +142,50 @@ (utils/send os (utils/response-for msg {"sessions" sessions "status" #{"done"}}) opts))) -(defn eldoc [ctx msg os {:keys [debug] :as opts}] +(defn lookup [ctx msg os mapping-type {:keys [debug] :as opts}] (let [ns-str (:ns msg) - sym-str (:sym msg) + sym-str (or (:sym msg) (:symbol msg)) + sym-str-ns-striped (last (str/split sym-str #"\/")) sci-ns (when ns-str (sci-utils/namespace-object (:env ctx) (symbol ns-str) nil false))] (try (sci/binding [vars/current-ns (or sci-ns @vars/current-ns)] (let [m (sci/eval-string* ctx (format " -(when-let [v (ns-resolve '%s '%s)] - (let [m (meta v)] - (assoc m :arglists (:arglists m) - :doc (:doc m) - :name (:name m) - :ns (some-> m :ns ns-name) - :val @v)))" ns-str sym-str)) - reply {"ns" (:ns m) - "name" (:name m) - "eldoc" (mapv #(mapv str %) (:arglists m)) - "type" (cond - (ifn? (:val m)) "function" - :else "variable") - "docstring" (:doc m) - "status" #{"done"}}] +(let [sym-ns-str '%s + sym-str '%s + ns-striped-sym-str '%s] + (when-let [v (or (ns-resolve sym-ns-str sym-str) + (ns-resolve sym-ns-str ns-striped-sym-str))] + (let [m (meta v)] + (assoc m :arglists (:arglists m) + :doc (:doc m) + :name (:name m) + :ns (some-> m :ns ns-name) + :val @v))))" ns-str sym-str sym-str-ns-striped)) + arglists-vec (mapv #(mapv str %) (:arglists m)) + reply (->> (case mapping-type + :eldoc {"ns" (:ns m) + "name" (:name m) + "eldoc" arglists-vec + "docstring" (:doc m) + "type" (cond + (ifn? (:val m)) "function" + :else "variable") + "status" #{"done"}} + :lookup {"ns" (:ns m) + "name" (:name m) + "arglists-str" (str arglists-vec) + "status" #{"done"} + "doc" (:doc m)}) + (remove #(nil? (second %))) + (into {}))] (utils/send os (utils/response-for msg reply) opts))) (catch Throwable e (when debug (println e)) - (utils/send os (utils/response-for msg {"status" #{"done" "no-eldoc"}}) opts))))) + (let [status (remove nil? #{"done" + (when (= mapping-type :eldoc) "no-eldoc")})] + (utils/send os (utils/response-for msg {"status" status}) opts)))))) (defn read-msg [msg] (-> (zipmap (map keyword (keys msg)) @@ -207,6 +224,9 @@ :complete (do (complete ctx os msg opts) (recur ctx is os id opts)) + (:lookup :info) (do + (lookup ctx msg os :lookup opts) + (recur ctx is os id opts)) :describe (do (utils/send os (utils/response-for msg @@ -214,7 +234,7 @@ {"status" #{"done"} "ops" (zipmap #{"clone" "close" "eval" "load-file" "complete" "describe" "ls-sessions" - "eldoc"} + "eldoc" "info" "lookup"} (repeat {})) "versions" {"babashka.nrepl" babashka-nrepl-version}} (:describe opts))) opts) @@ -222,7 +242,7 @@ :ls-sessions (do (ls-sessions ctx msg os opts) (recur ctx is os id opts)) :eldoc (do - (eldoc ctx msg os opts) + (lookup ctx msg os :eldoc opts) (recur ctx is os id opts)) ;; fallback (do (when debug diff --git a/src/babashka/nrepl/impl/utils.clj b/src/babashka/nrepl/impl/utils.clj index 6b525e1..d963514 100644 --- a/src/babashka/nrepl/impl/utils.clj +++ b/src/babashka/nrepl/impl/utils.clj @@ -2,7 +2,8 @@ {:author "Michiel Borkent" :no-doc true} (:refer-clojure :exclude [send]) - (:require [bencode.core :refer [write-bencode]]) + (:require [bencode.core :refer [write-bencode]] + [clojure.string :as str]) (:import [java.io Writer PrintWriter StringWriter OutputStream BufferedWriter])) (set! *warn-on-reflection* true) diff --git a/test/babashka/nrepl/server_test.clj b/test/babashka/nrepl/server_test.clj index d4cd165..3419915 100644 --- a/test/babashka/nrepl/server_test.clj +++ b/test/babashka/nrepl/server_test.clj @@ -336,10 +336,43 @@ (is (= "variable" type)))) (testing "eldoc of invalid characters" (bencode/write-bencode os {"op" "eldoc" "ns" "user" - "sym" " " + "sym" "\r" "session" session "id" (new-id!)}) (let [{:keys [status]} (read-reply in session @id)] (is (contains? (set status) "no-eldoc"))))) + (testing "lookup" + (testing "lookup of inc" + (bencode/write-bencode os {"op" "lookup" "ns" "user" + "symbol" "inc" + "session" session "id" (new-id!)}) + (let [{:keys [doc arglists-str]} (read-reply in session @id)] + (is (str/includes? doc "Returns a number one greater than num")) + (is (= "[[\"x\"]]" arglists-str)))) + (testing "lookup of last-index-of" + (bencode/write-bencode os {"op" "lookup" "ns" "user" + "symbol" "clojure.string/last-index-of" + "session" session "id" (new-id!)}) + (let [{:keys [doc arglists-str]} (read-reply in session @id)] + (is (str/includes? doc "Return last index of value (string or char) in s")) + (is (= "[[\"s\" \"value\"] [\"s\" \"value\" \"from-index\"]]" arglists-str)))) + (testing "lookup of s/lower-case (from core ns, aliased as s/, core passed as ns)" + (bencode/write-bencode os {"op" "eval" "code" "(ns core) + (require '[clojure.string :as s])" "session" session "id" (new-id!)}) + (bencode/write-bencode os {"op" "lookup" "ns" "core" + "symbol" "s/lower-case" + "session" session "id" (new-id!)}) + (let [{:keys [doc arglists-str]} (read-reply in session @id)] + (is (str/includes? doc "Converts string to all lower-case")) + (is (= "[[\"s\"]]" arglists-str)))) + (testing "lookup of s/lower-case (from core ns, aliased as s/, clojure.string passed as ns)" + (bencode/write-bencode os {"op" "eval" "code" "(ns core) + (require '[clojure.string :as s])" "session" session "id" (new-id!)}) + (bencode/write-bencode os {"op" "lookup" "ns" "clojure.string" + "symbol" "s/lower-case" + "session" session "id" (new-id!)}) + (let [{:keys [doc arglists-str]} (read-reply in session @id)] + (is (str/includes? doc "Converts string to all lower-case")) + (is (= "[[\"s\"]]" arglists-str))))) (testing "dynamic var can be set! if provided in :dynamic-vars option" (bencode/write-bencode os {"op" "eval" "code" "(set! *warn-on-reflection* true)" "session" session "id" (new-id!)}) @@ -373,3 +406,4 @@ (comment ) +