diff --git a/.dir-locals.el b/.dir-locals.el
deleted file mode 100644
index c8a34a2..0000000
--- a/.dir-locals.el
+++ /dev/null
@@ -1,5 +0,0 @@
-((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")
- )))
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 08ba224..3cba78d 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}
@@ -38,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 -R: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/README.md b/README.md
index b21457d..23c8a59 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):

@@ -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,24 +89,21 @@ 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
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`
### 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
diff --git a/deps.edn b/deps.edn
index 81530b9..de78a4e 100644
--- a/deps.edn
+++ b/deps.edn
@@ -1,14 +1,20 @@
{: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"]
: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/pom.xml b/pom.xml
index 1017fd3..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
@@ -25,7 +25,12 @@
org.clojure
clojurescript
- [1.9.908,)
+ 1.10.844
+
+
+ compliment
+ compliment
+ 0.3.10
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 5fb636d..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]]))
@@ -13,7 +11,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
@@ -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/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/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/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 53176ba..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)
@@ -173,13 +174,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)))
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))
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"