Skip to content
Closed
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 @@ -4,6 +4,7 @@

### New features

* [#2656](https://github.com/clojure-emacs/cider/issues/2656): Base64 encode clojure command and arguments on jack-in when `cider-clojure-cli-command` is `"powershell"` to avoid escaping issues. If no `clojure` command is found on Windows `cider-clojure-cli-command` defaults to `"powershell"`.
* Allow editing of jack in command with prefix or when `cider-edit-jack-in-command` is truthy.
* New defcustom `cider-repl-require-ns-on-set`: Set it to make cider require the namespace before setting it, when calling `cider-repl-set-ns`.
* [#2611](https://github.com/clojure-emacs/cider/issues/2611): Add `eval`-based classpath lookup fallback. It's used when cider-nrepl is not present.
Expand Down
21 changes: 17 additions & 4 deletions cider.el
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,14 @@ version from the CIDER package or library.")
:package-version '(cider . "0.9.0"))

(defcustom cider-clojure-cli-command
"clojure"
(if (and (eq system-type 'windows-nt)
(null (executable-find "clojure")))
"powershell"
"clojure")
"The command used to execute clojure with tools.deps (requires Clojure 1.9+).
Don't use clj here, as it doesn't work when spawned from Emacs due to
it using rlwrap."
Don't use clj here, as it doesn't work when spawned from Emacs due to it
using rlwrap. If on Windows and no \"clojure\" executable is found we
default to \"powershell\"."
:type 'string
:group 'cider
:safe #'stringp
Expand Down Expand Up @@ -1184,6 +1188,13 @@ non-nil, don't start if ClojureScript requirements are not met."
:safe #'booleanp
:version '(cider . "0.22.0"))

(defun cider--powershell-encode-command (cmd-params)
"Base64 encode the powershell command and jack-in CMD-PARAMS for clojure-cli."
(let* ((quoted-params (replace-regexp-in-string "\"" "\"\"" cmd-params))
(command (format "clojure %s" quoted-params))
(utf-16le-command (encode-coding-string command 'utf-16le)))
(format "-encodedCommand %s" (base64-encode-string utf-16le-command t))))

(defun cider--update-jack-in-cmd (params)
"Update :jack-in-cmd key in PARAMS."
(let* ((params (cider--update-do-prompt params))
Expand All @@ -1209,7 +1220,9 @@ non-nil, don't start if ClojureScript requirements are not met."
(and (null project-dir)
(eq cider-allow-jack-in-without-project 'warn)
(y-or-n-p "Are you sure you want to run `cider-jack-in' without a Clojure project? ")))
(let ((cmd (format "%s %s" command-resolved cmd-params)))
(let ((cmd (format "%s %s" command-resolved (if (string-equal command "powershell")
(cider--powershell-encode-command cmd-params)
cmd-params))))
(plist-put params :jack-in-cmd (if (or cider-edit-jack-in-command
(plist-get params :edit-jack-in-command))
(read-string "jack-in command: " cmd t)
Expand Down
6 changes: 6 additions & 0 deletions doc/modules/ROOT/pages/basics/up_and_running.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ these are passed to the command directly, in first position
usually task names and their parameters (e.g., `dev` for launching
boot's dev task instead of the standard `repl -s wait`).

To use `cider-jack-in` with `tools.deps` on Windows set the
`cider-clojure-cli-command` to `"powershell"`. This happens by default
if you are on Windows and no `clojure` executable is found. Using
`"powershell"` will Base64 encode the clojure launch command before
passing it to PowerShell and avoids shell-escaping issues.

== Connect to a Running nREPL Server

If you have an nREPL server already running, CIDER can connect to
Expand Down
28 changes: 28 additions & 0 deletions test/cider-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,34 @@
(expect (cider--shadow-parse-builds (parseedn-read-str "[oops]"))
:to-equal '(browser-repl node-repl))))

(describe "cider--powershell-encode-command"
(it "base64 encodes command and parameters"
(expect (cider--powershell-encode-command "cmd-params")
:to-equal (concat "-encodedCommand "
;; Eval to reproduce reference string below: (base64-encode-string (encode-coding-string "clojure cmd-params" 'utf-16le) t)
"YwBsAG8AagB1AHIAZQAgAGMAbQBkAC0AcABhAHIAYQBtAHMA")))
(it "escapes double quotes by repeating them"
(expect (cider--powershell-encode-command "\"cmd-params\"")
:to-equal (concat "-encodedCommand "
;; Eval to reproduce reference string below: (base64-encode-string (encode-coding-string "clojure \"\"cmd-params\"\"" 'utf-16le) t)
"YwBsAG8AagB1AHIAZQAgACIAIgBjAG0AZAAtAHAAYQByAGEAbQBzACIAIgA="))))

(describe "cider--update-jack-in-cmd"
(describe "when 'clojure-cli project type and \"powershell\" command"
(it "returns a jack-in command using encodedCommand option"
(setq-local cider-clojure-cli-command "powershell")
(setq-local cider-inject-dependencies-at-jack-in nil)
(setq-local cider-allow-jack-in-without-project t)
(setq-local cider-edit-jack-in-command nil)
(spy-on 'cider-project-type :and-return-value 'clojure-cli)
(spy-on 'cider-jack-in-resolve-command :and-return-value "resolved-powershell")
(spy-on 'cider-jack-in-global-options)
(spy-on 'cider-jack-in-params :and-return-value "\"cmd-params\"")
(expect (plist-get (cider--update-jack-in-cmd nil) :jack-in-cmd)
:to-equal (concat "resolved-powershell -encodedCommand "
;; Eval to reproduce reference string below: (base64-encode-string (encode-coding-string "clojure \"\"cmd-params\"\"" 'utf-16le) t)
"YwBsAG8AagB1AHIAZQAgACIAIgBjAG0AZAAtAHAAYQByAGEAbQBzACIAIgA=")))))

(defmacro with-temp-shadow-config (contents &rest body)
"Run BODY with a mocked shadow-cljs.edn project file with the CONTENTS."
`(let* ((edn-file "shadow-cljs.edn")
Expand Down