From 3afd028293ec14ce761c5a9ad835e5d51a0ce0f9 Mon Sep 17 00:00:00 2001 From: Robert Krahn Date: Sun, 11 Apr 2021 18:46:23 +0200 Subject: [PATCH 1/5] [test] fix tests (nashorn is no more) --- Makefile | 2 -- deps.edn | 2 +- pom.xml | 7 ++++- src/dev/suitable/nrepl.clj | 2 +- src/dev/suitable/repl.clj | 2 +- src/test/suitable/complete_for_nrepl_test.clj | 30 +++---------------- 6 files changed, 13 insertions(+), 32 deletions(-) diff --git a/Makefile b/Makefile index 08ba224..8755581 100644 --- a/Makefile +++ b/Makefile @@ -9,9 +9,7 @@ clean: .cpcache \ target \ out \ - .cljs_nashorn_repl \ .cljs_node_repl \ - nashorn_code_cache \ .rebel_readline_history test: ${SRC_FILES} diff --git a/deps.edn b/deps.edn index 81530b9..f189ed9 100644 --- a/deps.edn +++ b/deps.edn @@ -1,5 +1,5 @@ {:deps {org.clojure/clojurescript {:mvn/version "[1.9.908,)"} - compliment {:mvn/version "0.3.10"}} + compliment/compliment {:mvn/version "0.3.10"}} :paths ["src/main"] diff --git a/pom.xml b/pom.xml index 1017fd3..e7692c9 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,12 @@ org.clojure clojurescript - [1.9.908,) + 1.10.844 + + + compliment + compliment + 0.3.10 diff --git a/src/dev/suitable/nrepl.clj b/src/dev/suitable/nrepl.clj index 5fb636d..b97960a 100644 --- a/src/dev/suitable/nrepl.clj +++ b/src/dev/suitable/nrepl.clj @@ -13,7 +13,7 @@ ;; a la https://github.com/nrepl/piggieback/issues/91 ;; 1. start nrepl server with piggieback ;; 2. get session -;; 3. send cljs start form (e.g. nashorn or figwheel) +;; 3. send cljs start form (e.g. figwheel) ;; 4. ...profit! ;; 1. start nrepl server with piggieback diff --git a/src/dev/suitable/repl.clj b/src/dev/suitable/repl.clj index 042c979..913be42 100644 --- a/src/dev/suitable/repl.clj +++ b/src/dev/suitable/repl.clj @@ -79,7 +79,7 @@ ;; a la https://github.com/nrepl/piggieback/issues/91 ;; 1. start nrepl server with piggieback ;; 2. get session -;; 3. send cljs start form (e.g. nashorn or figwheel) +;; 3. send cljs start form (e.g. figwheel) ;; 4. ...profit! ;; 1. start nrepl server with piggieback diff --git a/src/test/suitable/complete_for_nrepl_test.clj b/src/test/suitable/complete_for_nrepl_test.clj index 332c0ef..4c5dbae 100644 --- a/src/test/suitable/complete_for_nrepl_test.clj +++ b/src/test/suitable/complete_for_nrepl_test.clj @@ -43,8 +43,6 @@ (.close *server*)) (comment - - (start (cljs.repl.nashorn/repl-env :debug false)) (start (cljs.repl.node/repl-env)) (stop) ) @@ -58,16 +56,6 @@ ;; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -(deftest sanity-test-nashorn - (require 'cljs.repl.nashorn) - (with-repl-env (cljs.repl.nashorn/repl-env :debug false) - (testing "cljs repl is active" - (let [response (message {:op :eval - :code (nrepl/code (js/Object.))})] - (is (= "cljs.user" (:ns response))) - (is (= ["#js {}"] (:value response))) - (is (= #{"done"} (:status response))))))) - (deftest sanity-test-node (require 'cljs.repl.node) (with-repl-env (cljs.repl.node/repl-env) @@ -75,11 +63,12 @@ (let [response (message {:op :eval :code (nrepl/code (js/Object.))})] (is (= "cljs.user" (:ns response))) - (is (= ["#js {}"] (:value response))) + (is (= ["#js{}"] (:value response))) (is (= #{"done"} (:status response))))))) -(deftest suitable-nashorn - (with-repl-env (cljs.repl.nashorn/repl-env :debug false) +(deftest suitable-node + (require 'cljs.repl.node) + (with-repl-env (cljs.repl.node/repl-env) (testing "js global completion" (let [response (message {:op "complete" :ns "cljs.user" @@ -99,16 +88,5 @@ candidates (:completions response)] (is (= [{:ns "js/Object", :candidate ".keys" :type "function"}] candidates)))))) -(deftest suitable-node - (require 'cljs.repl.node) - (with-repl-env (cljs.repl.node/repl-env) - (testing "js global completion" - (let [response (message {:op "complete" - :ns "cljs.user" - :symbol "js/Ob"}) - candidates (:completions response)] - (is (= [{:candidate "js/Object", :ns "js", :type "function"}] candidates)))))) - - (comment (run-tests)) From d83e300db33c3989a5637dedc97ffeec2a3ae528 Mon Sep 17 00:00:00 2001 From: Robert Krahn Date: Mon, 12 Apr 2021 01:04:30 +0200 Subject: [PATCH 2/5] [doc] minor readme changes --- README.md | 74 +++++++++++++++---------------------------------------- 1 file changed, 20 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index b21457d..f88bad7 100644 --- a/README.md +++ b/README.md @@ -6,22 +6,16 @@ It provides two complementary completion sources: -- It integrates with the CLJS analyzer and using the compilation state for -"static" symbol completion. This functionality was briefly part of -[compliment](https://github.com/alexander-yakushev/compliment), and before this - [Orchard](https://github.com/clojure-emacs/orchard) and [cljs-tooling](https://github.com/clojure-emacs/cljs-tooling). -- It can use a CLJS REPL session to query and inspect JavaScript runtime state, -allowing code completion for JavaScript objects and interfaces. +- It integrates with the CLJS analyzer and using the compilation state for "static" symbol completion. This functionality was briefly part of [compliment](https://github.com/alexander-yakushev/compliment), and before this - [Orchard](https://github.com/clojure-emacs/orchard) and [cljs-tooling](https://github.com/clojure-emacs/cljs-tooling). +- It can use a CLJS REPL session to query and inspect JavaScript runtime state, allowing code completion for JavaScript objects and interfaces. ## Static code completion -The static code completion is based on analysis of the ClojureScript compiler state. -This approach was pioneered by `cljs-tooling` and the completion logic was subsequently moved to `orchard`, `compliment` and finally here. +The static code completion is based on analysis of the ClojureScript compiler state. This approach was pioneered by `cljs-tooling` and the completion logic was subsequently moved to `orchard`, `compliment` and finally here. Why here? Because it's very convenient from the user perspective to have a single library providing both types of completion. -This type of completion provides a [compliment custom -source](https://github.com/alexander-yakushev/compliment/wiki/Custom-sources) -for ClojureScript, so it's easy to plug with the most popular completion framework out there. +This type of completion provides a [compliment custom source](https://github.com/alexander-yakushev/compliment/wiki/Custom-sources) for ClojureScript, so it's easy to plug with the most popular completion framework out there. ``` clojure (ns suitable.demo @@ -39,35 +33,21 @@ for ClojureScript, so it's easy to plug with the most popular completion framewo (complete/completions prefix (merge completion-opts {:sources cljs-sources}))) ``` -Note that you'll need to establish a binding to `suitable-sources/*compiler-env*` -for the completion to work. +Note that you'll need to establish a binding to `suitable-sources/*compiler-env*` for the completion to work. ## Dynamic code completion for CLJS repls -The dynamic code completion features allow for exploratory development by -inspecting the runtime. For example you work with DOM objects but can't remember -how to query for child elements. Type `(.| js/document)` (with `|` marking the -postion of your cursor) and press TAB. Methods and properties of `js/document` -will appear — including `querySelector` and `querySelectorAll`. +The dynamic code completion features allow for exploratory development by inspecting the runtime. For example you work with DOM objects but can't remember how to query for child elements. Type `(.| js/document)` (with `|` marking the postion of your cursor) and press TAB. Methods and properties of `js/document` will appear — including `querySelector` and `querySelectorAll`. ### Beware the Side-Effects -The dynamic code completion *evaluates* code on completion requests! It does -this by trying to [enumerate the -properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors) -of JavaScript objects, so in the example above it would fetch all properties of -the `js/document` object. This might cause side effects: Even just reading property values of an object can run arbitrary code if that object defines getter functions. +The dynamic code completion *evaluates* code on completion requests! It does this by trying to [enumerate the properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors) of JavaScript objects, so in the example above it would fetch all properties of the `js/document` object. This might cause side effects: Even just reading property values of an object can run arbitrary code if that object defines getter functions. -Moreover, also chains of methods and properties will be evaluated upon -completion requests. So for example, asking for completions for the code / -cursor position `(-> js/some-object (.deleteAllMyFilesAndStartAWar) .|)` will -evaluate the JavaScript code `some-object.deleteAllMyFilesAndStartAWar()`! -This only applies to JavaSript interop code, i.e. JavaScript methods and properties. Pure ClojureScript is not inspected or evaluated. Please be aware of this behavior when using the dynamic code completion features. +Moreover, also chains of methods and properties will be evaluated upon completion requests. So for example, asking for completions for the code / cursor position `(-> js/some-object (.deleteAllMyFilesAndStartAWar) .|)` will evaluate the JavaScript code `some-object.deleteAllMyFilesAndStartAWar()`! This only applies to JavaSript interop code, i.e. JavaScript methods and properties. Pure ClojureScript is not inspected or evaluated. Please be aware of this behavior when using the dynamic code completion features. ### Dynamic completion Demo -The animation shows how various properties and methods of the native DOM can be -accessed (Tab is used to show completions for the expression at the cursor): +The animation shows how various properties and methods of the native DOM can be accessed (Tab is used to show completions for the expression at the cursor): ![](doc/2019_07_22_suitable-figwheel.gif) @@ -75,9 +55,7 @@ accessed (Tab is used to show completions for the expression at the cursor): ### figwheel.main with rebel-readline -Please note that you need to use -[rebel-readline](https://github.com/bhauman/rebel-readline) with figwheel for -that to work. Plain repls have no completion feature. +Please note that you need to use [rebel-readline](https://github.com/bhauman/rebel-readline) with figwheel for that to work. Plain repls have no completion feature. #### Tools CLI @@ -90,8 +68,9 @@ Then modify `deps.edn` and `dev.cljs.edn`, you should end up with the files look ```clojure {:deps {com.bhauman/figwheel-main {:mvn/version "RELEASE"} com.bhauman/rebel-readline-cljs {:mvn/version "RELEASE"}} - :paths ["src" "resources" "target"] - :aliases {:suitable {:extra-deps {org.rksm/suitable {:mvn/version "RELEASE"}} + :paths ["src" "target" "resources"] + :aliases {:build-dev {:main-opts ["-m" "figwheel.main" "-b" "dev" "-r"]} + :suitable {:extra-deps {org.rksm/suitable {:mvn/version "RELEASE"}} :main-opts ["-e" "(require,'suitable.hijack-rebel-readline-complete)" "-m" "figwheel.main" "--build" "dev" "--repl"]}}} @@ -110,7 +89,7 @@ Then modify `deps.edn` and `dev.cljs.edn`, you should end up with the files look (ns example.core) ``` -You can now start a figwheel repl via `clj -A:suitable` and use TAB to complete. +You can now start a figwheel repl via `clj -M:suitable` and use TAB to complete. #### leiningen @@ -122,12 +101,9 @@ Then you can start a repl with `lein trampoline run -m suitable.figwheel.main -- ### Emacs CIDER -Suitable is used by CIDER's code completion middleware (as of CIDER 0.22.0), so no extra -installation steps are required. +Suitable is used by CIDER's code completion middleware (as of CIDER 0.22.0), so no extra installation steps are required. -CIDER will always use the static code completion provided by suitable, regardless of the ClojureScript runtime, -but the dynamic completion is **not** currently available with `shadow-cljs`. (See [this ticket](https://github.com/clojure-emacs/clj-suitable/issues/15) for -more details) +CIDER will always use the static code completion provided by suitable, regardless of the ClojureScript runtime, but the dynamic completion is **not** currently available with `shadow-cljs`. (See [this ticket](https://github.com/clojure-emacs/clj-suitable/issues/15) for more details) In case you run into any issues with suitable's dynamic completion in CIDER you can disable it like this: @@ -148,7 +124,7 @@ Suitable is always-on, just as with CIDER. To load suitable into a custom server you can load it using this monstrosity: ```shell -clj -Sdeps '{:deps {cider/cider-nrepl {:mvn/version "0.22.0"} cider/piggieback {:mvn/version"0.4.1"}}}' -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware,cider.piggieback/wrap-cljs-repl]" +clj -Sdeps '{:deps {cider/cider-nrepl {:mvn/version "RELEASE"} cider/piggieback {:mvn/version "RELEASE"}}}' -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware,cider.piggieback/wrap-cljs-repl]" ``` Or from within Clojure: @@ -175,19 +151,9 @@ Please see [issue #2](https://github.com/rksm/clj-suitable/issues/2#issuecomment ## How does it work? suitable uses the same input as the widely used -[compliment](https://github.com/alexander-yakushev/compliment). This means it -gets a prefix string and a context form from the tool it is connected to. For -example you type `(.l| js/console)` with "|" marking where your cursor is. The -input we get would then be: prefix = `.l` and context = `(__prefix__ js/console)`. - -suitable recognizes various ways how CLJS can access properties and methods, -such as `.`, `..`, `doto`, and threading forms. Also direct global access is -supported such as `js/console.log`. suitable will then figure out the expression -that defines the "parent object" that the property / method we want to use -belongs to. For the example above it would be `js/console`. The system then uses -the [EcmaScript property descriptor API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) -to enumerate the object members. Those are converted into completion candidates -and send back to the tooling. +[compliment](https://github.com/alexander-yakushev/compliment). This means it gets a prefix string and a context form from the tool it is connected to. For example you type `(.l| js/console)` with "|" marking where your cursor is. The input we get would then be: prefix = `.l` and context = `(__prefix__ js/console)`. + +suitable recognizes various ways how CLJS can access properties and methods, such as `.`, `..`, `doto`, and threading forms. Also direct global access is supported such as `js/console.log`. suitable will then figure out the expression that defines the "parent object" that the property / method we want to use belongs to. For the example above it would be `js/console`. The system then uses the [EcmaScript property descriptor API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) to enumerate the object members. Those are converted into completion candidates and send back to the tooling. ## License From ba6d937f02de8ccf3907fab1bf9c842ccecd3c07 Mon Sep 17 00:00:00 2001 From: Robert Krahn Date: Mon, 12 Apr 2021 04:50:04 +0200 Subject: [PATCH 3/5] [fix] fix dynamic completion in shadow-cljs runtimes --- .dir-locals.el | 8 ++++---- .gitignore | 1 + Makefile | 2 +- src/main/suitable/complete_for_nrepl.clj | 23 ++++++++--------------- src/main/suitable/js_completions.cljc | 4 ++-- 5 files changed, 16 insertions(+), 22 deletions(-) diff --git a/.dir-locals.el b/.dir-locals.el index c8a34a2..5c49313 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -1,5 +1,5 @@ -((nil . ((cider-default-cljs-repl . figwheel-main) - (cider-preferred-build-tool . clojure-cli) - (cider-clojure-cli-global-options . "-R:dev") - (cider-figwheel-main-default-options . ":fig") +((nil . ((cider-preferred-build-tool . clojure-cli) + ;; (cider-default-cljs-repl . figwheel-main) + ;; (cider-clojure-cli-global-options . "-R:dev") + ;; (cider-figwheel-main-default-options . ":fig") ))) diff --git a/.gitignore b/.gitignore index d769a65..21415e8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ /out/ /.lsp/sqlite*.db /.calva/output-window/*.calva-repl +/.shadow-cljs \ No newline at end of file diff --git a/Makefile b/Makefile index 8755581..4680ff8 100644 --- a/Makefile +++ b/Makefile @@ -40,4 +40,4 @@ fig-repl: clojure -A:fig-repl nrepl: - clojure -A:dev -R:test:nrepl + clojure -A:dev:test:nrepl diff --git a/src/main/suitable/complete_for_nrepl.clj b/src/main/suitable/complete_for_nrepl.clj index 67bb326..8771265 100644 --- a/src/main/suitable/complete_for_nrepl.clj +++ b/src/main/suitable/complete_for_nrepl.clj @@ -207,21 +207,14 @@ (defn- complete-for-shadow-cljs "Shadow-cljs handles evals quite differently from normal cljs so we need some special handling here." - [{:keys [session] :as msg}] - (require 'shadow.cljs.repl) - (require 'shadow.cljs.devtools.server.repl-impl) - (require 'shadow.cljs.devtools.server.worker) - (let [worker (:shadow.cljs.devtools.server.nrepl-impl/worker msg) - runtime-id (:runtime-id msg) - session-id (-> session meta :id str) - build-state ((resolve 'shadow.cljs.devtools.server.repl-impl/worker-build-state) worker) - cljs-eval-fn (fn [ns code] - (let [read-result ((resolve 'shadow.cljs.repl/read-one) build-state (StringReader. code) {}) - eval-result ((resolve 'shadow.cljs.devtools.server.worker/repl-eval) worker session-id runtime-id read-result) - [value error] (->> eval-result :results last :result ((juxt :value :error)))] - {:error error - :value (some->> value edn/read-string)})) - ensure-loaded-fn (fn [_session] (cljs-eval-fn 'cljs.user (str "(require '" munged-js-introspection-ns ")")))] + [msg] + (let [build-id (-> msg :shadow.cljs.devtools.server.nrepl-impl/build-id) + cljs-eval-fn + (fn [ns code] + (let [result ((resolve 'shadow.cljs.devtools.api/cljs-eval) build-id code {:ns (symbol ns)})] + {:error (some->> result :err str) + :value (some->> result :results first edn/read-string)})) + ensure-loaded-fn (fn [_] nil)] (handle-completion-msg! msg cljs-eval-fn ensure-loaded-fn))) (defn complete-for-nrepl diff --git a/src/main/suitable/js_completions.cljc b/src/main/suitable/js_completions.cljc index 53176ba..4cd2bee 100644 --- a/src/main/suitable/js_completions.cljc +++ b/src/main/suitable/js_completions.cljc @@ -173,13 +173,13 @@ library for details on this format. Currently unsupported options that compliment implements are :extra-metadata :sort-order and :plain-candidates." - [cljs-eval-fn symbol {:keys [ns context] :as options-map}] + [cljs-eval-fn symbol {:keys [ns context]}] (when (and symbol (not= "nil" symbol)) (let [{:keys [prefix prepend-to-candidate vars-have-dashes? obj-expr type]} (analyze-symbol-and-context symbol context) global? (#{:global} type)] (when-let [{error :error properties :value} (and obj-expr (js-properties-of-object cljs-eval-fn ns obj-expr prefix))] - (if error + (if (not (empty? error)) (when debug? (binding [*out* *err*] (println "[suitable] error in suitable cljs-completions:" error))) From d52351cce1cdd3c785bbcfaaa96506a4eca48ed2 Mon Sep 17 00:00:00 2001 From: Robert Krahn Date: Sun, 18 Apr 2021 01:29:58 +0200 Subject: [PATCH 4/5] [chore] dev setup for figwheel / shadow --- .dir-locals.el | 5 - Makefile | 12 +- deps.edn | 16 ++- shadow-cljs.edn | 11 ++ src/dev/suitable/nrepl.clj | 90 ------------ src/dev/suitable/nrepl_figwheel.clj | 44 ++++++ src/dev/suitable/nrepl_shadow.clj | 18 +++ .../suitable/compliment/sources/cljs.cljc | 133 +++++++++--------- src/main/suitable/js_completions.cljc | 9 +- .../suitable/compliment/sources/t_cljs.cljc | 89 ++++++------ 10 files changed, 211 insertions(+), 216 deletions(-) delete mode 100644 .dir-locals.el create mode 100644 shadow-cljs.edn create mode 100644 src/dev/suitable/nrepl_figwheel.clj create mode 100644 src/dev/suitable/nrepl_shadow.clj diff --git a/.dir-locals.el b/.dir-locals.el deleted file mode 100644 index 5c49313..0000000 --- a/.dir-locals.el +++ /dev/null @@ -1,5 +0,0 @@ -((nil . ((cider-preferred-build-tool . clojure-cli) - ;; (cider-default-cljs-repl . figwheel-main) - ;; (cider-clojure-cli-global-options . "-R:dev") - ;; (cider-figwheel-main-default-options . ":fig") - ))) diff --git a/Makefile b/Makefile index 4680ff8..3cba78d 100644 --- a/Makefile +++ b/Makefile @@ -36,8 +36,14 @@ deploy: all -Durl=https://clojars.org/repo \ -DrepositoryId=clojars +# starts a figwheel repl with suitable enabled fig-repl: - clojure -A:fig-repl + clojure -M:fig-repl -nrepl: - clojure -A:dev:test:nrepl +# useful for development, see comment in src/dev/suitable/nrepl_figwheel.clj +nrepl-figwheel: + clojure -M:test:dev-figwheel + +# useful for development, see comment in src/dev/suitable/nrepl_.clj +nrepl-shadow: + clojure -M:test:dev-shadow diff --git a/deps.edn b/deps.edn index f189ed9..de78a4e 100644 --- a/deps.edn +++ b/deps.edn @@ -4,11 +4,17 @@ :paths ["src/main"] :aliases {;; for starting nrepl clj & cljs servers for live development - :dev {:extra-paths ["src/dev" "resources" "target"] - :extra-deps {cider/piggieback {:mvn/version "RELEASE"} - com.bhauman/figwheel-main {:mvn/version "RELEASE"} - cider/cider-nrepl {:mvn/version "RELEASE"}} - :main-opts ["-m" "suitable.nrepl"]} + :dev-figwheel {:extra-paths ["src/dev" "resources" "target"] + :extra-deps {cider/piggieback {:mvn/version "RELEASE"} + cider/cider-nrepl {:mvn/version "RELEASE"} + com.bhauman/figwheel-main {:mvn/version "RELEASE"}} + :main-opts ["-m" "suitable.nrepl-figwheel"]} + + :dev-shadow {:extra-paths ["src/dev" "resources" "target"] + :extra-deps {cider/piggieback {:mvn/version "RELEASE"} + cider/cider-nrepl {:mvn/version "RELEASE"} + thheller/shadow-cljs {:mvn/version "RELEASE"}} + :main-opts ["-m" "suitable.nrepl-shadow"]} :fig-repl {:extra-paths ["resources" "target" "src/dev" "src/test"] :main-opts ["-e" "(require,'suitable.hijack-rebel-readline-complete)" diff --git a/shadow-cljs.edn b/shadow-cljs.edn new file mode 100644 index 0000000..5d85084 --- /dev/null +++ b/shadow-cljs.edn @@ -0,0 +1,11 @@ +;; shadow-cljs configuration +{:source-paths + ["src/dev" + "src/main" + "src/test"] + + :dependencies + [] + + :builds + {}} diff --git a/src/dev/suitable/nrepl.clj b/src/dev/suitable/nrepl.clj index b97960a..c3151b3 100644 --- a/src/dev/suitable/nrepl.clj +++ b/src/dev/suitable/nrepl.clj @@ -2,8 +2,6 @@ (:require cider.nrepl cider.piggieback [clojure.pprint :refer [cl-format pprint]] - figwheel.main - figwheel.main.api nrepl.core nrepl.server [suitable.middleware :refer [wrap-complete]])) @@ -59,91 +57,3 @@ (defn cljs-send-eval [code] (@cljs-send-msg {:op :eval :code code})) - -;; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -(defn restart-cljs-server [] - (when @cljs-nrepl-server - (nrepl.server/stop-server @cljs-nrepl-server)) - (require 'figwheel.main.api) - (try (figwheel.main.api/stop-all) (catch Exception e (prn e))) - - (start-cljs-nrepl-server) - (start-cljs-nrepl-client)) - -(defn -main [& args] - (start-clj-nrepl-server) - - (start-cljs-nrepl-server) - (start-cljs-nrepl-client) - ;; (cljs-send-eval "(require 'figwheel.main) (figwheel.main/start :fig)") - ) - -;; (restart-cljs-server) - - - -;; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -(comment - (pprint (doall (nrepl.core/message sess1 {:op :eval :code "(require 'cider.piggieback) (require 'cljs.repl.nashorn) (cider.piggieback/cljs-repl (cljs.repl.nashorn/repl-env))"}))) - (pprint (doall (nrepl.core/message sess1 {:op :eval :code "(require 'figwheel.main) (figwheel.main/start :fig)"}))) - (pprint (doall (nrepl.core/message sess1 {:op :eval :code "(require 'figwheel.main) (figwheel.main/stop-builds :fig)"}))) - (pprint (doall (nrepl.core/message sess1 {:op :eval :code ":cljs/quit"}))) - (pprint (doall (nrepl.core/message sess1 {:op :eval :code "js/console"}))) - (pprint (doall (nrepl.core/message sess1 {:op :eval :code "123"}))) - (nrepl.core/message sess1 {:op :eval :code "(list 1 2 3)"}) - ) - - - -(comment - - (do (start-nrepl-server) - (start-nrepl-client) - (send-eval "(require 'figwheel.main) (figwheel.main/start :fig)")) - - (require 'figwheel.main.api) (figwheel.main.api/cljs-repl "fig") - 123 - (send-eval "(require 'suitable.core)") - (send-eval "123") - - (send-eval "(require 'figwheel.main.api) (figwheel.main.api/cljs-repl \"fig\")") - (send-eval ":cljs/quit") - - (@send-msg {:op :close}) - - (@send-msg {:op :complete :symbol "js/co" :ns "cljs.user" :context nil}) - (@send-msg {:op :complete :symbol "cljs." :ns "suitable.core" :context nil}) - - (require '[cider.nrepl.inlined-deps.cljs-tooling.v0v3v1.cljs-tooling.complete :as cljs-complete]) - (require '[cider.nrepl.middleware.util.cljs :as cljs]) - - (let [ns (symbol "cljs.user") - prefix (str "cljs.co") - extra-metadata (set (map keyword nil)) - cljs-env (some-> (figwheel.main.api/repl-env "fig") :repl-options deref :compiler-env deref)] - (cljs-complete/completions cljs-env prefix {:context-ns ns - :extra-metadata extra-metadata})) - - ;; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - - - - (send-eval "123") - - - (send-eval "(require 'figwheel.main) (figwheel.main/start :fig)") - (send-eval "*ns*") - (send-eval "js/console") - - - (-> @figwheel.main/build-registry (get "fig")) - (figwheel.main.watching/reset-watch!) - - (def server (-> @figwheel.main/build-registry (get "fig") :repl-env :server deref)) - (.stop server) - (figwheel.main/stop-builds :fig) - - ) - diff --git a/src/dev/suitable/nrepl_figwheel.clj b/src/dev/suitable/nrepl_figwheel.clj new file mode 100644 index 0000000..0eb8120 --- /dev/null +++ b/src/dev/suitable/nrepl_figwheel.clj @@ -0,0 +1,44 @@ +(ns suitable.nrepl-figwheel + (:require nrepl.server + [suitable.nrepl :refer [start-clj-nrepl-server + start-cljs-nrepl-server + start-cljs-nrepl-client + cljs-nrepl-server]])) + +;;;; nrepl servers with figwheel +;;; This is useful for development. It will start two nrepl servers. The outer +;;; one on localhost:7888 allows to develop the clojure code. The inner server +;;; is a cljs repl and connected to figwheel. You can connect with cider +;;; 'figwheel-main build 'fig and test the cljs side of things (e.g. visit +;;; suitable.main). Also open localhost:9500 in a web browser to get the +;;; figwheel js enviornment loaded. + +(defn restart-cljs-server [] + (when @cljs-nrepl-server + (nrepl.server/stop-server @cljs-nrepl-server)) + (require 'figwheel.main.api) + (try (figwheel.main.api/stop-all) (catch Exception e (prn e))) + + (start-cljs-nrepl-server) + (start-cljs-nrepl-client)) + +(defn -main [& args] + (start-clj-nrepl-server) + + (start-cljs-nrepl-server) + (start-cljs-nrepl-client)) + +;; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +(comment + (do (start-nrepl-server) + (start-nrepl-client) + (cljs-send-eval "(require 'figwheel.main) (figwheel.main/start :fig)")) + + (cljs-send-eval "(require 'suitable.core)") + (cljs-send-eval "123") + + (cljs-send-eval "(require 'figwheel.main.api) (figwheel.main.api/cljs-repl \"fig\")") + (cljs-send-eval ":cljs/quit") + ) + diff --git a/src/dev/suitable/nrepl_shadow.clj b/src/dev/suitable/nrepl_shadow.clj new file mode 100644 index 0000000..0332137 --- /dev/null +++ b/src/dev/suitable/nrepl_shadow.clj @@ -0,0 +1,18 @@ +(ns suitable.nrepl-shadow + (:require shadow.cljs.devtools.server + [suitable.nrepl :refer [start-clj-nrepl-server + start-cljs-nrepl-server + start-cljs-nrepl-client + cljs-nrepl-server + cljs-send-eval]])) + +;;;; nrepl servers with shadow-cljs +;;; start and connect to localhost:7889 via cider for a cljs repl. connect to +;;; :7888 for the clojure side. + +(defn -main [& args] + (start-clj-nrepl-server) + (shadow.cljs.devtools.server/start! + (merge + (shadow.cljs.devtools.server/load-config) + {:nrepl {:port 7889}}))) diff --git a/src/main/suitable/compliment/sources/cljs.cljc b/src/main/suitable/compliment/sources/cljs.cljc index 1764bab..70bf841 100644 --- a/src/main/suitable/compliment/sources/cljs.cljc +++ b/src/main/suitable/compliment/sources/cljs.cljc @@ -2,10 +2,10 @@ "Standalone auto-complete library based on cljs analyzer state" (:refer-clojure :exclude [meta]) (:require [clojure.set :as set] - [compliment.sources :refer [defsource]] - [compliment.utils :as utils :refer [*extra-metadata*]] + #?(:clj [compliment.sources :refer [defsource]]) + #?(:clj [compliment.utils :as utils :refer [*extra-metadata*]]) [suitable.compliment.sources.cljs.analysis :as ana]) - (:import java.io.StringWriter)) + #?(:clj (:import java.io.StringWriter))) (defn unquote-first "Handles some weird double-quoting in the analyzer" @@ -289,67 +289,70 @@ It requires the compliment.sources.cljs/*compiler-env* var to be dynamically bound to the ClojureScript compiler env." [prefix ns context] - (let [context-ns (try (ns-name ns) (catch Exception _ nil))] - (->> (potential-candidates *compiler-env* context-ns prefix *extra-metadata*) - #?(:cljs (map remove-candidate-macros)) - (distinct-candidates) - (filter #(candidate-match? % prefix))))) - -(defn generate-docstring - "Generates a docstring from a given var metadata. + #?(:clj + (let [context-ns (try (ns-name ns) (catch Exception _ nil))] + (->> (potential-candidates *compiler-env* context-ns prefix *extra-metadata*) + #?(:cljs (map remove-candidate-macros)) + (distinct-candidates) + (filter #(candidate-match? % prefix))))) + #?(:cljs nil)) + +#?(:clj + (defn generate-docstring + "Generates a docstring from a given var metadata. Copied from `cljs.repl` with some minor modifications." - [{n :ns nm :name :as m}] - (binding [*out* (StringWriter.)] - (println "-------------------------") - (println (or (:spec m) (str (when-let [ns (:ns m)] (str ns "/")) (:name m)))) - (when (:protocol m) - (println "Protocol")) - (cond - (:forms m) (doseq [f (:forms m)] - (println " " f)) - (:arglists m) (let [arglists (:arglists m)] - (if (or (:macro m) - (:repl-special-function m)) - (prn arglists) - (prn - (if (= 'quote (first arglists)) - (second arglists) - arglists))))) - (if (:special-form m) - (do - (println "Special Form") - (println " " (:doc m)) - (if (contains? m :url) - (when (:url m) - (println (str "\n Please see http://clojure.org/" (:url m)))) - (println (str "\n Please see http://clojure.org/special_forms#" - (:name m))))) - (do - (when (:macro m) - (println "Macro")) - (when (:spec m) - (println "Spec")) - (when (:repl-special-function m) - (println "REPL Special Function")) - (println " " (:doc m)) - (when (:protocol m) - (doseq [[name {:keys [doc arglists]}] (:methods m)] - (println) - (println " " name) - (println " " arglists) - (when doc - (println " " doc)))) - ;; Specs are handled separately in cider-nrepl - ;; - ;; (when n - ;; (when-let [fnspec (spec/get-spec (symbol (str (ns-name n)) (name nm)))] - ;; (print "Spec") - ;; (doseq [role [:args :ret :fn]] - ;; (when-let [spec (get fnspec role)] - ;; (print (str "\n " (name role) ":") (spec/describe spec)))))) - )) - (str *out*))) + [{n :ns nm :name :as m}] + (binding [*out* (StringWriter.)] + (println "-------------------------") + (println (or (:spec m) (str (when-let [ns (:ns m)] (str ns "/")) (:name m)))) + (when (:protocol m) + (println "Protocol")) + (cond + (:forms m) (doseq [f (:forms m)] + (println " " f)) + (:arglists m) (let [arglists (:arglists m)] + (if (or (:macro m) + (:repl-special-function m)) + (prn arglists) + (prn + (if (= 'quote (first arglists)) + (second arglists) + arglists))))) + (if (:special-form m) + (do + (println "Special Form") + (println " " (:doc m)) + (if (contains? m :url) + (when (:url m) + (println (str "\n Please see http://clojure.org/" (:url m)))) + (println (str "\n Please see http://clojure.org/special_forms#" + (:name m))))) + (do + (when (:macro m) + (println "Macro")) + (when (:spec m) + (println "Spec")) + (when (:repl-special-function m) + (println "REPL Special Function")) + (println " " (:doc m)) + (when (:protocol m) + (doseq [[name {:keys [doc arglists]}] (:methods m)] + (println) + (println " " name) + (println " " arglists) + (when doc + (println " " doc)))) + ;; Specs are handled separately in cider-nrepl + ;; + ;; (when n + ;; (when-let [fnspec (spec/get-spec (symbol (str (ns-name n)) (name nm)))] + ;; (print "Spec") + ;; (doseq [role [:args :ret :fn]] + ;; (when-let [spec (get fnspec role)] + ;; (print (str "\n " (name role) ":") (spec/describe spec)))))) + )) + (str *out*)))) (defn doc [s ns] @@ -377,6 +380,6 @@ (not-empty) (generate-docstring)))) -(defsource ::cljs-source - :candidates #'candidates - :doc #'doc) +#?(:clj (defsource ::cljs-source + :candidates #'candidates + :doc #'doc)) diff --git a/src/main/suitable/js_completions.cljc b/src/main/suitable/js_completions.cljc index 4cd2bee..d1d6ae8 100644 --- a/src/main/suitable/js_completions.cljc +++ b/src/main/suitable/js_completions.cljc @@ -52,10 +52,11 @@ (when-let [form (if (string? context) (try (with-in-str context (read *in* nil nil)) - (catch Exception _e - (when debug? - (binding [*out* *err*] - (cl-format true "[suitable] Error reading context: ~s" context))))) + #?(:clj (catch Exception _e + (when debug? + (binding [*out* *err*] + (cl-format true "[suitable] Error reading context: ~s" context))))) + #?(:cljs (catch js/Error _e))) context)] (let [prefix (find-prefix form) left-sibling (zip/left prefix) diff --git a/src/test/suitable/compliment/sources/t_cljs.cljc b/src/test/suitable/compliment/sources/t_cljs.cljc index 0426c0c..bb4840a 100644 --- a/src/test/suitable/compliment/sources/t_cljs.cljc +++ b/src/test/suitable/compliment/sources/t_cljs.cljc @@ -4,7 +4,7 @@ [clojure.test :as test #?(:clj :refer :cljs :refer-macros) [deftest is testing use-fixtures]] [clojure.tools.reader.edn :as edn] [clojure.walk :as walk] - [compliment.utils :refer [*extra-metadata*]] + #?(:clj [compliment.utils :refer [*extra-metadata*]]) [suitable.cljs.env :as cljs-env] [suitable.compliment.sources.cljs :as cljs-sources])) @@ -241,49 +241,50 @@ {:candidate "ES6IteratorSeq" :ns "cljs.core" :type :type}) (completions "ES6I"))))) -(deftest extra-metadata - (testing "Extra metadata: namespace :doc" - (binding [*extra-metadata* #{:doc}] - (is (set= '({:candidate "suitable.test-ns" :doc "A test namespace" :type :namespace} - {:candidate "suitable.test-ns-dep" :doc "Dependency of test-ns namespace" :type :namespace}) - (completions "suitable.test-"))))) - - (testing "Extra metadata: aliased namespace :doc" - (binding [*extra-metadata* #{:doc}] - (is (= '({:candidate "test-dep" :doc "Dependency of test-ns namespace" :ns "suitable.test-ns-dep" :type :namespace}) - (completions "test-d" 'suitable.test-ns))))) - - (testing "Extra metadata: macro namespace :doc" - (binding [*extra-metadata* #{:doc}] - (is (= '({:candidate "suitable.test-macros" :doc "A test macro namespace" :type :namespace}) - (completions "suitable.test-m" 'suitable.test-ns))))) - - (testing "Extra metadata: normal var :arglists" - (binding [*extra-metadata* #{:arglists}] - (is (set= '({:candidate "unchecked-add" :ns "cljs.core" :arglists ("[]" "[x]" "[x y]" "[x y & more]") :type :function} - {:candidate "unchecked-add-int" :ns "cljs.core" :arglists ("[]" "[x]" "[x y]" "[x y & more]") :type :function}) - (completions "unchecked-a" 'cljs.user))))) - - (testing "Extra metadata: normal var :doc" - (binding [*extra-metadata* #{:doc}] - (is (set= '({:candidate "unchecked-add" :ns "cljs.core" :doc "Returns the sum of nums. (+) returns 0." :type :function} - {:candidate "unchecked-add-int" :ns "cljs.core" :doc "Returns the sum of nums. (+) returns 0." :type :function}) - (completions "unchecked-a" 'cljs.user))))) - - (testing "Extra metadata: macro :arglists" - (binding [*extra-metadata* #{:arglists}] - (is (= '({:candidate "defprotocol" :ns "cljs.core" :arglists ("[psym & doc+methods]") :type :macro}) - (completions "defproto" 'cljs.user))))) - - (testing "Extra metadata: referred var :arglists" - (binding [*extra-metadata* #{:arglists}] - (is (= '({:candidate "foo-in-dep" :ns "suitable.test-ns-dep" :arglists ("[foo]") :type :function}) - (completions "foo" 'suitable.test-ns))))) - - (testing "Extra metadata: referred macro :arglists" - (binding [*extra-metadata* #{:arglists}] - (is (= '({:candidate "my-add" :ns "suitable.test-macros" :arglists ("[a b]") :type :macro}) - (completions "my-a" 'suitable.test-ns)))))) +#?(:clj + (deftest extra-metadata + (testing "Extra metadata: namespace :doc" + (binding [*extra-metadata* #{:doc}] + (is (set= '({:candidate "suitable.test-ns" :doc "A test namespace" :type :namespace} + {:candidate "suitable.test-ns-dep" :doc "Dependency of test-ns namespace" :type :namespace}) + (completions "suitable.test-"))))) + + (testing "Extra metadata: aliased namespace :doc" + (binding [*extra-metadata* #{:doc}] + (is (= '({:candidate "test-dep" :doc "Dependency of test-ns namespace" :ns "suitable.test-ns-dep" :type :namespace}) + (completions "test-d" 'suitable.test-ns))))) + + (testing "Extra metadata: macro namespace :doc" + (binding [*extra-metadata* #{:doc}] + (is (= '({:candidate "suitable.test-macros" :doc "A test macro namespace" :type :namespace}) + (completions "suitable.test-m" 'suitable.test-ns))))) + + (testing "Extra metadata: normal var :arglists" + (binding [*extra-metadata* #{:arglists}] + (is (set= '({:candidate "unchecked-add" :ns "cljs.core" :arglists ("[]" "[x]" "[x y]" "[x y & more]") :type :function} + {:candidate "unchecked-add-int" :ns "cljs.core" :arglists ("[]" "[x]" "[x y]" "[x y & more]") :type :function}) + (completions "unchecked-a" 'cljs.user))))) + + (testing "Extra metadata: normal var :doc" + (binding [*extra-metadata* #{:doc}] + (is (set= '({:candidate "unchecked-add" :ns "cljs.core" :doc "Returns the sum of nums. (+) returns 0." :type :function} + {:candidate "unchecked-add-int" :ns "cljs.core" :doc "Returns the sum of nums. (+) returns 0." :type :function}) + (completions "unchecked-a" 'cljs.user))))) + + (testing "Extra metadata: macro :arglists" + (binding [*extra-metadata* #{:arglists}] + (is (= '({:candidate "defprotocol" :ns "cljs.core" :arglists ("[psym & doc+methods]") :type :macro}) + (completions "defproto" 'cljs.user))))) + + (testing "Extra metadata: referred var :arglists" + (binding [*extra-metadata* #{:arglists}] + (is (= '({:candidate "foo-in-dep" :ns "suitable.test-ns-dep" :arglists ("[foo]") :type :function}) + (completions "foo" 'suitable.test-ns))))) + + (testing "Extra metadata: referred macro :arglists" + (binding [*extra-metadata* #{:arglists}] + (is (= '({:candidate "my-add" :ns "suitable.test-macros" :arglists ("[a b]") :type :macro}) + (completions "my-a" 'suitable.test-ns))))))) (deftest predicates (testing "The plain-symbol? predicate" From 30037b20506bd21ed850c6f88778a453117ee72e Mon Sep 17 00:00:00 2001 From: Robert Krahn Date: Sun, 18 Apr 2021 01:30:34 +0200 Subject: [PATCH 5/5] [chore] 0.4.0 --- README.md | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f88bad7..23c8a59 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ You can now start a figwheel repl via `clj -M:suitable` and use TAB to complete. First make sure that the [normal leiningen setup](https://figwheel.org/#setting-up-a-build-with-leiningen) works. -Add `[org.rksm/suitable "0.3.5"]` to your dependencies vector. +Add `[org.rksm/suitable "0.4.0"]` to your dependencies vector. Then you can start a repl with `lein trampoline run -m suitable.figwheel.main -- -b dev -r` diff --git a/pom.xml b/pom.xml index e7692c9..1c59c99 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.rksm suitable - 0.3.5 + 0.4.0 suitable An addon for Figwheel and Emacs Cider to aid live exploratory development. Queries objects in ClojureScript for their properties to use as part of nREPL completion handlers. http://github.com/rksm/clj-suitable