Skip to content

Commit d715086

Browse files
committed
Forward stdin if it's piped on Linux and MacOS
1 parent fa56b15 commit d715086

File tree

4 files changed

+36
-4
lines changed

4 files changed

+36
-4
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,16 @@ objc2-metal = { version = "0.3.1", default-features = false, features = [
168168
skia-safe = { version = "0.88.0", features = ["metal", "gl", "textlayout"] }
169169
uzers = "0.12.1"
170170

171-
172171
[target.'cfg(not(any(target_os = "windows", target_os = "macos")))'.dependencies]
173172
skia-safe = { version = "0.88.0", features = ["gl", "textlayout"] }
174173

175-
176174
[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies]
177175
csscolorparser = "0.7.0"
178176
shlex = "1.3.0"
179177

178+
[target.'cfg(not(target_os = "windows"))'.dependencies]
179+
rustix = "1.0.8"
180+
180181
[target.'cfg(target_os = "windows")'.build-dependencies]
181182
winres = "0.1.12"
182183

src/bridge/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ async fn launch(
110110
) -> Result<NeovimSession> {
111111
let neovim_instance = neovim_instance(settings.as_ref()).await?;
112112

113-
let session = NeovimSession::new(neovim_instance, handler)
113+
#[allow(unused_mut)]
114+
let mut session = NeovimSession::new(neovim_instance, handler)
114115
.await
115116
.context("Could not locate or start neovim process")?;
116117

@@ -153,6 +154,14 @@ async fn launch(
153154
options.set_linegrid_external(true);
154155
options.set_multigrid_external(!cmdline_settings.no_multi_grid);
155156
options.set_rgb(true);
157+
// We can close the handle here, as Neovim already owns it
158+
#[cfg(not(target_os = "windows"))]
159+
if let Some(fd) = session.stdin_fd.take() {
160+
use rustix::fd::AsRawFd;
161+
if let Ok(fd) = fd.as_raw_fd().try_into() {
162+
options.set_stdin_fd(fd);
163+
}
164+
}
156165

157166
// Triggers loading the user config
158167

src/bridge/session.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub struct NeovimSession {
2929
pub io_handle: JoinHandle<std::result::Result<(), Box<LoopError>>>,
3030
pub neovim_process: Option<Child>,
3131
pub stderr_task: Option<JoinHandle<Vec<String>>>,
32+
#[cfg(not(target_os = "windows"))]
33+
pub stdin_fd: Option<rustix::fd::OwnedFd>,
3234
}
3335

3436
#[cfg(debug_assertions)]
@@ -45,6 +47,10 @@ impl NeovimSession {
4547
instance: NeovimInstance,
4648
handler: impl Handler<Writer = NeovimWriter>,
4749
) -> anyhow::Result<Self> {
50+
// This needs to be done before the process is spawned, since the file descriptors are
51+
// inherited on unix-like systems
52+
#[cfg(not(target_os = "windows"))]
53+
let stdin_fd = instance.forward_stdin();
4854
let (reader, writer, stderr_reader, neovim_process) = instance.connect().await?;
4955
// Spawn a background task to read from stderr
5056
let stderr_task = stderr_reader.map(|reader| {
@@ -84,6 +90,8 @@ impl NeovimSession {
8490
io_handle,
8591
neovim_process,
8692
stderr_task,
93+
#[cfg(not(target_os = "windows"))]
94+
stdin_fd,
8795
})
8896
}
8997
}
@@ -120,7 +128,6 @@ impl NeovimInstance {
120128
mut cmd: Command,
121129
) -> Result<(BoxedReader, BoxedWriter, Option<BoxedReader>, Option<Child>)> {
122130
log::debug!("Starting neovim with: {cmd:?}");
123-
124131
let mut child = cmd
125132
.stdin(Stdio::piped())
126133
.stdout(Stdio::piped())
@@ -177,6 +184,20 @@ impl NeovimInstance {
177184
}
178185
}
179186

187+
#[cfg(not(target_os = "windows"))]
188+
fn forward_stdin(&self) -> Option<rustix::fd::OwnedFd> {
189+
use std::io::IsTerminal;
190+
// stdin should be forwarded only in embedded mode when stdio is piped
191+
match self {
192+
Self::Embedded(..) => {
193+
let stdin = std::io::stdin();
194+
let is_pipe = !stdin.is_terminal();
195+
is_pipe.then(|| rustix::io::dup(stdin).ok()).flatten()
196+
}
197+
Self::Server { .. } => None,
198+
}
199+
}
200+
180201
fn split(
181202
stream: impl AsyncRead + AsyncWrite + Send + Unpin + 'static,
182203
) -> (BoxedReader, BoxedWriter) {

0 commit comments

Comments
 (0)