Skip to content

Commit 7bcdabc

Browse files
ikappakibbatsov
authored andcommitted
Support nbb as native cljs repl
If no repl init form is given, logic assumes it is repl is cljs from the start.
1 parent 5631d60 commit 7bcdabc

File tree

3 files changed

+146
-37
lines changed

3 files changed

+146
-37
lines changed

cider.el

Lines changed: 86 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,27 @@ By default we favor the project-specific shadow-cljs over the system-wide."
230230
:safe #'stringp
231231
:package-version '(cider . "1.2.0"))
232232

233+
(defcustom cider-nbb-command
234+
"nbb"
235+
"The command used to execute nbb."
236+
:type 'string
237+
:safe #'stringp
238+
:package-version '(cider . "1.2.0"))
239+
240+
(defcustom cider-nbb-global-options
241+
nil
242+
"Command line options used to execute nbb."
243+
:type 'string
244+
:safe #'stringp
245+
:package-version '(cider . "1.2.0"))
246+
247+
(defcustom cider-nbb-parameters
248+
"nrepl-server"
249+
"Params passed to nbb to start an nREPL server via `cider-jack-in'."
250+
:type 'string
251+
:safe #'stringp
252+
:package-version '(cider . "1.2.0"))
253+
233254
(defcustom cider-jack-in-default (if (executable-find "clojure") 'clojure-cli 'lein)
234255
"The default tool to use when doing `cider-jack-in' outside a project.
235256
This value will only be consulted when no identifying file types, i.e.
@@ -243,7 +264,8 @@ to Leiningen."
243264
(const clojure-cli)
244265
(const shadow-cljs)
245266
(const gradle)
246-
(const babashka))
267+
(const babashka)
268+
(const nbb))
247269
:safe #'symbolp
248270
:package-version '(cider . "0.9.0"))
249271

@@ -262,6 +284,7 @@ command when there is no ambiguity."
262284
(const shadow-cljs)
263285
(const gradle)
264286
(const babashka)
287+
(const nbb)
265288
(const :tag "Always ask" nil))
266289
:safe #'symbolp
267290
:package-version '(cider . "0.13.0"))
@@ -337,6 +360,7 @@ Sub-match 1 must be the project path.")
337360
('babashka cider-babashka-command)
338361
('shadow-cljs cider-shadow-cljs-command)
339362
('gradle cider-gradle-command)
363+
('nbb cider-nbb-command)
340364
(_ (user-error "Unsupported project type `%S'" project-type))))
341365

342366
(defun cider-jack-in-resolve-command (project-type)
@@ -357,6 +381,7 @@ Throws an error if PROJECT-TYPE is unknown."
357381
;; relative path like "./gradlew" use locate file instead of checking
358382
;; the exec-path
359383
('gradle (cider--resolve-project-command cider-gradle-command))
384+
('nbb (cider--resolve-command cider-nbb-command))
360385
(_ (user-error "Unsupported project type `%S'" project-type))))
361386

362387
(defun cider-jack-in-global-options (project-type)
@@ -368,6 +393,7 @@ Throws an error if PROJECT-TYPE is unknown."
368393
('babashka cider-babashka-global-options)
369394
('shadow-cljs cider-shadow-cljs-global-options)
370395
('gradle cider-gradle-global-options)
396+
('nbb cider-nbb-global-options)
371397
(_ (user-error "Unsupported project type `%S'" project-type))))
372398

373399
(defun cider-jack-in-params (project-type)
@@ -383,6 +409,7 @@ Throws an error if PROJECT-TYPE is unknown."
383409
('babashka cider-babashka-parameters)
384410
('shadow-cljs cider-shadow-cljs-parameters)
385411
('gradle cider-gradle-parameters)
412+
('nbb cider-nbb-parameters)
386413
(_ (user-error "Unsupported project type `%S'" project-type))))
387414

388415

@@ -766,6 +793,10 @@ dependencies."
766793
(cider-add-clojure-dependencies-maybe
767794
cider-jack-in-dependencies)
768795
(cider-jack-in-normalized-nrepl-middlewares)))
796+
('nbb (concat
797+
global-opts
798+
(unless (seq-empty-p global-opts) " ")
799+
params))
769800
(_ (error "Unsupported project type `%S'" project-type))))
770801

771802

@@ -993,30 +1024,35 @@ The supplied string will be wrapped in a do form if needed."
9931024
(def config (edn/read-string (slurp (io/file \"build.edn\"))))
9941025
(apply cider.piggieback/cljs-repl (krell.repl/repl-env) (mapcat identity config))"
9951026
cider-check-krell-requirements)
1027+
;; native cljs repl, no form required.
1028+
(nbb)
9961029
(custom cider-custom-cljs-repl-init-form nil))
9971030
"A list of supported ClojureScript REPLs.
9981031
999-
For each one we have its name, the form we need to evaluate in a Clojure
1000-
REPL to start the ClojureScript REPL and functions to verify their requirements.
1032+
For each one we have its name, and then, if the repl is not a native
1033+
ClojureScript REPL, the form we need to evaluate in a Clojure REPL to
1034+
switch to the ClojureScript REPL and functions to verify their
1035+
requirements.
10011036
1002-
The form should be either a string or a function producing a string.")
1037+
The form, if any, should be either a string or a function producing a
1038+
string.")
10031039

1004-
(defun cider-register-cljs-repl-type (type init-form &optional requirements-fn)
1040+
(defun cider-register-cljs-repl-type (type &optional init-form requirements-fn)
10051041
"Register a new ClojureScript REPL type.
10061042
10071043
Types are defined by the following:
10081044
10091045
- TYPE - symbol identifier that will be used to refer to the REPL type
1010-
- INIT-FORM - string or function (symbol) producing string
1046+
- INIT-FORM - (optional) string or function (symbol) producing string
10111047
- REQUIREMENTS-FN - function to check whether the REPL can be started.
10121048
This param is optional.
10131049
10141050
All this function does is modifying `cider-cljs-repl-types'.
10151051
It's intended to be used in your Emacs config."
10161052
(unless (symbolp type)
10171053
(user-error "The REPL type must be a symbol"))
1018-
(unless (or (stringp init-form) (symbolp init-form))
1019-
(user-error "The init form must be a string or a symbol referring to a function"))
1054+
(unless (or (null init-form) (stringp init-form) (symbolp init-form))
1055+
(user-error "The init form must be a string or a symbol referring to a function or nil"))
10201056
(unless (or (null requirements-fn) (symbolp requirements-fn))
10211057
(user-error "The requirements-fn must be a symbol referring to a function"))
10221058
(add-to-list 'cider-cljs-repl-types (list type init-form requirements-fn)))
@@ -1036,6 +1072,7 @@ you're working on."
10361072
(const :tag "Shadow" shadow)
10371073
(const :tag "Shadow w/o Server" shadow-select)
10381074
(const :tag "Krell" krell)
1075+
(const :tag "Nbb" nbb)
10391076
(const :tag "Custom" custom))
10401077
:safe #'symbolp
10411078
:package-version '(cider . "0.17.0"))
@@ -1054,15 +1091,16 @@ DEFAULT is the default ClojureScript REPL to offer in completion."
10541091
(or default (car cider--select-cljs-repl-history))))))
10551092

10561093
(defun cider-cljs-repl-form (repl-type)
1057-
"Get the cljs REPL form for REPL-TYPE."
1058-
(if-let* ((repl-form (cadr (seq-find
1059-
(lambda (entry)
1060-
(eq (car entry) repl-type))
1061-
cider-cljs-repl-types))))
1062-
;; repl-form can be either a string or a function producing a string
1063-
(if (symbolp repl-form)
1064-
(funcall repl-form)
1065-
repl-form)
1094+
"Get the cljs REPL form for REPL-TYPE, if any."
1095+
(if-let* ((repl-type-info (seq-find
1096+
(lambda (entry)
1097+
(eq (car entry) repl-type))
1098+
cider-cljs-repl-types)))
1099+
(when-let ((repl-form (cadr repl-type-info)))
1100+
;; repl-form can be either a string or a function producing a string
1101+
(if (symbolp repl-form)
1102+
(funcall repl-form)
1103+
repl-form))
10661104
(user-error "No ClojureScript REPL type %s found. Please make sure that `cider-cljs-repl-types' has an entry for it" repl-type)))
10671105

10681106
(defun cider-verify-cljs-repl-requirements (&optional repl-type)
@@ -1258,7 +1296,6 @@ server buffer, in which case a new session for that server is created."
12581296
(cider--update-cljs-type)
12591297
(cider--update-cljs-init-function)
12601298
(plist-put :session-name ses-name)
1261-
(plist-put :repl-type 'cljs)
12621299
(plist-put :cider-repl-cljs-upgrade-pending t)))))
12631300

12641301
;;;###autoload
@@ -1293,7 +1330,6 @@ parameters regardless of their supplied or default values."
12931330
(cider--update-cljs-type)
12941331
(cider--update-cljs-init-function)
12951332
(plist-put :session-name nil)
1296-
(plist-put :repl-type 'cljs)
12971333
(plist-put :cider-repl-cljs-upgrade-pending t))))
12981334

12991335
;;;###autoload
@@ -1466,27 +1502,39 @@ non-nil, don't start if ClojureScript requirements are not met."
14661502
(plist-put :port (cdr endpoint)))))))
14671503

14681504
(defun cider--update-cljs-init-function (params)
1469-
"Update PARAMS :repl-init-function for cljs connections."
1505+
"Update repl type and any init PARAMS for cljs connections.
1506+
1507+
The updated params are:
1508+
1509+
:cljs-type 'cljs if it is a cljs REPL, or 'pending-cljs when the init form
1510+
is required to be sent to the REPL to switch over to cljs.
1511+
1512+
:repl-init-form The form that can switch the REPL over to cljs.
1513+
1514+
:repl-init-function The fn that switches the REPL over to cljs."
14701515
(with-current-buffer (or (plist-get params :--context-buffer)
14711516
(current-buffer))
14721517
(let* ((cljs-type (plist-get params :cljs-repl-type))
14731518
(repl-init-form (cider-cljs-repl-form cljs-type)))
1474-
(thread-first
1475-
params
1476-
(plist-put :repl-init-function
1477-
(lambda ()
1478-
(cider--check-cljs cljs-type)
1479-
;; FIXME: ideally this should be done in the state handler
1480-
(setq-local cider-cljs-repl-type cljs-type)
1481-
(cider-nrepl-send-request
1482-
(list "op" "eval"
1483-
"ns" (cider-current-ns)
1484-
"code" repl-init-form)
1485-
(cider-repl-handler (current-buffer)))
1486-
(when (and (buffer-live-p nrepl-server-buffer)
1487-
cider-offer-to-open-cljs-app-in-browser)
1488-
(cider--offer-to-open-app-in-browser nrepl-server-buffer))))
1489-
(plist-put :repl-init-form repl-init-form)))))
1519+
(if (null repl-init-form)
1520+
(plist-put params :repl-type 'cljs)
1521+
(thread-first
1522+
params
1523+
(plist-put :repl-init-function
1524+
(lambda ()
1525+
(cider--check-cljs cljs-type)
1526+
;; FIXME: ideally this should be done in the state handler
1527+
(setq-local cider-cljs-repl-type cljs-type)
1528+
(cider-nrepl-send-request
1529+
(list "op" "eval"
1530+
"ns" (cider-current-ns)
1531+
"code" repl-init-form)
1532+
(cider-repl-handler (current-buffer)))
1533+
(when (and (buffer-live-p nrepl-server-buffer)
1534+
cider-offer-to-open-cljs-app-in-browser)
1535+
(cider--offer-to-open-app-in-browser nrepl-server-buffer))))
1536+
(plist-put :repl-init-form repl-init-form)
1537+
(plist-put :repl-type 'pending-cljs))))))
14901538

14911539
(defun cider--check-existing-session (params)
14921540
"Ask for confirmation if a session with similar PARAMS already exists.
@@ -1666,7 +1714,8 @@ PROJECT-DIR defaults to current project."
16661714
(babashka . "bb.edn")
16671715
(shadow-cljs . "shadow-cljs.edn")
16681716
(gradle . "build.gradle")
1669-
(gradle . "build.gradle.kts"))))
1717+
(gradle . "build.gradle.kts")
1718+
(nbb . "package.json"))))
16701719
(delq nil
16711720
(mapcar (lambda (candidate)
16721721
(when (file-exists-p (cdr candidate))

test/cider-tests.el

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,49 @@
579579
(expect (cider--resolve-project-command "command")
580580
:to-equal (shell-quote-argument "/bin/command"))))
581581

582+
(describe "cider-connect-sibling-cljs"
583+
:var (-cider-cljs-repl-types bu-cider-shadow-default-options)
584+
(before-all
585+
(setq -cider-cljs-repl-types cider-cljs-repl-types
586+
-cider-shadow-default-options cider-shadow-default-options))
587+
(after-each
588+
(setq cider-cljs-repl-types -cider-cljs-repl-types
589+
cider-shadow-default-options -cider-shadow-default-options))
590+
591+
(describe "sets nrepl client local vars correctly"
592+
(it "for nbb project"
593+
(let* ((server-process (nrepl-start-mock-server-process))
594+
(server-buffer (process-buffer server-process))
595+
(client-buffer (cider-connect-sibling-cljs '(:cljs-repl-type nbb) server-buffer)))
596+
(expect (buffer-local-value 'cider-repl-type client-buffer) :to-equal 'cljs)
597+
(expect (buffer-local-value 'cider-repl-init-function client-buffer) :to-be nil)
598+
(delete-process (get-buffer-process client-buffer))))
599+
(it "for shadow project"
600+
(setq cider-shadow-default-options "a-shadow-alias")
601+
(let* ((server-process (nrepl-start-mock-server-process))
602+
(server-buffer (process-buffer server-process))
603+
(client-buffer (cider-connect-sibling-cljs '(:cljs-repl-type shadow) server-buffer)))
604+
(expect (buffer-local-value 'cider-repl-type client-buffer) :to-equal 'pending-cljs)
605+
(expect (buffer-local-value 'cider-repl-init-function client-buffer) :not :to-be nil)
606+
(delete-process (get-buffer-process client-buffer))))
607+
(it "for a custom cljs REPL type project"
608+
(cider-register-cljs-repl-type 'native-cljs)
609+
(let* ((server-process (nrepl-start-mock-server-process))
610+
(server-buffer (process-buffer server-process))
611+
(client-buffer (cider-connect-sibling-cljs '(:cljs-repl-type native-cljs)
612+
server-buffer)))
613+
(expect (buffer-local-value 'cider-repl-type client-buffer) :to-equal 'cljs)
614+
(delete-process (get-buffer-process client-buffer))))
615+
(it "for a custom REPL type project that needs to switch to cljs"
616+
(cider-register-cljs-repl-type 'not-cljs-initially "(form-to-switch-to-cljs-repl)")
617+
(let* ((server-process (nrepl-start-mock-server-process))
618+
(server-buffer (process-buffer server-process))
619+
(client-buffer (cider-connect-sibling-cljs '(:cljs-repl-type not-cljs-initially)
620+
server-buffer)))
621+
(expect (buffer-local-value 'cider-repl-type client-buffer) :to-equal 'pending-cljs)
622+
(expect (buffer-local-value 'cider-repl-init-function client-buffer) :not :to-be nil)
623+
(delete-process (get-buffer-process client-buffer))))))
624+
582625
(provide 'cider-tests)
583626

584627
;;; cider-tests.el ends here

test/utils/nrepl-tests-utils.el

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
;;; Code:
2727

28+
(require 'nrepl-client)
29+
2830
(defmacro nrepl-tests-log/init! (enable? name log-filename &optional clean?)
2931
"Create a NAME/log! elisp function to log messages to LOG-FILENAME,
3032
taking the same arguments as `message'. Messages are appended to
@@ -97,5 +99,20 @@ calling process."
9799
;; invoke mock server
98100
" -l test/nrepl-server-mock.el -f nrepl-server-mock-start"))
99101

102+
(defun nrepl-start-mock-server-process ()
103+
"Start and return the mock nrepl server process."
104+
(let* ((up? nil)
105+
(server-process (nrepl-start-server-process
106+
default-directory
107+
(nrepl-server-mock-invocation-string)
108+
(lambda (server-buffer)
109+
(setq up? t))))
110+
server-buffer (process-buffer server-process))
111+
;; server has reported its endpoint
112+
(nrepl-tests-sleep-until 2 up?)
113+
server-process))
100114

101115
(provide 'nrepl-tests-utils)
116+
117+
;;; nrepl-tests-utils.el ends here
118+

0 commit comments

Comments
 (0)