summaryrefslogtreecommitdiff
path: root/cider.el
diff options
context:
space:
mode:
authorBozhidar Batsov <bozhidar@batsov.com>2018-03-05 13:37:45 +0700
committerBozhidar Batsov <bozhidar@batsov.com>2018-03-05 13:37:45 +0700
commit7d91a6d8c3b0c8b709465b43420d795e27829db4 (patch)
treeb62f3ee7461fb86e8d82d26d34d1215fefcdeec3 /cider.el
parent6c16e8af62bf6101dbe3a15919ff8d6ab4f0f977 (diff)
[#2202] Check in advance if a ClojureScript REPL can be created or not
The current logic relies mostly on namespace checks, but it can certainly be improved down the road. The most important thing is that now users are going to get more meaningful errors earlier. Before this we'd first create the second REPL buffer and just get there some obscure errors because the command didn't check at all if piggieback or the target REPL were even available.
Diffstat (limited to 'cider.el')
-rw-r--r--cider.el177
1 files changed, 107 insertions, 70 deletions
diff --git a/cider.el b/cider.el
index d789c7b8..85d17214 100644
--- a/cider.el
+++ b/cider.el
@@ -504,22 +504,48 @@ dependencies."
;;; ClojureScript REPL creation
+(defun cider-check-nashorn-requirements ()
+ "Check whether we can start a Nashorn ClojureScript REPL."
+ (when (string-prefix-p "1.7" (cider--java-version))
+ (user-error "Nashorn is supported only on Java 8 or newer")))
+
+(defun cider-check-node-requirements ()
+ "Check whether we can start a Node ClojureScript REPL."
+ (unless (executable-find "node")
+ (user-error "Node.js is not present on the exec-path. Make sure you've installed it and your exec-path is properly set")))
+
+(defun cider-check-figwheel-requirements ()
+ "Check whether we can start a Figwheel ClojureScript REPL."
+ (unless (cider-namespace-present-p "figwheel-sidecar.repl-api")
+ (user-error "Figwheel is not available. Please check http://cider.readthedocs.io/en/latest/up_and_running/#clojurescript-usage")))
+
+(defun cider-check-weasel-requirements ()
+ "Check whether we can start a Weasel ClojureScript REPL."
+ (unless (cider-namespace-present-p "weasel.repl.websocket")
+ (user-error "Weasel in not available. Please check http://cider.readthedocs.io/en/latest/up_and_running/#browser-connected-clojurescript-repl")))
+
+(defun cider-check-boot-requirements ()
+ "Check whether we can start a Boot ClojureScript REPL."
+ (unless (cider-namespace-present-p "adzerk.boot-cljs-repl")
+ (user-error "The Boot ClojureScript REPL is not available. Please check https://github.com/adzerk-oss/boot-cljs-repl/blob/master/README.md")))
+
(defconst cider-cljs-repl-types
- '(("Rhino" "(cemerick.piggieback/cljs-repl (cljs.repl.rhino/repl-env))" "")
- ("Nashorn" "(cemerick.piggieback/cljs-repl (cljs.repl.nashorn/repl-env))" " (part of Java 8 and newer)")
+ '(("Rhino" "(cemerick.piggieback/cljs-repl (cljs.repl.rhino/repl-env))"
+ nil)
+ ("Nashorn" "(cemerick.piggieback/cljs-repl (cljs.repl.nashorn/repl-env))"
+ cider-check-nashorn-requirements)
("Figwheel" "(do (require 'figwheel-sidecar.repl-api) (figwheel-sidecar.repl-api/start-figwheel!) (figwheel-sidecar.repl-api/cljs-repl))"
- " (add figwheel-sidecar to your plugins)")
+ cider-check-figwheel-requirements)
("Node" "(do (require 'cljs.repl.node) (cemerick.piggieback/cljs-repl (cljs.repl.node/repl-env)))"
- " (requires NodeJS to be installed)")
+ cider-check-node-requirements)
("Weasel" "(do (require 'weasel.repl.websocket) (cemerick.piggieback/cljs-repl (weasel.repl.websocket/repl-env :ip \"127.0.0.1\" :port 9001)))"
- " (see http://cider.readthedocs.io/en/latest/up_and_running/#browser-connected-clojurescript-repl)")
+ cider-check-weasel-requirements)
("Boot" "(do (require 'adzerk.boot-cljs-repl) (adzerk.boot-cljs-repl/start-repl))"
- " (see https://github.com/adzerk-oss/boot-cljs-repl/blob/master/README.md"))
+ cider-check-boot-requirements))
"A list of supported ClojureScript REPLs.
For each one we have its name, the form we need to evaluate in a Clojure
-REPL to start the ClojureScript REPL and some installation instructions (if
-necessary).")
+REPL to start the ClojureScript REPL and functions to very their requirements.")
(defcustom cider-default-cljs-repl nil
"The default ClojureScript REPL to start.
@@ -544,20 +570,23 @@ you're working on."
(defun cider-select-cljs-repl ()
"Select the ClojureScript REPL to use with `cider-jack-in-clojurescript'."
- (let* ((repl-types (mapcar #'car cider-cljs-repl-types))
- (selected-type (completing-read "Select ClojureScript REPL type: " repl-types)))
- (cadr (seq-find (lambda (entry)
- (equal (car entry)
- selected-type))
- cider-cljs-repl-types))))
-
-(defun cider-default-cljs-repl-form ()
- "Get the default cljs REPL form if set."
- (when cider-default-cljs-repl
- (cadr (seq-find
- (lambda (entry)
- (equal (car entry) cider-default-cljs-repl))
- cider-cljs-repl-types))))
+ (let ((repl-types (mapcar #'car cider-cljs-repl-types)))
+ (completing-read "Select ClojureScript REPL type: " repl-types)))
+
+(defun cider-cljs-repl-form (repl-type)
+ "Get the cljs REPL form for REPL-TYPE."
+ (cadr (seq-find
+ (lambda (entry)
+ (equal (car entry) repl-type))
+ cider-cljs-repl-types)))
+
+(defun cider-verify-cljs-repl-requirements (repl-type)
+ "Verify that the requirements for REPL-TYPE are met."
+ (when-let* ((fun (nth 2 (seq-find
+ (lambda (entry)
+ (equal (car entry) repl-type))
+ cider-cljs-repl-types))))
+ (funcall fun)))
(defun cider--offer-to-open-app-in-browser (server-buffer)
"Look for a server address in SERVER-BUFFER and offer to open it."
@@ -570,6 +599,11 @@ you're working on."
(when (y-or-n-p (format "Visit ā€˜%sā€™ in a browser? " url))
(browse-url url)))))))
+(defun cider-verify-piggieback-is-present ()
+ "Check whether the piggieback middleware is present."
+ (unless (cider-namespace-present-p "cemerick.piggieback")
+ (user-error "Piggieback is not available. See http://cider.readthedocs.io/en/latest/up_and_running/#clojurescript-usage for details")))
+
(defun cider-create-sibling-cljs-repl (client-buffer)
"Create a ClojureScript REPL with the same server as CLIENT-BUFFER.
The new buffer will correspond to the same project as CLIENT-BUFFER, which
@@ -578,54 +612,57 @@ should be the regular Clojure REPL started by the server process filter.
Normally this would prompt for the ClojureScript REPL to start (e.g. Node,
Figwheel, etc), unless you've set `cider-default-cljs-repl'."
(interactive (list (cider-current-connection)))
- ;; Load variables in .dir-locals.el into the server process buffer, so
- ;; cider-default-cljs-repl can be set for each project individually.
- (hack-local-variables)
- (let* ((nrepl-repl-buffer-name-template "*cider-repl CLJS%s*")
- (nrepl-create-client-buffer-function #'cider-repl-create)
- (nrepl-use-this-as-repl-buffer 'new)
- (client-process-args (with-current-buffer client-buffer
- (unless (or nrepl-server-buffer nrepl-endpoint)
- (error "This is not a REPL buffer, is there a REPL active?"))
- (list (car nrepl-endpoint)
- (elt nrepl-endpoint 1)
- (when (buffer-live-p nrepl-server-buffer)
- (get-buffer-process nrepl-server-buffer)))))
- (cljs-proc (apply #'nrepl-start-client-process client-process-args))
- (cljs-buffer (process-buffer cljs-proc))
- (cljs-repl-form (or (cider-default-cljs-repl-form)
- (cider-select-cljs-repl))))
- (with-current-buffer cljs-buffer
- ;; The new connection has now been bumped to the top, but it's still a
- ;; Clojure REPL! Additionally, some ClojureScript REPLs can actually take
- ;; a while to start (some even depend on the user opening a browser).
- ;; Meanwhile, this REPL will gladly receive requests in place of the
- ;; original Clojure REPL. Our solution is to bump the original REPL back
- ;; up the list, so it takes priority on Clojure requests.
- (cider-make-connection-default client-buffer)
- (setq cider-repl-type "cljs")
- (pcase cider-cljs-repl-types
- (`(,name ,_ ,info)
- (message "Starting a %s REPL%s" name (or info ""))))
- (cider-nrepl-send-request
- `("op" "eval"
- "ns" ,(cider-current-ns)
- "code" ,cljs-repl-form)
- (cider-repl-handler (current-buffer)))
- (when cider-offer-to-open-cljs-app-in-browser
- (cider--offer-to-open-app-in-browser nrepl-server-buffer)))))
-
-(defun cider--select-zombie-buffer (repl-buffers)
- "Return a zombie buffer from REPL-BUFFERS, or nil if none exists."
- (when-let* ((zombie-buffs (seq-remove #'get-buffer-process repl-buffers)))
- (when (y-or-n-p
- (format "Zombie REPL buffers exist (%s). Reuse? "
- (mapconcat #'buffer-name zombie-buffs ", ")))
- (if (= (length zombie-buffs) 1)
- (car zombie-buffs)
- (completing-read "Choose REPL buffer: "
- (mapcar #'buffer-name zombie-buffs)
- nil t)))))
+ (cider-verify-piggieback-is-present)
+ (let* ((cljs-repl-type (or cider-default-cljs-repl
+ (cider-select-cljs-repl)))
+ (cljs-repl-form (cider-cljs-repl-form cljs-repl-type)))
+ (cider-verify-cljs-repl-requirements cljs-repl-type)
+ ;; Load variables in .dir-locals.el into the server process buffer, so
+ ;; cider-default-cljs-repl can be set for each project individually.
+ (hack-local-variables)
+ (let* ((nrepl-repl-buffer-name-template "*cider-repl CLJS%s*")
+ (nrepl-create-client-buffer-function #'cider-repl-create)
+ (nrepl-use-this-as-repl-buffer 'new)
+ (client-process-args (with-current-buffer client-buffer
+ (unless (or nrepl-server-buffer nrepl-endpoint)
+ (error "This is not a REPL buffer, is there a REPL active?"))
+ (list (car nrepl-endpoint)
+ (elt nrepl-endpoint 1)
+ (when (buffer-live-p nrepl-server-buffer)
+ (get-buffer-process nrepl-server-buffer)))))
+ (cljs-proc (apply #'nrepl-start-client-process client-process-args))
+ (cljs-buffer (process-buffer cljs-proc)))
+ (with-current-buffer cljs-buffer
+ ;; The new connection has now been bumped to the top, but it's still a
+ ;; Clojure REPL! Additionally, some ClojureScript REPLs can actually take
+ ;; a while to start (some even depend on the user opening a browser).
+ ;; Meanwhile, this REPL will gladly receive requests in place of the
+ ;; original Clojure REPL. Our solution is to bump the original REPL back
+ ;; up the list, so it takes priority on Clojure requests.
+ (cider-make-connection-default client-buffer)
+ (setq cider-repl-type "cljs")
+ (pcase cider-cljs-repl-types
+ (`(,name ,_ ,info)
+ (message "Starting a %s REPL%s" name (or info ""))))
+ (cider-nrepl-send-request
+ `("op" "eval"
+ "ns" ,(cider-current-ns)
+ "code" ,cljs-repl-form)
+ (cider-repl-handler (current-buffer)))
+ (when cider-offer-to-open-cljs-app-in-browser
+ (cider--offer-to-open-app-in-browser nrepl-server-buffer)))))
+
+ (defun cider--select-zombie-buffer (repl-buffers)
+ "Return a zombie buffer from REPL-BUFFERS, or nil if none exists."
+ (when-let* ((zombie-buffs (seq-remove #'get-buffer-process repl-buffers)))
+ (when (y-or-n-p
+ (format "Zombie REPL buffers exist (%s). Reuse? "
+ (mapconcat #'buffer-name zombie-buffs ", ")))
+ (if (= (length zombie-buffs) 1)
+ (car zombie-buffs)
+ (completing-read "Choose REPL buffer: "
+ (mapcar #'buffer-name zombie-buffs)
+ nil t))))))
(defun cider-find-reusable-repl-buffer (endpoint project-directory)
"Check whether a reusable connection buffer already exists.