tpope / vim-fireplace

fireplace.vim: Clojure REPL support
https://www.vim.org/scripts/script.php?script_id=4978
1.75k stars 139 forks source link

Fireplace has problems with the Babashka nREPL #401

Open robbieh opened 2 years ago

robbieh commented 2 years ago

I can't get fireplace to work with the babashka nrepl.

> bb nrepl
Started nREPL server at 127.0.0.1:32851
For more info visit: https://book.babashka.org/#_nrepl

Fireplace seems to connect OK. I've tried using :Connect. And the nrepl confirms a connection is closed vim exits.

But trying to eval code fails:

Vim(return):E716: Key not present in Dictionary: "response, 'value', [])"
tpope commented 2 years ago

Guessing from the error message it's this line: https://github.com/tpope/vim-fireplace/blob/2e4540d62fd49523a3aefeab896a33ed6bbcb43b/autoload/fireplace.vim#L1366

You could try putting :echo json_encode(state) right above that line to see what's in that data structure.

robbieh commented 2 years ago

Here's what happens:

Vim(echo):E474: Invalid argument

Here's what I did, and wanted to show it just in case I misunderstood:

if get(state, 'ex', '') !=# ''
  let err = 'Clojure: '.state.ex
else
  echo json_encode(state)
  return get(state.history.response, 'value', [])
endif
tpope commented 2 years ago

Oh it must have function keys, try :echo state instead.

robbieh commented 2 years ago

Woooo! That did it! I hope you can make sense of this :)

{'echo': v:true, 'history': {'messages': [], 'tempfile': '/tmp/ve4jjOI/5.clj', 'ns': 'lochmess-bb-collector.main', 'code': '(ns lochmess-bb-collector.main
  (:require [babashka.fs :as fs]
            [clojure.java.io :as io]))', 'ext': 'clj', 'buffer': 1}, 'code': '(ns lochmess-bb-collector.main
  (:require [babashka.fs :as fs]
            [clojure.java.io :as io]))', 'client': {'ReplNs': function('<SNR>104_CljReplNs'), 'Client': function('129'), 'Eval': function('135'), 'Message': function('132', {'ReplNs': funct
ion('<SNR>104_CljReplNs'), 'Client': function('129'), 'UserNs': function('<SNR>104_CljUserNs'), 'Message': function('132', {...}), 'Query': function('<SNR>104_EvalQuery'), 'requires': {}, '
path': function('131', {...}), 'Done': function('133', {...}), 'preload': function('134'), 'HasOp': function('136'), 'BufferNs': function('<SNR>104_CljBufferNs'), 'eval': function('135', {.
..}), 'message': function('132'), 'user_ns': function('<SNR>104_CljUserNs', {...}), 'Eval': function('135'), 'Path': function('131'), 'done': function('133'), 'Ext': function('<SNR>104_CljE
xt'), 'Session': function('130'), 'Preload': function('134', {...})}), 'cljs_sessions': [], 'requires': {'lochmess-bb-collector.main': 0}, 'path': function('131', {'ReplNs': function('<SNR>
104_CljReplNs'), 'Client': function('129'), 'UserNs': function('<SNR>104_CljUserNs'), 'Message': function('132', {...}), 'Query': function('<SNR>104_EvalQuery'), 'requires': {}, 'path': fun
ction('131', {...}), 'Done': function('133', {...}), 'preload': function('134'), 'HasOp': function('136'), 'BufferNs': function('<SNR>104_CljBufferNs'), 'eval': function('135', {...}), 'mes
sage': function('132'), 'user_ns': function('<SNR>104_CljUserNs', {...}), 'Eval': function('135'), 'Path': function('131'), 'done': function('133'), 'Ext': function('<SNR>104_CljExt'), 'Ses
sion': function('130'), 'Preload': function('134', {...})}), 'Done': function('133', {'ReplNs': function('<SNR>104_CljReplNs'), 'Client': function('129'), 'UserNs': function('<SNR>104_CljUs
erNs'), 'Message': function('132', {...}), 'Query': function('<SNR>104_EvalQuery'), 'requires': {}, 'path': function('131', {...}), 'Done': function('133', {...}), 'preload': function('134'
), 'HasOp': function('136'), 'BufferNs': function('<SNR>104_CljBufferNs'), 'eval': function('135', {...}), 'message': function('132'), 'user_ns': function('<SNR>104_CljUserNs', {...}), 'Eva
l': function('135'), 'Path': function('131'), 'done': function('133'), 'Ext': function('<SNR>104_CljExt'), 'Session': function('130'), 'Preload': function('134', {...})}), 'session': {'Mess
age': function('<SNR>119_session_message'), 'close': function('<SNR>119_session_close'), 'id': '3d7bf619-269c-4768-afaf-fe23a5fce381', 'url': 'nrepl://localhost:37733/#3d7bf619-269c-4768-af
af-fe23a5fce381', 'path': function('<SNR>119_session_path'), 'session': '3d7bf619-269c-4768-afaf-fe23a5fce381', 'HasOp': function('<SNR>119_session_has_op'), 'has_op': function('<SNR>119_se
ssion_has_op'), 'transport': {'alive': function('<SNR>118_transport_alive'), '_path': [], 'job': 'process 403682 run', 'state': {'status': ''}, 'close': function('<SNR>118_transport_close')
, 'clone': function('<SNR>118_transport_clone'), 'url': 'nrepl://localhost:37733/', 'HasOp': function('<SNR>118_transport_has_op'), 'Alive': function('<SNR>118_transport_alive'), 'has_op':
function('<SNR>118_transport_has_op'), 'requests': {'d37a339f-68c4-4873-37f7-069ef088ba50': {'session': 'd0e506b2-7c48-4905-931c-2f6525986262', 'callbacks': [function('add', [[]])]}}, 'mess
age': function('<SNR>118_transport_message'), 'Close': function('<SNR>118_transport_close'), 'sessions': {'d0e506b2-7c48-4905-931c-2f6525986262': function('<SNR>119_session_callback', {'Mes
sage': function('<SNR>119_session_message'), 'close': function('<SNR>119_session_close'), 'id': 'd0e506b2-7c48-4905-931c-2f6525986262', 'url': 'nrepl://localhost:37733/#d0e506b2-7c48-4905-9
31c-2f6525986262', 'path': function('<SNR>119_session_path'), 'session': 'd0e506b2-7c48-4905-931c-2f6525986262', 'HasOp': function('<SNR>119_session_has_op'), 'has_op': function('<SNR>119_s
ession_has_op'), 'transport': {...}, 'clone': function('<SNR>119_session_clone'), 'message': function('<SNR>119_session_message'), 'Close': function('<SNR>119_session_close'), 'callbacks':
[function('<SNR>119_close_on_first_done', [{...}])], 'Clone': function('<SNR>119_session_clone'), 'Path': function('<SNR>119_session_path')}), '3d7bf619-269c-4768-afaf-fe23a5fce381': functi
on('<SNR>119_session_callback', {...})}, 'Clone': function('<SNR>118_transport_clone'), 'Message': function('<SNR>118_transport_message'), 'describe': {'status': ['done'], 'id': '4427c282-a
966-4a70-e26f-67f39a72bf24', 'session': ['none'], 'ops': {'info': {}, 'clone': {}, 'ls-sessions': {}, 'eldoc': {}, 'complete': {}, 'eval': {}, 'load-file': {}, 'close': {}, 'lookup': {}, 'd
escribe': {}}, 'versions': {'babashka.nrepl': '0.0.6-SNAPSHOT', 'babashka': '0.8.1'}}}, 'clone': function('<SNR>119_session_clone'), 'message': function('<SNR>119_session_message'), 'Close'
: function('<SNR>119_session_close'), 'callbacks': [], 'Clone': function('<SNR>119_session_clone'), 'Path': function('<SNR>119_session_path')}, 'preload': function('134'), 'HasOp': function
('136'), 'transport': {...}, 'BufferNs': function('<SNR>104_CljBufferNs'), 'eval': function('135', {'ReplNs': function('<SNR>104_CljReplNs'), 'Client': function('129'), 'UserNs': function('
<SNR>104_CljUserNs'), 'Message': function('132', {...}), 'Query': function('<SNR>104_EvalQuery'), 'requires': {}, 'path': function('131', {...}), 'Done': function('133', {...}), 'preload':
function('134'), 'HasOp': function('136'), 'BufferNs': function('<SNR>104_CljBufferNs'), 'eval': function('135', {...}), 'message': function('132'), 'user_ns': function('<SNR>104_CljUserNs'
, {...}), 'Eval': function('135'), 'Path': function('131'), 'done': function('133'), 'Ext': function('<SNR>104_CljExt'), 'Session': function('130'), 'Preload': function('134', {...})}), 'me
ssage': function('132'), 'user_ns': function('<SNR>104_CljUserNs', {'ReplNs': function('<SNR>104_CljReplNs'), 'Client': function('129'), 'UserNs': function('<SNR>104_CljUserNs'), 'Message':
 function('132', {...}), 'Query': function('<SNR>104_EvalQuery'), 'requires': {}, 'path': function('131', {...}), 'Done': function('133', {...}), 'preload': function('134'), 'HasOp': functi
on('136'), 'BufferNs': function('<SNR>104_CljBufferNs'), 'eval': function('135', {...}), 'message': function('132'), 'user_ns': function('<SNR>104_CljUserNs', {...}), 'Eval': function('135'
), 'Path': function('131'), 'done': function('133'), 'Ext': function('<SNR>104_CljExt'), 'Session': function('130'), 'Preload': function('134', {...})}), 'Query': function('<SNR>104_EvalQue
ry'), 'UserNs': function('<SNR>104_CljUserNs'), 'Path': function('131'), 'done': function('133'), 'Ext': function('<SNR>104_CljExt'), 'Session': function('130'), 'Preload': function('134',
{'ReplNs': function('<SNR>104_CljReplNs'), 'Client': function('129'), 'UserNs': function('<SNR>104_CljUserNs'), 'Message': function('132', {...}), 'Query': function('<SNR>104_EvalQuery'), '
requires': {}, 'path': function('131', {...}), 'Done': function('133', {...}), 'preload': function('134'), 'HasOp': function('136'), 'BufferNs': function('<SNR>104_CljBufferNs'), 'eval': fu
nction('135', {...}), 'message': function('132'), 'user_ns': function('<SNR>104_CljUserNs', {...}), 'Eval': function('135'), 'Path': function('131'), 'done': function('133'), 'Ext': functio
n('<SNR>104_CljExt'), 'Session': function('130'), 'Preload': function('134', {...})})}}
tpope commented 2 years ago

The important part is up front:

'history': {'messages': []

It's giving up waiting on a response before receiving a single message. I'm not sure why this would happen. Perhaps it could be a consequence of the connection terminating unexpectedly. You can check for that by looking for a running python child process before and after the eval. No python process, no connection.

robbieh commented 2 years ago

I see the python process both before and after the error, retaining the same PID. I'm fairly sure I have the right one because I see the nrepl port on the command line.

And just FYI I did a bundle update yesterday just to be sure I was up to date.

tpope commented 2 years ago

Absent a better idea:

tpope commented 2 years ago

One other thing you could try is delete the catch at https://github.com/tpope/vim-fireplace/blob/2e4540d62fd49523a3aefeab896a33ed6bbcb43b/autoload/fireplace/transport.vim#L135 and see if any errors bubble up.

robbieh commented 2 years ago

My setup has been working with lein and clj.

I tried removing the catch, but it didn't show anything new.

I'll try neovim next, but will need to learn how to set it up first.

"Jan K" from the Clojurians slack has the same problem, but noted that adding #!/usr/bin/env bb to the top of the file makes things partially work. cpp is ok but cpr fails.

tpope commented 2 years ago

I don't know much about babashka. It wouldn't surprise me if some high level functionality like cpr didn't work right. But this particular error is strange. This while loop is exiting before any messages have been received. You could maybe add a sleep 5 after it and see if the messages eventually show up.

elzibubble commented 2 years ago

I had this issue, but it's disappeared! My steps as best I can remember them:

After that my memory gets blurry but I tried putting the try/catch back - still works. Tried :Start bb --nrepl-server, still worked. Also tried original :Start shell and run nrepl, also works. Very confused but pleased I guess ^^

rafd commented 1 year ago

Ran into this today, some notes from my explorations:

Some of the previous suggestions in this thread may have "worked" because they were inadvertently evaluating in the user namespace.

When running :Require , fireplace figures out the current namespace by parsing the beginning of the file or defaults to user. Fireplace's logic here could be changed to skip lines that start with #, improving compatibility with babashka.

It may not seem like :Require is failing, because Fireplace will default to user if it can't find the namespace declaration (ex. because it's not there, or because there's a #!/usr/bin/env bb at the top of the file).

Evaluating (identity *ns*) can be useful to debug what namespace the REPL thinks it is currently in.

Informal babashka scripts often skip many Clojure formalities (ex. namespace declarations, namespace-file locations), breaking :Require, because :Require calls clojure.core/require (which assumes that namespaces are in certain files).

For informal babashka scripts, instead of :Require, you can eval the entire namespace in Fireplace with :%Eval.

For more formal babashka scripts (as recommended by Babashka docs):

tpope commented 1 year ago

This all tracks. Skipping # lines is a bit too broad, but skipping #! would certainly be reasonable. A simple tweak to the blank regexp would work.

marrs commented 7 months ago

I appear to be having the same issue with Babashka.

I have 2 namespaces that I'm working with. We'll call them a.core and a-core-test, living in src/a/core.clj and test/a/core_test.clj respectively.

The behaviour of this seems to vary, but for the moment I can reproduce the following. These are the results of running cpp on the following expressions:

(+ 1 2); => 3
(ns a.core); => nil
(defn a.core/foo [bar] ...) => #'a.core/foo
; Moving to a.core-test
(ns a.core-test); => Vim(return):E716: Key not present in Dictionary: "response"
(a.core/foo :bar) => Vim(return):E716: Key not present in Dictionary: "response"

Previously, evaluation of the expressions in src/a/core.clj were also failing with E716, but I cannot reproduce that behaviour now.

It doesn't matter what order I load the files in, the namespace in test never evaluates but the namespace in src does, so I wonder if this is to do with how bb.edn is configured.

my bb.edn is as follows:

{:paths ["src" "test"]
 :tasks
 {test (shell "bb --main a.core-test")}}

Running bb test works as expected, indicating that the namespaces are being found and evaluated without issue.

I'm connected to the nrepl server run by Babashka using the command bb --nrepl-server.

It may be worth looping Borkdude into this conversation.

Further info:

Evaluating (prn *ns*) in the src file prints the namespace of that file Evaluating (prn *ns*) in the test file returns the E716 error.

marrs commented 7 months ago

I can confirm that this is definitely a Babashka issue. Running an nrepl through clj works just fine.

rafd commented 7 months ago

@marrs can you publish a minimal repo that reproduces the issue?