Skip to content

nbb nrepl-server: can't send expressions from .cljs file #3061

Closed
@borkdude

Description

@borkdude

Expected behavior

I expect to be able to send expressions from a .cljs file in clojurescript-mode to an nbb nrepl server.

Actual behavior

Nothing happens until I activate clojure-mode in a .cljs file.

Steps to reproduce the problem

npm install -g nbb
nbb nrepl-server :port 1338

Then cider-connect from emacs to that server and try to evaluate some expressions from a .cljs file:

foo.cljs:

(defn version []
  js/process.version)

(version)

(require '["fs" :as fs])

(fs/existsSync "README.md")
(fs/existsSync "README2.md")

(require '[clojure.string :as str])

(first (str/split js/process.env.PATH ":"))

Environment & Version information

CIDER version information

Include here the version string displayed when
CIDER's REPL is launched. Here's an example:

;; Connected to nREPL server - nrepl://localhost:1337
;; CIDER 1.2.0snapshot (package: 20210914.1315)

Emacs version

27.2

Operating system

macOS

Activity

bbatsov

bbatsov commented on Oct 2, 2021

@bbatsov
Member

Do you have the same problem with cider-connect-cljs? I'm guess "yes" as this still assumes the Clojure nREPL server, but I'm asking just in case.

borkdude

borkdude commented on Oct 2, 2021

@borkdude
Author

With cider-connect-cljs it's the same + the clojure-mode workaround doesn't work there.

bbatsov

bbatsov commented on Oct 2, 2021

@bbatsov
Member

Got it.

bbatsov

bbatsov commented on Oct 29, 2021

@bbatsov
Member

I finally looked at this and the problem is that when you use cider-connect this is actually cider-connect-clj, which sets the connection type automatically to Clojure. Then if you try to evaluate something from a cljs file CIDER is looking for a cljs REPL, which it can't find. That's why switching to clojure-mode fixed this. I'll have to think a bit how to best approach this, but it shouldn't be hard to fix.

I guess we'll have to add some simple detection that we're connected to nbb and just skip the regular cljs init sequence (as for all other REPLs first we started a Clojure connection that gets upgraded to ClojureScript by evaluating a bit of "magic" code). Clearly, that's not need for a native ClojureScript REPL like nbb.

borkdude

borkdude commented on Oct 30, 2021

@borkdude
Author

Thanks for looking into this.

benjamin-asdf

benjamin-asdf commented on Jan 15, 2022

@benjamin-asdf
Contributor

with cider 318fe6878d8bedf5db9dfa649dedb45d72b2e7ee
I try

  • run nbb nrepl-server :port 1338
  • cider-connect-clj
  • then cider tries to call some classpath functions or something that are not there
    falls back to reading from minibuffer

output from nbb server:


Connection accepted
request {:op "clone", :id "1"}
response {"new-session" "a70ec1ab-299e-494f-a6d9-c83c54e36511", "status" ["done"], 
"id" "1"}
request {:op "clone", :id "2"}
response {"new-session" "e4b9cc25-91a2-48b5-bd24-b13dbccc6035", "status" ["done"], 
"id" "2"}
request {:op "describe", :session "a70ec1ab-299e-494f-a6d9-c83c54e36511", :id "3"}
response {"versions" {"nbb-nrepl" {"major" "TODO", "version-string" "TODO"}, "node"
 {"major" "v17", "minor" "3", "incremental" "0", "version-string" "v17.3.0"}}, "aux
" {}, "ops" {"eval" {}, "describe" {}, "clone" {}, "close" {}, "load-file" {}}, "st
atus" ["done"], "id" "3", "session" "a70ec1ab-299e-494f-a6d9-c83c54e36511"}
request {:nrepl.middleware.print/buffer-size 4096, :file "*cider-repl clojure/nbb-d
ropdown:localhost:1338(clj)*", :nrepl.middleware.print/quota 1048576, :nrepl.middle
ware.print/print "cider.nrepl.pprint/pprint", :op "eval", :column 1, :line 3, :id "
4", :code "(clojure.core/apply clojure.core/require clojure.main/repl-requires)", :
inhibit-cider-middleware "true", :nrepl.middleware.print/stream? "1", :nrepl.middle
ware.print/options {:right-margin 70}, :session "a70ec1ab-299e-494f-a6d9-c83c54e365
11"}
response {"err" "Could not resolve symbol: clojure.main/repl-requires\n", "id" "4",
 "session" "a70ec1ab-299e-494f-a6d9-c83c54e36511"}
response {"ex" "#error {:message \"Could not resolve symbol: clojure.main/repl-requ
ires\", :data {:type :sci/error, :line 1, :column 42, :file nil, :phase \"analysis\
"}}", "ns" "user", "status" ["done"], "id" "4", "session" "a70ec1ab-299e-494f-a6d9-
c83c54e36511"}
request {:op "eval", :code "(seq (.split (System/getProperty \"java.class.path\") \
":\"))", :session "e4b9cc25-91a2-48b5-bd24-b13dbccc6035", :id "5"}
response {"err" "Could not resolve symbol: System/getProperty\n", "id" "5", "sessio
n" "e4b9cc25-91a2-48b5-bd24-b13dbccc6035"}
response {"ex" "#error {:message \"Could not resolve symbol: System/getProperty\", 
:data {:type :sci/error, :line 1, :column 15, :file nil, :phase \"analysis\"}}", "n
s" "user", "status" ["done"], "id" "5", "session" "e4b9cc25-91a2-48b5-bd24-b13dbccc
6035"}
request {:op "eval", :code "(seq (.split (System/getProperty \"java.class.path\") \
":\"))", :session "e4b9cc25-91a2-48b5-bd24-b13dbccc6035", :id "6"}
response {"err" "Could not resolve symbol: System/getProperty\n", "id" "6", "sessio
n" "e4b9cc25-91a2-48b5-bd24-b13dbccc6035"}
response {"ex" "#error {:message \"Could not resolve symbol: System/getProperty\", 
:data {:type :sci/error, :line 1, :column 15, :file nil, :phase \"analysis\"}}", "n
s" "user", "status" ["done"], "id" "6", "session" "e4b9cc25-91a2-48b5-bd24-b13dbccc
6035"}

cider-repl contents:

;; Connected to nREPL server - nrepl://localhost:1338
;; CIDER 1.3.0-snapshot (package: 1.3.0-snapshot)
Could not resolve symbol: clojure.main/repl-requires
user> 

And here is the stacktrace for the "List expression" read from minibuffer call (which feels like a bug in that situation)

Debugger entered--Lisp error: (minibuffer-quit)
  #<subr F616e6f6e796d6f75732d6c616d626461_anonymous_lambda_57>()
  read-minibuffer("Lisp expression: ")
  cider-fallback-eval:classpath()
  cider-classpath-entries()
  #f(compiled-function (system session) "Check if SESSION is a friendly session." #<bytecode -0x649c99c46adde4>)(CIDER ("clojure/nbb-dropdown:localhost:1338" #<buffer *cider-repl clojure/nbb-dropdown:localhost:1338(clj)*>))
  apply(#f(compiled-function (system session) "Check if SESSION is a friendly session." #<bytecode -0x649c99c46adde4>) CIDER ("clojure/nbb-dropdown:localhost:1338" #<buffer *cider-repl clojure/nbb-dropdown:localhost:1338(clj)*>))
  sesman-friendly-session-p(CIDER ("clojure/nbb-dropdown:localhost:1338" #<buffer *cider-repl clojure/nbb-dropdown:localhost:1338(clj)*>))
  #f(compiled-function (ses) #<bytecode 0xa02ea2209b5b91>)(("clojure/nbb-dropdown:localhost:1338" #<buffer *cider-repl clojure/nbb-dropdown:localhost:1338(clj)*>))
  #f(compiled-function (elt) #<bytecode -0x14816b7dbc015a5f>)(("clojure/nbb-dropdown:localhost:1338" #<buffer *cider-repl clojure/nbb-dropdown:localhost:1338(clj)*>))
  mapcar(#f(compiled-function (elt) #<bytecode -0x14816b7dbc015a5f>) (("clojure/support-bot:localhost:38341" #<buffer *cider-repl clojure/support-bot:localhost:38341(clj)*>) ("clojure/support-bot:localhost:7000" #<buffer *cider-repl clojure/support-bot:localhost:7000(clj)*>) ("clojure/aws-play:localhost:46141" #<buffer *cider-repl clojure/aws-play:localhost:46141(clj)*>) ("clojure/support-bot:localhost:44177" #<buffer *cider-repl clojure/support-bot:localhost:44177(clj)*>) ("clojure/support-bot:localhost:45165" #<buffer *cider-repl clojure/support-bot:localhost:45165(clj)*>) ("clojure/reply-bot:localhost:42139" #<buffer *cider-repl clojure/reply-bot:localhost:42139(clj)*>) ("clojure/nbb-dropdown:localhost:1338" #<buffer *cider-repl clojure/nbb-dropdown:localhost:1338(clj)*>)))
  #f(compiled-function #'sequence #<bytecode 0x1842db430419e5f4>)(#f(compiled-function (elt) #<bytecode -0x14816b7dbc015a5f>) (("clojure/support-bot:localhost:38341" #<buffer *cider-repl clojure/support-bot:localhost:38341(clj)*>) ("clojure/support-bot:localhost:7000" #<buffer *cider-repl clojure/support-bot:localhost:7000(clj)*>) ("clojure/aws-play:localhost:46141" #<buffer *cider-repl clojure/aws-play:localhost:46141(clj)*>) ("clojure/support-bot:localhost:44177" #<buffer *cider-repl clojure/support-bot:localhost:44177(clj)*>) ("clojure/support-bot:localhost:45165" #<buffer *cider-repl clojure/support-bot:localhost:45165(clj)*>) ("clojure/reply-bot:localhost:42139" #<buffer *cider-repl clojure/reply-bot:localhost:42139(clj)*>) ("clojure/nbb-dropdown:localhost:1338" #<buffer *cider-repl clojure/nbb-dropdown:localhost:1338(clj)*>)))
  apply(#f(compiled-function #'sequence #<bytecode 0x1842db430419e5f4>) #f(compiled-function (elt) #<bytecode -0x14816b7dbc015a5f>) (("clojure/support-bot:localhost:38341" #<buffer *cider-repl clojure/support-bot:localhost:38341(clj)*>) ("clojure/support-bot:localhost:7000" #<buffer *cider-repl clojure/support-bot:localhost:7000(clj)*>) ("clojure/aws-play:localhost:46141" #<buffer *cider-repl clojure/aws-play:localhost:46141(clj)*>) ("clojure/support-bot:localhost:44177" #<buffer *cider-repl clojure/support-bot:localhost:44177(clj)*>) ("clojure/support-bot:localhost:45165" #<buffer *cider-repl clojure/support-bot:localhost:45165(clj)*>) ("clojure/reply-bot:localhost:42139" #<buffer *cider-repl clojure/reply-bot:localhost:42139(clj)*>) ("clojure/nbb-dropdown:localhost:1338" #<buffer *cider-repl clojure/nbb-dropdown:localhost:1338(clj)*>)) nil)
  seq-map(#f(compiled-function (elt) #<bytecode -0x14816b7dbc015a5f>) (("clojure/support-bot:localhost:38341" #<buffer *cider-repl clojure/support-bot:localhost:38341(clj)*>) ("clojure/support-bot:localhost:7000" #<buffer *cider-repl clojure/support-bot:localhost:7000(clj)*>) ("clojure/aws-play:localhost:46141" #<buffer *cider-repl clojure/aws-play:localhost:46141(clj)*>) ("clojure/support-bot:localhost:44177" #<buffer *cider-repl clojure/support-bot:localhost:44177(clj)*>) ("clojure/support-bot:localhost:45165" #<buffer *cider-repl clojure/support-bot:localhost:45165(clj)*>) ("clojure/reply-bot:localhost:42139" #<buffer *cider-repl clojure/reply-bot:localhost:42139(clj)*>) ("clojure/nbb-dropdown:localhost:1338" #<buffer *cider-repl clojure/nbb-dropdown:localhost:1338(clj)*>)))
  seq-filter(#f(compiled-function (ses) #<bytecode 0xa02ea2209b5b91>) (("clojure/support-bot:localhost:38341" #<buffer *cider-repl clojure/support-bot:localhost:38341(clj)*>) ("clojure/support-bot:localhost:7000" #<buffer *cider-repl clojure/support-bot:localhost:7000(clj)*>) ("clojure/aws-play:localhost:46141" #<buffer *cider-repl clojure/aws-play:localhost:46141(clj)*>) ("clojure/support-bot:localhost:44177" #<buffer *cider-repl clojure/support-bot:localhost:44177(clj)*>) ("clojure/support-bot:localhost:45165" #<buffer *cider-repl clojure/support-bot:localhost:45165(clj)*>) ("clojure/reply-bot:localhost:42139" #<buffer *cider-repl clojure/reply-bot:localhost:42139(clj)*>) ("clojure/nbb-dropdown:localhost:1338" #<buffer *cider-repl clojure/nbb-dropdown:localhost:1338(clj)*>)))
  sesman--friendly-sessions(CIDER sort)
  sesman-current-sessions(CIDER (project))
  cider--check-existing-session((:project-dir "~/repos/clojure/nbb-dropdown/" :host "localhost" :port 1338))
  cider-connect-clj(nil)
  funcall-interactively(cider-connect-clj nil)
  command-execute(cider-connect-clj)
vxe

vxe commented on Mar 16, 2022

@vxe

any updates?

bbatsov

bbatsov commented on Mar 17, 2022

@bbatsov
Member

Had no time for this so far. The way things are going it's unlikely that I'll be able to tackle it before April/May. If someone wants to beat me to it - be my guest.

jackrusher

jackrusher commented on Apr 30, 2022

@jackrusher

(It's not just nbb, btw. I also have some "connect directly to a clojurescript REPL" stuff happening that would benefit greatly from being able to evaluate forms while in CLJS mode.)

borkdude

borkdude commented on Apr 30, 2022

@borkdude
Author

@bbatsov I'm probably going to look into this next Monday/Tuesday. Any pointers that will set me on the right track will be appreciated. As cider-connect is an alias for cider-connect-clj, where should we start? I assume we should support cider-connect-cljs instead? Or should we have a cider-connect-generic alternative that doesn't assume anything but just plays by the rules of the nREPL "spec"?

jackrusher

jackrusher commented on May 1, 2022

@jackrusher

Looking at the spec and a trace of an nREPL session between cider and a jack'd in JVM, it appears that cider wants a few non-standard ops and falls back to trying to execute JVM-specific code when they're absent. (For example, cider seems to want a stacktrace op, and falls back to calling (clojure.stacktrace/print-cause-trace *e) directly if it isn't available.

Should we discuss improving the protocol a bit?

borkdude

borkdude commented on May 1, 2022

@borkdude
Author

I think this isn't a protocol problem, it's a problem of a client that expects the nREPL server to be of a certain implementation (JVM Clojure) rather than expecting it to just talk nREPL and implement the specification. Or maybe it is this way because the protocol isn't rich or specified/documented enough?

33 remaining items

added a commit that references this issue on Dec 3, 2022
vemv

vemv commented on Sep 29, 2023

@vemv
Member

Is this issue still valid? I see commits at the bottom of the timeline so I'd guess not

cc/ @benjamin-asdf

benjamin-asdf

benjamin-asdf commented on Sep 29, 2023

@benjamin-asdf
Contributor

@vemv No I wouild say this is fixed. Cider nbb support is quite complete as far as I am aware.

vemv

vemv commented on Sep 29, 2023

@vemv
Member

Nice!

vxe

vxe commented on Oct 1, 2023

@vxe

nice work all, big achievement here

dmg46664

dmg46664 commented on Oct 2, 2023

@dmg46664

Confirmed I needed to remove the snippet. Nice one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

      Participants

      @bbatsov@jackrusher@borkdude@vemv@dmg46664

      Issue actions

        nbb nrepl-server: can't send expressions from .cljs file · Issue #3061 · clojure-emacs/cider