From 38ddc7a3ef18ff8d8273561ce65a93b6dfe184a4 Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Sat, 20 Jan 2024 12:17:02 +0100 Subject: [PATCH 1/7] Use custom stdout without Bufwrite in Tokio --- src/create/tokio.rs | 12 +++++++----- src/neovim.rs | 6 +++--- src/rpc/model.rs | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/create/tokio.rs b/src/create/tokio.rs index 80fe3c4c..d13cf9f9 100644 --- a/src/create/tokio.rs +++ b/src/create/tokio.rs @@ -8,7 +8,7 @@ use std::{ }; use tokio::{ - io::{split, stdin, stdout, Stdout, WriteHalf}, + io::{split, stdin, WriteHalf}, net::{TcpStream, ToSocketAddrs}, process::{Child, ChildStdin, Command}, spawn, @@ -153,15 +153,17 @@ where pub async fn new_parent( handler: H, ) -> ( - Neovim>, + Neovim>, JoinHandle>>, ) where - H: Handler>, + H: Handler>, { - let (neovim, io) = Neovim::>::new( + use std::os::fd::FromRawFd; + let sout = unsafe { tokio::fs::File::from_raw_fd(1) }.compat_write(); + let (neovim, io) = Neovim::>::new( stdin().compat(), - stdout().compat_write(), + sout, handler, ); let io_handle = spawn(io); diff --git a/src/neovim.rs b/src/neovim.rs index 55272edf..6825a23c 100644 --- a/src/neovim.rs +++ b/src/neovim.rs @@ -12,7 +12,7 @@ use futures::{ mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, oneshot, }, - io::{AsyncRead, AsyncWrite, BufWriter}, + io::{AsyncRead, AsyncWrite,}, lock::Mutex, sink::SinkExt, stream::StreamExt, @@ -54,7 +54,7 @@ pub struct Neovim where W: AsyncWrite + Send + Unpin + 'static, { - pub(crate) writer: Arc>>, + pub(crate) writer: Arc>, pub(crate) queue: Queue, pub(crate) msgid_counter: Arc, } @@ -100,7 +100,7 @@ where H: Handler + Spawner, { let req = Neovim { - writer: Arc::new(Mutex::new(BufWriter::new(writer))), + writer: Arc::new(Mutex::new(writer)), msgid_counter: Arc::new(AtomicU64::new(0)), queue: Arc::new(Mutex::new(Vec::new())), }; diff --git a/src/rpc/model.rs b/src/rpc/model.rs index 920d3336..bf5f0ff8 100644 --- a/src/rpc/model.rs +++ b/src/rpc/model.rs @@ -7,7 +7,7 @@ use std::{ }; use futures::{ - io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, BufWriter}, + io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt,}, lock::Mutex, }; use rmpv::{decode::read_value, encode::write_value, Value}; @@ -165,7 +165,7 @@ fn decode_buffer( /// Encode the given message into the `BufWriter`. Flushes the writer when /// finished. pub async fn encode( - writer: Arc>>, + writer: Arc>, msg: RpcMessage, ) -> std::result::Result<(), Box> { let mut v: Vec = vec![]; From ac54f457bccb7623f3bcc94b8ff7956ebbe4bf19 Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Fri, 26 Jan 2024 16:24:25 +0100 Subject: [PATCH 2/7] Construct our stdout safely, surface possible error --- src/create/tokio.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/create/tokio.rs b/src/create/tokio.rs index d13cf9f9..694f4d2d 100644 --- a/src/create/tokio.rs +++ b/src/create/tokio.rs @@ -2,9 +2,11 @@ //! [`tokio`](tokio) use std::{ future::Future, - io::{self, Error, ErrorKind}, + io::{self, Error, ErrorKind, stdout}, path::Path, process::Stdio, + fs::File, + os::fd::AsFd, }; use tokio::{ @@ -13,6 +15,7 @@ use tokio::{ process::{Child, ChildStdin, Command}, spawn, task::JoinHandle, + fs::File as TokioFile, }; use parity_tokio_ipc::{Connection, Endpoint}; @@ -152,21 +155,23 @@ where /// Connect to the neovim instance that spawned this process over stdin/stdout pub async fn new_parent( handler: H, -) -> ( +) -> Result<( Neovim>, JoinHandle>>, -) +), Error> where H: Handler>, { - use std::os::fd::FromRawFd; - let sout = unsafe { tokio::fs::File::from_raw_fd(1) }.compat_write(); + let owned_sout_fd = stdout().as_fd().try_clone_to_owned()?; + let file = File::from(owned_sout_fd); + let sout = TokioFile::from_std(file); + let (neovim, io) = Neovim::>::new( stdin().compat(), - sout, + sout.compat(), handler, ); let io_handle = spawn(io); - (neovim, io_handle) + Ok((neovim, io_handle)) } From d2146bee7ed9b453b6ed61424912855dda486eee Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Fri, 26 Jan 2024 16:30:13 +0100 Subject: [PATCH 3/7] Remove buffering stdout from async_std code too --- src/create/async_std.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/create/async_std.rs b/src/create/async_std.rs index 9603f8e0..a8767ee9 100644 --- a/src/create/async_std.rs +++ b/src/create/async_std.rs @@ -1,14 +1,15 @@ //! Functions to spawn a [`neovim`](crate::neovim::Neovim) session using //! [`async-std`](async-std) -use std::{future::Future, io}; +use std::{future::Future, io, fs::File, os::fd::AsFd}; #[cfg(unix)] use async_std::os::unix::net::UnixStream; use async_std::{ - io::{stdin, stdout, Stdout}, + io::{stdin}, net::{TcpStream, ToSocketAddrs}, task::{spawn, JoinHandle}, + fs::File as ASFile, }; #[cfg(unix)] @@ -78,12 +79,15 @@ where /// Connect to the neovim instance that spawned this process over stdin/stdout pub async fn new_parent( handler: H, -) -> (Neovim, JoinHandle>>) +) -> io::Result<(Neovim, JoinHandle>>)> where - H: Handler, + H: Handler, { - let (neovim, io) = Neovim::::new(stdin(), stdout(), handler); + let owned = std::io::stdout().as_fd().try_clone_to_owned()?; + let file = File::from(owned); + let sout: ASFile = file.into(); + let (neovim, io) = Neovim::::new(stdin(), sout, handler); let io_handle = spawn(io); - (neovim, io_handle) + Ok((neovim, io_handle)) } From 647379adf3419f0b73a2c401477a9d72cd1639fa Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Fri, 26 Jan 2024 16:31:50 +0100 Subject: [PATCH 4/7] RustFmt --- src/create/async_std.rs | 6 +++--- src/create/tokio.rs | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/create/async_std.rs b/src/create/async_std.rs index a8767ee9..71b2b6ca 100644 --- a/src/create/async_std.rs +++ b/src/create/async_std.rs @@ -1,15 +1,15 @@ //! Functions to spawn a [`neovim`](crate::neovim::Neovim) session using //! [`async-std`](async-std) -use std::{future::Future, io, fs::File, os::fd::AsFd}; +use std::{fs::File, future::Future, io, os::fd::AsFd}; #[cfg(unix)] use async_std::os::unix::net::UnixStream; use async_std::{ - io::{stdin}, + fs::File as ASFile, + io::stdin, net::{TcpStream, ToSocketAddrs}, task::{spawn, JoinHandle}, - fs::File as ASFile, }; #[cfg(unix)] diff --git a/src/create/tokio.rs b/src/create/tokio.rs index 694f4d2d..caa24c70 100644 --- a/src/create/tokio.rs +++ b/src/create/tokio.rs @@ -1,21 +1,21 @@ //! Functions to spawn a [`neovim`](crate::neovim::Neovim) session using //! [`tokio`](tokio) use std::{ + fs::File, future::Future, - io::{self, Error, ErrorKind, stdout}, + io::{self, stdout, Error, ErrorKind}, + os::fd::AsFd, path::Path, process::Stdio, - fs::File, - os::fd::AsFd, }; use tokio::{ + fs::File as TokioFile, io::{split, stdin, WriteHalf}, net::{TcpStream, ToSocketAddrs}, process::{Child, ChildStdin, Command}, spawn, task::JoinHandle, - fs::File as TokioFile, }; use parity_tokio_ipc::{Connection, Endpoint}; @@ -155,10 +155,13 @@ where /// Connect to the neovim instance that spawned this process over stdin/stdout pub async fn new_parent( handler: H, -) -> Result<( - Neovim>, - JoinHandle>>, -), Error> +) -> Result< + ( + Neovim>, + JoinHandle>>, + ), + Error, +> where H: Handler>, { From 4eeca137ee399bd3a5d118ce54f59d7b45c1468d Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Fri, 26 Jan 2024 16:42:29 +0100 Subject: [PATCH 5/7] Fix examples --- examples/basic.rs | 8 ++++---- examples/bench_async-std.rs | 26 +++++++++++--------------- examples/bench_tokio.rs | 21 ++++++++++----------- examples/scorched_earth.rs | 8 ++++---- examples/scorched_earth_as.rs | 12 +++++------- 5 files changed, 34 insertions(+), 41 deletions(-) diff --git a/examples/basic.rs b/examples/basic.rs index dcb45fbb..25f2a599 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -6,7 +6,7 @@ use async_trait::async_trait; use rmpv::Value; -use tokio::io::Stdout; +use tokio::fs::File as TokioFile; use nvim_rs::{ compat::tokio::Compat, create::tokio as create, rpc::IntoVal, Handler, Neovim, @@ -17,13 +17,13 @@ struct NeovimHandler {} #[async_trait] impl Handler for NeovimHandler { - type Writer = Compat; + type Writer = Compat; async fn handle_request( &self, name: String, _args: Vec, - _neovim: Neovim>, + _neovim: Neovim>, ) -> Result { match name.as_ref() { "ping" => Ok(Value::from("pong")), @@ -35,7 +35,7 @@ impl Handler for NeovimHandler { #[tokio::main] async fn main() { let handler: NeovimHandler = NeovimHandler {}; - let (nvim, io_handler) = create::new_parent(handler).await; + let (nvim, io_handler) = create::new_parent(handler).await.unwrap(); let curbuf = nvim.get_current_buf().await.unwrap(); let mut envargs = env::args(); diff --git a/examples/bench_async-std.rs b/examples/bench_async-std.rs index 795cf62b..a72ce444 100644 --- a/examples/bench_async-std.rs +++ b/examples/bench_async-std.rs @@ -4,25 +4,22 @@ use async_trait::async_trait; use rmpv::Value; -use async_std::io::Stdout; -use async_std; +use async_std::{self, fs::File as ASFile}; -use nvim_rs::{ - create::async_std as create, Handler, Neovim, -}; +use nvim_rs::{create::async_std as create, Handler, Neovim}; #[derive(Clone)] -struct NeovimHandler{} +struct NeovimHandler {} #[async_trait] impl Handler for NeovimHandler { - type Writer =Stdout; + type Writer = ASFile; async fn handle_request( &self, name: String, _args: Vec, - neovim: Neovim, + neovim: Neovim, ) -> Result { match name.as_ref() { "file" => { @@ -31,30 +28,29 @@ impl Handler for NeovimHandler { let _x = c.get_lines(0, -1, false).await; } Ok(Value::Nil) - }, + } "buffer" => { for _ in 0..10_000_usize { let _ = neovim.get_current_buf().await.unwrap(); } Ok(Value::Nil) - }, + } "api" => { for _ in 0..1_000_usize { let _ = neovim.get_api_info().await.unwrap(); } Ok(Value::Nil) - }, - _ => Ok(Value::Nil) + } + _ => Ok(Value::Nil), } } } #[async_std::main] async fn main() { + let handler: NeovimHandler = NeovimHandler {}; - let handler: NeovimHandler = NeovimHandler{}; - - let (nvim, io_handler) = create::new_parent(handler).await; + let (nvim, io_handler) = create::new_parent(handler).await.unwrap(); // Any error should probably be logged, as stderr is not visible to users. match io_handler.await { diff --git a/examples/bench_tokio.rs b/examples/bench_tokio.rs index 450b7525..86897ad6 100644 --- a/examples/bench_tokio.rs +++ b/examples/bench_tokio.rs @@ -4,24 +4,24 @@ use async_trait::async_trait; use rmpv::Value; -use tokio::io::Stdout; +use tokio::fs::File as TokioFile; use nvim_rs::{ compat::tokio::Compat, create::tokio as create, Handler, Neovim, }; #[derive(Clone)] -struct NeovimHandler{} +struct NeovimHandler {} #[async_trait] impl Handler for NeovimHandler { - type Writer = Compat; + type Writer = Compat; async fn handle_request( &self, name: String, _args: Vec, - neovim: Neovim>, + neovim: Neovim>, ) -> Result { match name.as_ref() { "file" => { @@ -30,30 +30,29 @@ impl Handler for NeovimHandler { let _x = c.get_lines(0, -1, false).await; } Ok(Value::Nil) - }, + } "buffer" => { for _ in 0..10_000_usize { let _ = neovim.get_current_buf().await.unwrap(); } Ok(Value::Nil) - }, + } "api" => { for _ in 0..1_000_usize { let _ = neovim.get_api_info().await.unwrap(); } Ok(Value::Nil) - }, - _ => Ok(Value::Nil) + } + _ => Ok(Value::Nil), } } } #[tokio::main] async fn main() { + let handler: NeovimHandler = NeovimHandler {}; - let handler: NeovimHandler = NeovimHandler{}; - - let (nvim, io_handler) = create::new_parent(handler).await; + let (nvim, io_handler) = create::new_parent(handler).await.unwrap(); // Any error should probably be logged, as stderr is not visible to users. match io_handler.await { diff --git a/examples/scorched_earth.rs b/examples/scorched_earth.rs index 024e4716..ef9a78cc 100644 --- a/examples/scorched_earth.rs +++ b/examples/scorched_earth.rs @@ -6,7 +6,7 @@ use async_trait::async_trait; use rmpv::Value; use futures::lock::Mutex; -use tokio::io::Stdout; +use tokio::fs::File as TokioFile; use nvim_rs::{ compat::tokio::Compat, create::tokio as create, Handler, Neovim, @@ -44,13 +44,13 @@ struct NeovimHandler(Arc>); #[async_trait] impl Handler for NeovimHandler { - type Writer = Compat; + type Writer = Compat; async fn handle_notify( &self, name: String, args: Vec, - neovim: Neovim>, + neovim: Neovim>, ) { match name.as_ref() { "cursor-moved-i" => { @@ -102,7 +102,7 @@ async fn main() { }; let handler: NeovimHandler = NeovimHandler(Arc::new(Mutex::new(p))); - let (nvim, io_handler) = create::new_parent(handler).await; + let (nvim, io_handler) = create::new_parent(handler).await.unwrap(); // Any error should probably be logged, as stderr is not visible to users. match io_handler.await { diff --git a/examples/scorched_earth_as.rs b/examples/scorched_earth_as.rs index 23986a47..50d505c1 100644 --- a/examples/scorched_earth_as.rs +++ b/examples/scorched_earth_as.rs @@ -7,11 +7,9 @@ use rmpv::Value; use futures::lock::Mutex; -use nvim_rs::{ - create::async_std as create, Handler, Neovim, -}; +use nvim_rs::{create::async_std as create, Handler, Neovim}; -use async_std::{self, io::Stdout}; +use async_std::{self, fs::File as ASFile}; struct Posis { cursor_start: Option<(u64, u64)>, @@ -45,13 +43,13 @@ struct NeovimHandler(Arc>); #[async_trait] impl Handler for NeovimHandler { - type Writer = Stdout; + type Writer = ASFile; async fn handle_notify( &self, name: String, args: Vec, - neovim: Neovim, + neovim: Neovim, ) { match name.as_ref() { "cursor-moved-i" => { @@ -103,7 +101,7 @@ async fn main() { }; let handler: NeovimHandler = NeovimHandler(Arc::new(Mutex::new(p))); - let (nvim, io_handler) = create::new_parent(handler).await; + let (nvim, io_handler) = create::new_parent(handler).await.unwrap(); // Any error should probably be logged, as stderr is not visible to users. match io_handler.await { From c5cfcc9140ea9bf2dc82605319eaed8aeb3d468e Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Fri, 26 Jan 2024 17:23:29 +0100 Subject: [PATCH 6/7] Create stdout differently on windows, fix dependency feature --- Cargo.toml | 3 +++ src/create/async_std.rs | 13 ++++++++----- src/create/mod.rs | 18 ++++++++++++++++++ src/create/tokio.rs | 15 ++++++++------- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1d0aab54..6f08026b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,9 @@ async-std = { version = "1.12.0", features = ["attributes"], optional = true } neovim-lib = { version = "0.6.1", optional = true } parity-tokio-ipc = { version = "0.9.0", optional = true } +[target.'cfg(windows)'.dependencies] +winapi = { version = '*', features = ["winerror"] } + [dev-dependencies] tempfile = "3.8.0" # TODO: if changing tempfile: the rand version is based on whatever version diff --git a/src/create/async_std.rs b/src/create/async_std.rs index 71b2b6ca..378b5557 100644 --- a/src/create/async_std.rs +++ b/src/create/async_std.rs @@ -1,6 +1,6 @@ //! Functions to spawn a [`neovim`](crate::neovim::Neovim) session using //! [`async-std`](async-std) -use std::{fs::File, future::Future, io, os::fd::AsFd}; +use std::{future::Future, io}; #[cfg(unix)] use async_std::os::unix::net::UnixStream; @@ -17,7 +17,12 @@ use async_std::path::Path; use futures::io::{AsyncReadExt, WriteHalf}; -use crate::{create::Spawner, error::LoopError, neovim::Neovim, Handler}; +use crate::{ + create::{unbuffered_stdout, Spawner}, + error::LoopError, + neovim::Neovim, + Handler, +}; impl Spawner for H where @@ -83,9 +88,7 @@ pub async fn new_parent( where H: Handler, { - let owned = std::io::stdout().as_fd().try_clone_to_owned()?; - let file = File::from(owned); - let sout: ASFile = file.into(); + let sout: ASFile = unbuffered_stdout()?.into(); let (neovim, io) = Neovim::::new(stdin(), sout, handler); let io_handle = spawn(io); diff --git a/src/create/mod.rs b/src/create/mod.rs index 741b3e13..95e4891f 100644 --- a/src/create/mod.rs +++ b/src/create/mod.rs @@ -17,6 +17,7 @@ pub mod tokio; pub mod async_std; use core::future::Future; +use std::{fs::File, io}; use crate::rpc::handler::Handler; @@ -36,3 +37,20 @@ pub trait Spawner: Handler { where Fut: Future + Send + 'static; } + +/// Create a std::io::File for stdout, which is not line-buffered, as +/// opposed to std::io::Stdout. +#[cfg(unix)] +pub fn unbuffered_stdout() -> io::Result { + use std::{io::stdout, os::fd::AsFd}; + + let owned_sout_fd = stdout().as_fd().try_clone_to_owned()?; + Ok(File::from(owned_sout_fd)) +} +#[cfg(windows)] +pub fn unbuffered_stdout() -> io::Result { + use std::{io::stdout, os::windows::io::AsHandle}; + + let owned_sout_handle = stdout().as_handle().try_clone_to_owned()?; + Ok(File::from(owned_sout_handle)) +} diff --git a/src/create/tokio.rs b/src/create/tokio.rs index caa24c70..339454c3 100644 --- a/src/create/tokio.rs +++ b/src/create/tokio.rs @@ -1,10 +1,8 @@ //! Functions to spawn a [`neovim`](crate::neovim::Neovim) session using //! [`tokio`](tokio) use std::{ - fs::File, future::Future, - io::{self, stdout, Error, ErrorKind}, - os::fd::AsFd, + io::{self, Error, ErrorKind}, path::Path, process::Stdio, }; @@ -24,7 +22,12 @@ use tokio_util::compat::{ Compat, TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt, }; -use crate::{create::Spawner, error::LoopError, neovim::Neovim, Handler}; +use crate::{ + create::{unbuffered_stdout, Spawner}, + error::LoopError, + neovim::Neovim, + Handler, +}; impl Spawner for H where @@ -165,9 +168,7 @@ pub async fn new_parent( where H: Handler>, { - let owned_sout_fd = stdout().as_fd().try_clone_to_owned()?; - let file = File::from(owned_sout_fd); - let sout = TokioFile::from_std(file); + let sout = TokioFile::from_std(unbuffered_stdout()?); let (neovim, io) = Neovim::>::new( stdin().compat(), From 7ea91dc3983c9dd5fd8c3f229f79630d0637505d Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Fri, 26 Jan 2024 19:32:15 +0100 Subject: [PATCH 7/7] Add tests for crashing neovim with linebuffering --- Cargo.toml | 12 ++++++++++ src/bin/linebuffercrash.rs | 24 +++++++++++++++++++ src/bin/linebuffercrash_as.rs | 24 +++++++++++++++++++ tests/regression/buffering.rs | 45 +++++++++++++++++++++++++++++++++++ tests/regression/mod.rs | 4 ++++ 5 files changed, 109 insertions(+) create mode 100644 src/bin/linebuffercrash.rs create mode 100644 src/bin/linebuffercrash_as.rs create mode 100644 tests/regression/buffering.rs create mode 100644 tests/regression/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 6f08026b..9f4e0e35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,3 +112,15 @@ required-features = ["use_tokio"] [[test]] name = "basic" + +[[test]] +name = "regression" +path = "tests/regression/mod.rs" + +[[bin]] +name = "linebuffercrash" +required-features = ["use_tokio"] + +[[bin]] +name = "linebuffercrash_as" +required-features = ["use_async-std"] diff --git a/src/bin/linebuffercrash.rs b/src/bin/linebuffercrash.rs new file mode 100644 index 00000000..9c9fa56a --- /dev/null +++ b/src/bin/linebuffercrash.rs @@ -0,0 +1,24 @@ + +use nvim_rs::{ + create::tokio as create, + rpc::handler::Dummy as DummyHandler +}; + + +#[tokio::main] +async fn main() { + let handler = DummyHandler::new(); + let (nvim, _io_handler) = create::new_parent(handler).await.unwrap(); + let curbuf = nvim.get_current_buf().await.unwrap(); + + // If our Stdout is linebuffered, this has a high chance of crashing neovim + // Should probably befixed in neovim itself, but for now, let's just make + // sure we're not using linebuffering, or at least don't crash neovim with + // this. + for i in 0..20 { + curbuf.set_name(&format!("a{i}")).await.unwrap(); + } + + let _ = nvim.command("quit!").await; + +} diff --git a/src/bin/linebuffercrash_as.rs b/src/bin/linebuffercrash_as.rs new file mode 100644 index 00000000..10c13008 --- /dev/null +++ b/src/bin/linebuffercrash_as.rs @@ -0,0 +1,24 @@ + +use nvim_rs::{ + create::async_std as create, + rpc::handler::Dummy as DummyHandler +}; + + +#[async_std::main] +async fn main() { + let handler = DummyHandler::new(); + let (nvim, _io_handler) = create::new_parent(handler).await.unwrap(); + let curbuf = nvim.get_current_buf().await.unwrap(); + + // If our Stdout is linebuffered, this has a high chance of crashing neovim + // Should probably befixed in neovim itself, but for now, let's just make + // sure we're not using linebuffering, or at least don't crash neovim with + // this. + for i in 0..20 { + curbuf.set_name(&format!("a{i}")).await.unwrap(); + } + + let _ = nvim.command("quit!").await; + +} diff --git a/tests/regression/buffering.rs b/tests/regression/buffering.rs new file mode 100644 index 00000000..8e2a695a --- /dev/null +++ b/tests/regression/buffering.rs @@ -0,0 +1,45 @@ +#[path = "../common/mod.rs"] +mod common; +use common::*; + +use std::{path::PathBuf, process::Command}; + +fn viml_escape(in_str: &str) -> String { + in_str.replace('\\', r"\\") +} + +fn linebuffercrashbin() -> &'static str { + #[cfg(feature = "use_tokio")] + return "linebuffercrash"; + #[cfg(feature = "use_async-std")] + return "linebuffercrash_as"; +} + +#[test] +fn linebuffer_crash() { + let c1 = format!( + "let jobid = jobstart([\"{}\"], {{\"rpc\": v:true}})", + viml_escape( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("target") + .join("debug") + .join(linebuffercrashbin()) + .to_str() + .unwrap() + ) + ); + + let status = Command::new(nvim_path()) + .args(&[ + "-u", + "NONE", + "--headless", + "-c", + &c1, + ]) + .status() + .unwrap(); + + assert!(status.success()); + +} diff --git a/tests/regression/mod.rs b/tests/regression/mod.rs new file mode 100644 index 00000000..cf8373db --- /dev/null +++ b/tests/regression/mod.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "use_tokio")] +pub mod buffering; +#[cfg(feature = "use_async-std")] +pub mod buffering;