Skip to content

Commit

Permalink
Allow predicates in plugin and middleware lists
Browse files Browse the repository at this point in the history
  • Loading branch information
raxod502 committed Mar 24, 2018
1 parent 3d47506 commit f9bd359
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* [#2241](https://github.com/clojure-emacs/cider/pull/2241): Make `cider-test-ediff` diff eval'ed values.
* Add support for shadow-cljs to `cider-jack-in`.
* [#2244](https://github.com/clojure-emacs/cider/issues/2244): Display the REPL type in the modeline.
* [#2238](https://github.com/clojure-emacs/cider/pull/2238): Allow specifying predicates for entries in `cider-jack-in-lein-plugins` and `cider-jack-in-nrepl-middlewares`.

### Bugs Fixed

Expand Down
68 changes: 60 additions & 8 deletions cider.el
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,10 @@ version from the CIDER package or library.")
:package-version '(cider . "0.17.0"))

(defcustom cider-clojure-cli-parameters
"-e '(require (quote cider-nrepl.main)) (cider-nrepl.main/init [\"cider.nrepl/cider-middleware\"])'"
"Params passed to clojure to start an nREPL server via `cider-jack-in'."
"-e '(require (quote cider-nrepl.main)) (cider-nrepl.main/init %s)'"
"Params passed to clojure to start an nREPL server via `cider-jack-in'.
This is evaluated using `format', with the first argument being the Clojure
vector of middleware variables as a string."
:type 'string
:group 'cider
:safe #'stringp
Expand Down Expand Up @@ -346,7 +348,14 @@ Throws an error if PROJECT-TYPE is unknown. Known types are
(pcase project-type
("lein" cider-lein-parameters)
("boot" cider-boot-parameters)
("clojure-cli" cider-clojure-cli-parameters)
("clojure-cli" (format cider-clojure-cli-parameters
(concat
"["
(mapconcat
(apply-partially #'format "\"%s\"")
(cider-jack-in-normalized-nrepl-middlewares)
", ")
"]")))
("shadow-cljs" cider-shadow-cljs-parameters)
("gradle" cider-gradle-parameters)
(_ (user-error "Unsupported project type `%s'" project-type))))
Expand Down Expand Up @@ -385,17 +394,60 @@ specifying the artifact ID, and the second element the version number."
(string :tag "Version"))))

(defvar cider-jack-in-lein-plugins nil
"List of Leiningen plugins where elements are lists of artifact name and version.")
"List of Leiningen plugins to be injected at jack-in.
Each element is a list of artifact name and version, followed optionally by
keyword arguments. The only keyword argument currently accepted is
`:predicate', which should be given a function that takes the list (name,
version, and keyword arguments) and returns non-nil to indicate that the
plugin should actually be injected. (This is useful primarily for packages
that extend CIDER, not for users. For example, a refactoring package might
want to inject some middleware only when within a project context.)")
(put 'cider-jack-in-lein-plugins 'risky-local-variable t)
(cider-add-to-alist 'cider-jack-in-lein-plugins
"cider/cider-nrepl" (upcase cider-version))

(defun cider-jack-in-normalized-lein-plugins ()
"Return a normalized list of Leiningen plugins to be injected.
See `cider-jack-in-lein-plugins' for the format, except that the list
returned by this function does not include keyword arguments."
(thread-last cider-jack-in-lein-plugins
(seq-filter
(lambda (spec)
(if-let* ((pred (plist-get (seq-drop spec 2) :predicate)))
(funcall pred spec)
t)))
(mapcar
(lambda (spec)
(seq-take spec 2)))))

(defvar cider-jack-in-nrepl-middlewares nil
"List of Clojure variable names.
Each of these Clojure variables should hold a vector of nREPL middlewares.")
Each of these Clojure variables should hold a vector of nREPL middlewares.
Instead of a string, an element can be a list containing a string followed
by optional keyword arguments. The only keyword argument currently
accepted is `:predicate', which should be given a function that takes the
list (string and keyword arguments) and returns non-nil to indicate that
the middlewares should actually be injected.")
(put 'cider-jack-in-nrepl-middlewares 'risky-local-variable t)
(add-to-list 'cider-jack-in-nrepl-middlewares "cider.nrepl/cider-middleware")

(defun cider-jack-in-normalized-nrepl-middlewares ()
"Return a normalized list of middleware variable names.
See `cider-jack-in-nrepl-middlewares' for the format, except that the list
returned by this function only contains strings."
(thread-last cider-jack-in-nrepl-middlewares
(seq-filter
(lambda (spec)
(or (not (listp spec))
(if-let* ((pred (plist-get (cdr spec) :predicate)))
(funcall pred spec)
t))))
(mapcar
(lambda (spec)
(if (listp spec)
(car spec)
spec)))))

(defun cider--list-as-boot-artifact (list)
"Return a boot artifact string described by the elements of LIST.
LIST should have the form (ARTIFACT-NAME ARTIFACT-VERSION). The returned
Expand Down Expand Up @@ -523,14 +575,14 @@ dependencies."
(cider-add-clojure-dependencies-maybe
cider-jack-in-dependencies)
cider-jack-in-dependencies-exclusions
cider-jack-in-lein-plugins))
(cider-jack-in-normalized-lein-plugins)))
("boot" (cider-boot-jack-in-dependencies
global-opts
params
(cider-add-clojure-dependencies-maybe
cider-jack-in-dependencies)
cider-jack-in-lein-plugins
cider-jack-in-nrepl-middlewares))
(cider-jack-in-normalized-lein-plugins)
(cider-jack-in-normalized-nrepl-middlewares)))
("clojure-cli" (cider-clojure-cli-jack-in-dependencies
global-opts
params
Expand Down
57 changes: 56 additions & 1 deletion test/cider-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,62 @@
:to-equal "-C -o -i \"(require 'cider.tasks)\" -d org.clojure/tools.nrepl\\:0.2.12 -d cider/cider-nrepl\\:0.11.0 cider.tasks/add-middleware -m cider.nrepl/cider-middleware repl -s wait"))
(it "can concat in a gradle project"
(expect (cider-inject-jack-in-dependencies "-m" "--no-daemon clojureRepl" "gradle")
:to-equal "-m --no-daemon clojureRepl"))))
:to-equal "-m --no-daemon clojureRepl")))

(describe "when there are predicates"
:var (plugins-predicate middlewares-predicate)

(before-each
(fset 'plugins-predicate (lambda (&rest _) t))
(fset 'middlewares-predicate (lambda (&rest _) t))
(setq-local cider-jack-in-lein-plugins '(("refactor-nrepl" "2.0.0" :predicate plugins-predicate) ("cider/cider-nrepl" "0.11.0")))
(setq-local cider-jack-in-nrepl-middlewares '(("refactor-nrepl.middleware/wrap-refactor" :predicate middlewares-predicate) "cider.nrepl/cider-middleware" ("another/middleware"))))
(it "includes plugins whose predicates return true"
(expect (cider-jack-in-normalized-lein-plugins)
:to-equal '(("refactor-nrepl" "2.0.0") ("cider/cider-nrepl" "0.11.0"))))
(it "includes middlewares whose predicates return true"
(expect (cider-jack-in-normalized-nrepl-middlewares)
:to-equal '("refactor-nrepl.middleware/wrap-refactor" "cider.nrepl/cider-middleware" "another/middleware")))
(it "ignores plugins whose predicates return false"
(spy-on 'plugins-predicate :and-return-value nil)
(expect (cider-jack-in-normalized-lein-plugins)
:to-equal '(("cider/cider-nrepl" "0.11.0"))))
(it "ignores plugins whose predicates return false"
(spy-on 'middlewares-predicate :and-return-value nil)
(expect (cider-jack-in-normalized-nrepl-middlewares)
:to-equal '("cider.nrepl/cider-middleware" "another/middleware")))
(it "calls plugin predicates with the whole list entry"
(spy-on 'plugins-predicate)
(cider-jack-in-normalized-lein-plugins)
(expect 'plugins-predicate
:to-have-been-called-with '("refactor-nrepl" "2.0.0" :predicate plugins-predicate)))
(it "calls middleware predicates with the whole list entry"
(spy-on 'middlewares-predicate)
(cider-jack-in-normalized-nrepl-middlewares)
(expect 'middlewares-predicate
:to-have-been-called-with '("refactor-nrepl.middleware/wrap-refactor" :predicate middlewares-predicate)))
(it "only calls plugin predicates for their own entries"
(spy-on 'plugins-predicate)
(cider-jack-in-normalized-lein-plugins)
(expect 'plugins-predicate :to-have-been-called-times 1))
(it "only calls middleware predicates for their own entries"
(spy-on 'middlewares-predicate)
(cider-jack-in-normalized-nrepl-middlewares)
(expect 'middlewares-predicate :to-have-been-called-times 1)))

(describe "when the middleware and plugin lists have been normalized"
(before-each
(spy-on 'cider-jack-in-normalized-nrepl-middlewares
:and-return-value '("refactor-nrepl.middleware/wrap-refactor" "cider.nrepl/cider-middleware"))
(spy-on 'cider-jack-in-normalized-lein-plugins
:and-return-value '(("refactor-nrepl" "2.0.0") ("cider/cider-nrepl" "0.11.0")))
(setq-local cider-jack-in-dependencies-exclusions '()))
(it "uses them in a lein project"
(expect (cider-inject-jack-in-dependencies "" "repl :headless" "lein")
:to-equal "update-in :dependencies conj \\[org.clojure/tools.nrepl\\ \\\"0.2.12\\\"\\] -- update-in :plugins conj \\[refactor-nrepl\\ \\\"2.0.0\\\"\\] -- update-in :plugins conj \\[cider/cider-nrepl\\ \\\"0.11.0\\\"\\] -- repl :headless"))
(it "uses them in a boot project"
(expect (cider-inject-jack-in-dependencies "" "repl -s wait" "boot")
:to-equal "-i \"(require 'cider.tasks)\" -d org.clojure/tools.nrepl\\:0.2.12 -d refactor-nrepl\\:2.0.0 -d cider/cider-nrepl\\:0.11.0 cider.tasks/add-middleware -m refactor-nrepl.middleware/wrap-refactor -m cider.nrepl/cider-middleware repl -s wait"))))

(describe "cider-jack-in-auto-inject-clojure"
(it "injects `cider-minimum-clojure-version' when `cider-jack-in-auto-inject-clojure' is set to minimal"
Expand Down

0 comments on commit f9bd359

Please sign in to comment.