diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d0dd1171..58973240d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * [#2191](https://github.com/clojure-emacs/cider/issues/2191): Add support for jacking-in just with the `clojure` command-line tool and `tools.deps`. * Make it possible to start a Nashorn ClojureScript REPL. * [#2235](https://github.com/clojure-emacs/cider/pull/2235): Make the REPL ignore blank input rather than evaluating. +* [#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 diff --git a/cider.el b/cider.el index 79cbfa215..66b9fd466 100644 --- a/cider.el +++ b/cider.el @@ -358,17 +358,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 @@ -483,14 +526,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" (cider-clojure-jack-in-dependencies global-opts params diff --git a/test/cider-tests.el b/test/cider-tests.el index 54e8a2853..179fcd71f 100644 --- a/test/cider-tests.el +++ b/test/cider-tests.el @@ -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"