vim-fireplace
vim-fireplace copied to clipboard
Fireplace has problems with the Babashka nREPL
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', [])"
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.
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
Oh it must have function keys, try :echo state instead.
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', {...})})}}
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.
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.
Absent a better idea:
- Make sure it works with another toolchain, like
lein. - Try both Neovim and Vim. This will help rule out any bugs in the low level code.
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.
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.
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.
I had this issue, but it's disappeared! My steps as best I can remember them:
- Opened vim to edit a bb .clj file
- I started a shell with vim-dispatch (
:Shell) - Ran
bb --nrepl-server :FireplaceConnect 1667- Try to eval something, oh it's not working... google...
- Remove the try/catch, re: https://github.com/tpope/vim-fireplace/issues/401#issuecomment-1102955161
- Closed vim entirely, ran
bb --brepl-server & - Relaunched vim
:FireplaceConnect 1667- Hey it works now!
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 ^^
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):
- remove
#!/usr/bin/env bbat the top of the file - add
:paths ["src"]tobb.edn(note: appending--classpath "src"is different) - put namespace files in the appropriate places (ex.
fooinsrc/foo.clj) - use namespace declarations (ie.
(ns foo (:require ....))) - run repl with
bb --nrepl-serverand use:Connect 1667or:Fireplace 1667to connect
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.
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.
I can confirm that this is definitely a Babashka issue. Running an nrepl through clj works just fine.
@marrs can you publish a minimal repo that reproduces the issue?