Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- [#4143](https://github.com/clojure-emacs/cider/pull/4143): Highlight the `#break`/`#dbg`/`#light` debugging reader tags in `clojure-ts-mode` buffers too.
- [#4117](https://github.com/clojure-emacs/cider/pull/4117): Add `cider-use-completing-read-for-symbol` (off by default): when enabled, symbol prompts (e.g. `cider-doc`, `cider-find-var`) read through `completing-read` over a lazy, runtime-backed collection, so they work with `completing-read` UIs (Vertico, Ivy, Helm) and annotate candidates with their type and namespace.
- [#4129](https://github.com/clojure-emacs/cider/pull/4129): Render completion annotations as an aligned type/namespace column (via an `affixation-function`) in UIs that support it, such as the built-in `*Completions*`, Corfu and Vertico.
- [#3839](https://github.com/clojure-emacs/cider/pull/3839): Add jack-in support for ClojureCLR.

### Changes

Expand Down
1 change: 1 addition & 0 deletions doc/modules/ROOT/pages/basics/up_and_running.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ The following Clojure build tools are supported so far
- kbd:[M-3 C-c C-x j u] jack-in using babashka.
- kbd:[M-4 C-c C-x j u] jack-in using nbb.
- kbd:[M-5 C-c C-x j u] jack-in using basilisp.
- kbd:[M-6 C-c C-x j u] jack-in using ClojureCLR.

Here is an example of how to bind kbd:[F12] for quickly bringing up a
babashka REPL:
Expand Down
13 changes: 0 additions & 13 deletions doc/modules/ROOT/pages/caveats.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,6 @@ loaded. As a workaround remove

from your Emacs config.

== ClojureCLR Support

CIDER currently has very basic support for ClojureCLR (via Arcadia's nREPL server). The reasons for this are the following:

* nREPL itself runs only on the JVM (because it leverages Java APIs
internally). There's an
https://github.com/clojure/clr.tools.nrepl[nREPL port for ClojureCLR], but
it's not actively maintained and it doesn't behave like the Clojure nREPL.
* `cider-nrepl` uses a lot of Java code internally itself.

Those issues are not insurmountable, but are beyond the scope of our current roadmap.
If someone would like to tackle them, we'd be happy to provide assistance.

== Injecting dependencies and Leiningen pedantic: abort mode

Because injection currently creates an override of the nREPL dependency that
Expand Down
21 changes: 12 additions & 9 deletions doc/modules/ROOT/pages/platforms/clojureclr.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,30 @@

== Current Status

ClojureCLR on CIDER is not great due to the lack of a fully-functional nREPL
server for ClojureCLR. There are currently two options:
You will get basic CIDER functionality with ClojureCLR. Two nREPL server options:

- https://github.com/clojure/clr.tools.nrepl[clr.tools.nrepl]: A direct (but incomplete) port of the reference Clojure nREPL server.
- https://github.com/arcadia-unity/Arcadia/blob/master/Editor/NRepl.cs[Arcadia's nREPL]: A basic, but working nREPL implementation in C#.
- https://github.com/clojure/clr.tools.nrepl[clr.tools.nrepl]: currently a port of https://github.com/babashka/babashka.nrepl[babashka.nrepl] to ClojureCLR.
- https://github.com/clojure/clr.tools.nrepl/tree/master/partial-nrepl-nrepl-port[port of nrepl/nrepl]: A non-working, work-in-progress port of nrepl/nrepl, which may
ultimately better integrate with CIDER once CIDER's middleware (cider-nrepl) is also adapted/ported.

If you need to use CIDER with ClojureCLR today Arcadia's nREPL is your only usable option. That being said - `clr.tools.nrepl` is a much
more sophisticated project and ideally we should get it over to the finish line.
CIDER's support is basic because `cider-nrepl`, the middleware behind most of
CIDER's features, uses a lot of Java internally and would need to be ported to
ClojureCLR like any other Clojure library.

Alternatives to using CIDER with ClojureCLR include https://github.com/clojure-emacs/inf-clojure[inf-clojure] and https://github.com/nrepl/neat[neat].

== Usage

NOTE: Contributions welcome!

As `cider-jack-in` doesn't support ClojureCLR projects out-of-the-box currently, you'll need to start an nREPL server externally and
connect to it with `cider-connect`.
`cider-jack-in-universal` will jack into a clr.tools.nrepl server as long as a `deps-clr.edn` file
exists in the project directory, otherwise you may call `cider-jack-in-universal` with prefix
argument 6, by either `M-6` or `C-u 6` followed by `M-x cider-jack-in-universal`.

== Plans

In an ideal world we'll achieve the following objectives:

- out-of-the-box ClojureCLR support with `cider-jack-in`
- feature parity between Clojure's nREPL implementation and `clr.tools.nrepl` (the project can use some help)
- adapting `cider-nrepl` for ClojureCLR (some of its codebase is JVM-specific)

Expand Down
63 changes: 63 additions & 0 deletions lisp/cider-jack-in.el
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,30 @@ By default we favor the project-specific shadow-cljs over the system-wide."
:safe #'stringp
:package-version '(cider . "1.14.0"))

(defcustom cider-clojure-clr-cli-command
"cljr"
"The command used to execute ClojureCLR."
:type 'string
:group 'cider
:safe #'stringp
:package-version '(cider . "2.0.1"))
Comment thread
rene-descartes2021 marked this conversation as resolved.

(defcustom cider-clojure-clr-cli-parameters
"-X clojure.tools.nrepl/start-server!"
"Params passed to ClojureCLR to start an nREPL server via `cider-jack-in'."
:type 'string
:group 'cider
:safe #'stringp
:package-version '(cider . "2.0.1"))

;; Clojure git deps require :git/sha even when :git/tag is set, just do full SHA
(defcustom cider-clojure-clr-cli-nrepl-sha "a6bf822a5f72ec613f703eaf95420758591f2437"
"The version of clr.tools.nrepl injected on jack-in with ClojureCLR."
:type 'string
:group 'cider
:safe #'stringp
:package-version '(cider . "2.0.1"))


;;; Jack-in defaults and toggles

Expand Down Expand Up @@ -668,6 +692,30 @@ Does so by concatenating PARAMS and DEPENDENCIES."
" "
params)))

(defun cider-clojure-clr-cli-jack-in-dependencies (params dependencies &optional command)
"Create ClojureCLR clr.core.cli jack-in dependencies.
Does so by concatenating DEPENDENCIES, and PARAMS into a
suitable `cljr` invocation and quoting, also accounting for COMMAND if
provided."
(let* ((all-deps (thread-last dependencies
(cider--dedupe-deps)
(seq-map (lambda (dep)
(if (listp (cadr dep))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only caller passes a (lib sha) pair, so the listp branch is dead code carried over from the clojure-cli version. Something like this does the same job and also drops the doubled space before the params:

(let* ((deps (format "{:deps {%s}}"
                     (mapconcat (lambda (dep)
                                  (format "%s {:git/sha \"%s\"}" (car dep) (cadr dep)))
                                (cider--dedupe-deps dependencies)
                                " ")))
       (deps-quoted (cider--shell-quote-argument deps command)))
  (if params
      (format "-Sdeps %s %s" deps-quoted params)
    (format "-Sdeps %s" deps-quoted)))

(format "%s {%s}"
(car dep)
(seq-reduce
(lambda (acc v)
(concat acc (format " :%s \"%s\" " (car v) (cdr v))))
(cadr dep)
""))
(format "%s {:git/sha \"%s\"}" (car dep) (cadr dep)))))))
(deps (format "{:deps {%s}}"
(string-join all-deps " ")))
(deps-quoted (cider--shell-quote-argument deps command)))
(format "-Sdeps %s %s"
deps-quoted
(if params (format " %s" params) ""))))

(defun cider-add-clojure-dependencies-maybe (dependencies)
"Return DEPENDENCIES with an added Clojure dependency if requested.
See also `cider-jack-in-auto-inject-clojure'."
Expand Down Expand Up @@ -727,6 +775,14 @@ COMMAND is the resolved jack-in command, used to handle PowerShell quoting."
(cider-add-clojure-dependencies-maybe cider-jack-in-dependencies)
(cider-jack-in-normalized-nrepl-middlewares)))

(defun cider--clojure-clr-cli-inject-deps (params _project-type command)
"Inject CIDER deps into PARAMS for a ClojureCLR CLI project.
COMMAND is the resolved jack-in command, used to handle PowerShell quoting."
(cider-clojure-clr-cli-jack-in-dependencies
params
`(("io.github.clojure/clr.tools.nrepl" ,cider-clojure-clr-cli-nrepl-sha))
command))

(defun cider-inject-jack-in-dependencies (params project-type &optional command)
"Return PARAMS with injected REPL dependencies for PROJECT-TYPE.
Looks up the tool's :inject-fn in `cider-jack-in-tools' and calls it with
Expand Down Expand Up @@ -894,6 +950,13 @@ Throws an error if PROJECT-TYPE is unknown."
:project-files '("basilisp.edn")
:dispatch-prefix-arg 5)

(cider-register-jack-in-tool 'clojure-clr-cli

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deps-clr.edn also needs to go into cider-build-tool-files in cider-util.el, otherwise cider-project-dir won't find the root of a CLR-only project. And clojure-clr-cli should be added to the :type choices of cider-jack-in-default and cider-preferred-build-tool so it shows up in customize.

:command-var 'cider-clojure-clr-cli-command
:params-var 'cider-clojure-clr-cli-parameters
:project-files '("deps-clr.edn")
:inject-fn #'cider--clojure-clr-cli-inject-deps
:dispatch-prefix-arg 6)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no tests yet. The cheap ones that would cover this, all in test/cider-jack-in-tests.el:

  • add clojure-clr-cli to the tool list in the cider-jack-in-tools registry spec
  • add deps-clr.edn to the faked files in the cider--identify-buildtools-present spec and expect clojure-clr-cli in the result
  • a spec for the deps string next to the clojure-cli one, e.g.
(describe "cider-clojure-clr-cli-jack-in-dependencies"
  (it "produces a -Sdeps invocation with the clr.tools.nrepl git dep"
    (let ((result (cider-clojure-clr-cli-jack-in-dependencies
                   nil '(("io.github.clojure/clr.tools.nrepl" "abc123")))))
      (expect result :to-match "\\`-Sdeps ")
      (expect result :to-match "io.github.clojure/clr.tools.nrepl")
      (expect result :to-match ":git/sha")
      (expect result :to-match "abc123")))
  (it "appends params after the deps"
    (expect (cider-clojure-clr-cli-jack-in-dependencies
             "-X clojure.tools.nrepl/start-server!"
             '(("io.github.clojure/clr.tools.nrepl" "abc123")))
            :to-match "-X clojure.tools.nrepl/start-server!\\'")))
  • one for cider-inject-jack-in-dependencies with 'clojure-clr-cli, checking that cider-clojure-clr-cli-nrepl-sha ends up in the output



;;; ClojureScript jack-in helpers

Expand Down