daa84 / neovim-lib Goto Github PK
View Code? Open in Web Editor NEWRust library for Neovim clients
License: GNU Lesser General Public License v3.0
Rust library for Neovim clients
License: GNU Lesser General Public License v3.0
Hi!
First of all thanks for providing this plugin :).
I'm currently planning to write a rust reimplementation of the ctrlp.vim plugin.
While playing around with the library and trying to get a simple test setup working, I stumbled upon these nvim_error_events:
14:51:06 [INFO] ctrlp_rs::handler: [src/handler.rs:23] Incoming event: search
14:51:06 [INFO] ctrlp_rs: [src/main.rs:87] Waiting
14:51:06 [DEBUG] neovim_lib::rpc::client: [/home/nuke/.cargo/registry/src/github.com-1ecc6299db9ec823/neovim-lib-0.6.1/src/rpc/client.rs:242] Get message RpcNotification { method: "nvim_error_event", params: [Integer(PosInt(1)), String(Utf8String { s: Ok("Message is not an array") })] }
14:51:06 [INFO] ctrlp_rs::handler: [src/handler.rs:23] Incoming event: nvim_error_event
14:51:06 [ERROR] ctrlp_rs::handler: [src/handler.rs:36] Got nvim Error:
14:51:06 [ERROR] ctrlp_rs::handler: [src/handler.rs:37] [Integer(PosInt(1)), String(Utf8String { s: Ok("Message is not an array") })]
14:51:06 [ERROR] neovim_lib::rpc::client: [/home/nuke/.cargo/registry/src/github.com-1ecc6299db9ec823/neovim-lib-0.6.1/src/rpc/client.rs:237] Error while reading: I/O error while reading marker byte: failed to fill whole buffer
The rust bin is simply receiving events, and doesn't manipulate the Neovim instance and doesn't call any other functions on the Neovim instance.
I'm kind of confused, where these errors originate, maybe you can clarify things a little.
Project files:
https://github.com/Nukesor/ctrlp-rs.vim/blob/master/src/main.rs
https://github.com/Nukesor/ctrlp-rs.vim/blob/master/src/handler.rs
I have a handler which I pass along to Session start_event_loop_handler(handler)
. Event loop spinning. Want to subscribe to certain events so I call subscribe
on Neovim, after starting the event loop.
One problem. I want the handler to use functions like get_current_buffer
. It needs a &mut Neovim
. No problem, would normally construct the handler with that reference to the Neovim binding as its field. Here's the issue though, I need to be able to still use that Neovim binding after I've given it to a handler AND I need to allow multiple handlers to use that same mutable reference to make other NeomvimApi calls since most of those functions accept a &mut Neovim
. Here it is
let mut neovim = Neovim::new(Session::new_tcp("127.0.0.1:6666").unwrap());
let handler = SomeHandler {neovim: &mut neovim};
// Mutability exclusion violations
neovim.session.start_event_loop_handler(handler);
neovim.subscribe("get_generics").expect("cannot subscribe to event: get_generics");
Yeah I could subscribe and start an event loop before I deal with the handler but I want to be able subscribe to events long after I start handling others. I tried something using Arc<Mutex<Neovim>>
and got it to compile, unfortunately that did something "bad" because non of the NeovimApi methods I try to call work (they all timeout). This is the best neovim rpc crate and I like it but it seem like I'm kind of stuck, based on how the api is laid out here. Handling - Subscribing - Handling -Subscribing in any order but at least handling first before subscribing so you don't miss events doesn't sound like a far out use case does it?
Here's the stacktrace:
[Neocord] ERR (channel 3/stderr): File "rust:src/libcore/macros/mod.rs", line 15, in core::option::Option<T>::unwrap
File "/Users/prismarine/.cargo/registry/src/github.com-1ecc6299db9ec823/neovim-lib-0.6.1/src/rpc/client.rs", line 292, in neovim_lib::rpc::client::find_sender
let pos = queue.iter().position(|req| req.0 == msgid).unwrap();
File "/Users/prismarine/.cargo/registry/src/github.com-1ecc6299db9ec823/neovim-lib-0.6.1/src/rpc/client.rs", line 270, in neovim_lib::rpc::client::Client<R,W>::dispatch_thread::{{closure}}
let sender = find_sender(&queue, msgid);
File "rust:src/libstd/sys_common/backtrace.rs", line 136, in std::sys_common::backtrace::__rust_begin_short_backtrace
File "rust:src/libstd/thread/mod.rs", line 469, in std::thread::Builder::spawn_unchecked::{{closure}}::{{closure}}
File "rust:src/libstd/panic.rs", line 318, in <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
File "rust:src/libstd/panicking.rs", line 292, in std::panicking::try::do_call
File "src/libpanic_unwind/lib.rs", line 78, in __rust_maybe_catch_panic
File "rust:src/libstd/panicking.rs", line 270, in std::panicking::try
File "rust:src/libstd/panic.rs", line 394, in std::panic::catch_unwind
File "rust:src/libstd/thread/mod.rs", line 468, in std::thread::Builder::spawn_unchecked::{{closure}}
File "rust:src/libcore/ops/function.rs", line 232, in core::ops::function::FnOnce::call_once{{vtable.shim}}
File "rust:src/liballoc/boxed.rs", line 1022, in <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once
File "rust:src/liballoc/boxed.rs", line 1022, in <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once
File "src/libstd/sys_common/thread.rs", line 13, in std::sys_common::thread::start_thread
File "src/libstd/sys/unix/thread.rs", line 80, in std::sys::unix::thread::Thread::new::thread_start
File "<unknown>", line 0, in <unknown>
The application panicked (crashed).
called `Option::unwrap()` on a `None` value
in rust:src/libcore/macros/mod.rs, line 15
thread: <unnamed>
Code to duplicate can be seen at my plugin repository: https://github.com/DrBluefall/Neocord
Rust ver.: 1.41.0-nightly
As Unix sockets are supported, I feel the library should support Windows named pipes too, as that is the default listen mechanisms of the windows edition of neovim.
https://medium.com/@srishanbhattarai/a-detailed-guide-to-writing-your-first-neovim-plugin-in-rust-a81604c606b1 is a good starting point for people wanting to use this library. Maybe you want to link it somewhere :)
Hey, one quick(?) question. I came about this call, which I'm working with for my neovim rpc plugin. Is there a reason you're passing the values by reference? As far as I can see, both method
and params
go out of scope anyways after that. Wouldn't it be better than to pass them by value?
The reason I'm asking is that in my case params
will be quite large, and if passed by reference I will have to do quite a bit of copying to keep the data in my addon. I you move the values here, I can simply take ownership and be done with it.
I was taking a look at externalized messages support for gnvim, it seems ext_messages is missing.
See: https://github.com/neovim/neovim/blob/master/runtime/doc/ui.txt#L680
Heyho!
Would you consider buffered reading, or the option to have buffered reading to the lib? It can speed up the communication with neovim (probably a bottleneck for many applications... at least it is this way for my plugin for sure) greatly! Simply wrapping the reader in the communication thread in a BufReader
reduced the time of the relevant benchmark of my plugin by 70%!
So would you consider that? If it proves troublesome, maybe a compile time option?
Hey, thanks for this lib, I'm just trying it out :)
I encountered a problem. When using the neovim plugin I started to write with files above a certain size (seems like 9.2MB is ok, 13.2MB and above is not) I encounter the following error:
09:29:20 [DEBUG] neovim_lib::rpc::client: [neovim-lib/src/rpc/client.rs:149] Error reading I/O error while reading marker byte: failed to fill whole buffer
Now, I'm very shaky on all the details, and the circumstances I'm working under are quiet complicated. That being said, maybe you can already tell what's going on? Maybe you can give me some hints how to dig into this issue? Or is that an issue of the msgpack library?
(E) Actually, let me clarify that the size of the files having something to do with it is a theory of mine. I tested with 8 files of varying size, and the size is the most obvious difference here, but of course there are other differences I can't fully account for.
Hey, could you put up a new release? The last one is from August 10, 2018, and there have been quite some improvements that I'd like to use. Cheers :)
Here's my first completely useless neovim plugin[1] in Rust! I've been using it to test/dictate the design choices in my patches for neovim-lib. It relies on PR #4 and another yet-to-be PR currently in my fork of neovim-lib.
One thing this project brought to light is argument parsing. I wrote a couple functions to extract usize
and String
from neovim_lib::rpc::Value
[2], and I see src/rpc/model.rs
defines a couple macros along the same lines. I think it would be worthwhile for neovim_lib
to expose this functionality.
Anyway, wanted to submit this for review as a working example and possible template for other plugins.
Cheers!
[1]: https://github.com/boxofrox/neovim-scorched-earth
[2]: https://github.com/boxofrox/neovim-scorched-earth/blob/master/src/args.rs
This is something of a "semantical" issue, but I wanted to bring it up anyways. This line is very much spamming my logs when I use the debug
log level. That's because it also prints out the payload of the messages, which in my case is kind of big. Moreover, it puts all of it on one line, which wreaks havok with basically every tool that I use to look at the logs (even less is ... less than amused :)).
That leaves me in a bit of a conundrum: I want debug printout often (I make a lot of mistakes), but this is too much. Switching the level to info
leaves me without messages. From my personal understanding, payload would belong into the trace
level debug. Of course, just switching this call to trace!
instead of debug!
really just moves my problem...
With a bit of control flow though, we could output a useful debug message, and leave the full print to trace only. Would you consider that? I'd make a PR, but wanted to discuss this first. I'd tend to asking in the forums how other people handle this problem. I think there should be something like a log_exact
makro that does only log if a certain level is enabled, but not any others.
Thanks for your consideration!
What about moving the repo under the neovim
namespace?
It is an organization, so you will retain the same access, while increasing the repository visibility.
They host libraries/clients for another languages as well: https://github.com/neovim/
It will help to improve testing as well.
no method named `open_win` found for struct `neovim_lib::Neovim` in the current scope
method not found in `neovim_lib::Neovim` rustc(E0599)
main.rs(12, 8): method not found in `neovim_lib::Neovim`
[dependencies]
neovim-lib = "*"
github version:
// Auto generated 2019-08-29 20:30:34.996423
crates.io version:
// Auto generated 2019-01-27 23:29:06.441158
Hi there, I'm executing echo "foo"
as a command which shows up in Neovim fine.
pub fn command(&mut self, cmd: &str) {
if let Err(msg) = self.nvim.command(cmd) {
error!("Command failed ({}): {}", cmd, msg);
}
}
The problem is that if I don't clear the "press enter to continue" message in Neovim within 5 seconds (I think that's the timeout?) when I eventually press enter neovim_lib will panic. If this is intended (because Neovim doesn't respond to the RPC call while it's waiting for the user to press enter) is there a way I can send a command without waiting for a response?
In my logs I see this after 5 seconds:
13:27:11 [ERROR] Command failed (echo "[foo] 127.0.0.1:5555 for files matching 'clj$'
[bar] 127.0.0.1:5555 for files matching 'cljc?$'"): Unknown error type: Wait timeout (nvim_command)
And then I see this after pressing enter in Neovim since I pipe stderr to echoerr:
conjure: 13 stderr thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: "SendError(..)"', libcore/result.rs:1009:5
conjure: 13 stderr note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
at libst
d/sys/unix/backtrace/tracing/gcc_s.rs:49
1: std::sys_common::backtrace::print
at libstd/sys_common/backtrace.rs:71
at libstd/sys_common/backtrace.rs:59
2: std::panicking::defau
lt_hook::{{closure}}
at libstd/panicking.rs:211
3: std::panicking::default_hook
at libstd/panicking.rs:227
4: std::panicking::rust_panic_with_hook
at libstd/panic
king.rs:477
5: std::panicking::continue_panic_fmt
at libstd/panicking.rs:391
6: rust_begin_unwind
at libstd/panicking.rs:326
7: core::panicking::panic_fmt
at
libcore/panicking.rs:77
8: core::result::unwrap_failed
9: neovim_lib::rpc::client::Sender::send
The backtrace was really weirdly formatted because of Neovim but I'd tried to recover it as best I can.
Thanks a lot! The library has been extremely helpful for me so far!
Now that it's available on stable, it seems like a premier way of solving #23. Do you have any plans regarding that? I've thought a bit about it, and it seems like that would result in a major breaking change, but it's the first time I'm dabbling in that stuff, so I might just not have had the right idea.
TL;DR: One needs to read the neovim documentation carefully, sorry for the noise!
Hey!
Could you help me figure out a problem? I'm not sure on which side it is, exactly :)
I've written the following function:
pub fn resend_all_atomic(&self, nvim: &mut Neovim) -> Result<(), Error> {
let mut calls: Vec<Value> = Vec::with_capacity(self.folds.len() + 1);
calls.push(
vec![
Value::from("nvim_command".to_owned()),
Value::from("normal! zE".to_owned()),
].into(),
);
for range in self.folds.keys() {
calls.push(
vec![
Value::from("nvim_command".to_owned()),
Value::from(format!("{},{}fo", range[0] + 1, range[1] + 1)),
].into(),
);
}
nvim.call_atomic(calls).context("call_atomic failed")?;
Ok(())
}
I compiles, so calls
is indeed a Vec<Value>
, and as can be seen, each Value
is constructed from calling into
on a Vec<Value>
. So echo Value
of calls
is of variant Array
with 2 elements. As far as I can see, that's the needed setup for neovim.
Still, neovim returns an error 1 - Args must be Array
(I assume 1 denotes the channel).
I've tried following through the code, but the only thing I really noticed is that call_args!
wraps calls
it in another Vec
, which is then passed down the chain, made part of an RpcMessage
which is given to model::encode
, where rpc_args!
wraps it in another Vec
together with the rpc metadata.
So what I'm saying is, I'm at a loss and I'd appreciate some help. If nothing else, a confirmation that call_atomic
works as expected would be helpfull. Thanks in advance!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.