diff --git a/yazi-core/src/input/commands/kill.rs b/yazi-core/src/input/commands/kill.rs index 754f04ded..d1cbeb074 100644 --- a/yazi-core/src/input/commands/kill.rs +++ b/yazi-core/src/input/commands/kill.rs @@ -70,6 +70,7 @@ impl Input { let snap = self.snap_mut(); match opt.kind.as_str() { + "all" => self.kill_range(..), "bol" => { let end = snap.idx(snap.cursor).unwrap_or(snap.len()); self.kill_range(..end) diff --git a/yazi-core/src/input/input.rs b/yazi-core/src/input/input.rs index 243f24dce..3fea5764f 100644 --- a/yazi-core/src/input/input.rs +++ b/yazi-core/src/input/input.rs @@ -87,16 +87,17 @@ impl Input { } pub(super) fn flush_value(&mut self) { + let Some(tx) = &self.callback else { return }; self.ticket = self.ticket.wrapping_add(1); if self.realtime { let value = self.snap().value.clone(); - self.callback.as_ref().unwrap().send(Err(InputError::Typed(value))).ok(); + tx.send(Err(InputError::Typed(value))).ok(); } if self.completion { let before = self.partition()[0].to_owned(); - self.callback.as_ref().unwrap().send(Err(InputError::Completed(before, self.ticket))).ok(); + tx.send(Err(InputError::Completed(before, self.ticket))).ok(); } } } diff --git a/yazi-plugin/src/process/child.rs b/yazi-plugin/src/process/child.rs index 268726abd..a56ad39f9 100644 --- a/yazi-plugin/src/process/child.rs +++ b/yazi-plugin/src/process/child.rs @@ -1,25 +1,25 @@ use std::time::Duration; use futures::future::try_join3; -use mlua::{AnyUserData, IntoLuaMulti, Table, UserData, Value}; -use tokio::{io::{self, AsyncBufReadExt, AsyncReadExt, BufReader}, process::{ChildStderr, ChildStdin, ChildStdout}, select}; +use mlua::{AnyUserData, ExternalError, IntoLua, IntoLuaMulti, Table, UserData, Value}; +use tokio::{io::{self, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufWriter}, process::{ChildStderr, ChildStdin, ChildStdout}, select}; use super::Status; use crate::process::Output; pub struct Child { inner: tokio::process::Child, - _stdin: Option, + stdin: Option>, stdout: Option>, stderr: Option>, } impl Child { pub fn new(mut inner: tokio::process::Child) -> Self { - let stdin = inner.stdin.take(); + let stdin = inner.stdin.take().map(BufWriter::new); let stdout = inner.stdout.take().map(BufReader::new); let stderr = inner.stderr.take().map(BufReader::new); - Self { inner, _stdin: stdin, stdout, stderr } + Self { inner, stdin, stdout, stderr } } } @@ -69,6 +69,26 @@ impl UserData for Child { Err(_) => Ok((String::new(), 3u8)), } }); + + methods.add_async_method_mut("write_all", |lua, me, src: mlua::String| async move { + let Some(stdin) = &mut me.stdin else { + return Err("stdin is not piped".into_lua_err()); + }; + match stdin.write_all(src.as_bytes()).await { + Ok(()) => (true, Value::Nil).into_lua_multi(lua), + Err(e) => (false, e.raw_os_error()).into_lua_multi(lua), + } + }); + methods.add_async_method_mut("flush", |lua, me, ()| async move { + let Some(stdin) = &mut me.stdin else { + return Err("stdin is not piped".into_lua_err()); + }; + match stdin.flush().await { + Ok(()) => (true, Value::Nil).into_lua_multi(lua), + Err(e) => (false, e.raw_os_error()).into_lua_multi(lua), + } + }); + methods.add_async_method_mut("wait", |lua, me, ()| async move { match me.inner.wait().await { Ok(status) => (Status::new(status), Value::Nil).into_lua_multi(lua), @@ -107,5 +127,18 @@ impl UserData for Child { Ok(_) => (true, Value::Nil).into_lua_multi(lua), Err(e) => (false, e.raw_os_error()).into_lua_multi(lua), }); + + methods.add_method_mut("take_stdin", |lua, me, ()| match me.stdin.take() { + Some(stdin) => lua.create_any_userdata(stdin.into_inner())?.into_lua(lua), + None => Ok(Value::Nil), + }); + methods.add_method_mut("take_stdout", |lua, me, ()| match me.stdout.take() { + Some(stdout) => lua.create_any_userdata(stdout.into_inner())?.into_lua(lua), + None => Ok(Value::Nil), + }); + methods.add_method_mut("take_stderr", |lua, me, ()| match me.stderr.take() { + Some(stderr) => lua.create_any_userdata(stderr.into_inner())?.into_lua(lua), + None => Ok(Value::Nil), + }); } } diff --git a/yazi-plugin/src/process/command.rs b/yazi-plugin/src/process/command.rs index be57d68a4..5877345c1 100644 --- a/yazi-plugin/src/process/command.rs +++ b/yazi-plugin/src/process/command.rs @@ -1,6 +1,7 @@ use std::process::Stdio; -use mlua::{AnyUserData, IntoLuaMulti, Lua, Table, UserData, Value}; +use mlua::{AnyUserData, ExternalError, IntoLuaMulti, Lua, Table, UserData, Value}; +use tokio::process::{ChildStderr, ChildStdin, ChildStdout}; use super::{output::Output, Child}; @@ -36,6 +37,33 @@ impl Command { impl UserData for Command { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + #[inline] + fn make_stdio(v: Value) -> mlua::Result { + match v { + Value::Integer(n) => { + return Ok(match n as u8 { + PIPED => Stdio::piped(), + INHERIT => Stdio::inherit(), + _ => Stdio::null(), + }); + } + Value::UserData(ud) => { + if let Ok(stdin) = ud.take::() { + return Ok(stdin.try_into()?); + } else if let Ok(stdout) = ud.take::() { + return Ok(stdout.try_into()?); + } else if let Ok(stderr) = ud.take::() { + return Ok(stderr.try_into()?); + } + } + _ => {} + } + + Err( + "must be one of Command.NULL, Command.PIPED, Command.INHERIT, or a ChildStdin, ChildStdout, or ChildStderr".into_lua_err(), + ) + } + methods.add_function("arg", |_, (ud, arg): (AnyUserData, mlua::String)| { ud.borrow_mut::()?.inner.arg(arg.to_string_lossy().as_ref()); Ok(ud) @@ -62,28 +90,16 @@ impl UserData for Command { Ok(ud) }, ); - methods.add_function("stdin", |_, (ud, stdio): (AnyUserData, u8)| { - ud.borrow_mut::()?.inner.stdin(match stdio { - PIPED => Stdio::piped(), - INHERIT => Stdio::inherit(), - _ => Stdio::null(), - }); + methods.add_function("stdin", |_, (ud, stdio): (AnyUserData, Value)| { + ud.borrow_mut::()?.inner.stdin(make_stdio(stdio)?); Ok(ud) }); - methods.add_function("stdout", |_, (ud, stdio): (AnyUserData, u8)| { - ud.borrow_mut::()?.inner.stdout(match stdio { - PIPED => Stdio::piped(), - INHERIT => Stdio::inherit(), - _ => Stdio::null(), - }); + methods.add_function("stdout", |_, (ud, stdio): (AnyUserData, Value)| { + ud.borrow_mut::()?.inner.stdout(make_stdio(stdio)?); Ok(ud) }); - methods.add_function("stderr", |_, (ud, stdio): (AnyUserData, u8)| { - ud.borrow_mut::()?.inner.stderr(match stdio { - PIPED => Stdio::piped(), - INHERIT => Stdio::inherit(), - _ => Stdio::null(), - }); + methods.add_function("stderr", |_, (ud, stdio): (AnyUserData, Value)| { + ud.borrow_mut::()?.inner.stderr(make_stdio(stdio)?); Ok(ud) }); methods.add_method_mut("spawn", |lua, me, ()| match me.inner.spawn() {