diff --git a/.github/workflows/draft.yml b/.github/workflows/draft.yml index df8a36df7..651faaf3c 100644 --- a/.github/workflows/draft.yml +++ b/.github/workflows/draft.yml @@ -8,7 +8,6 @@ on: env: SCCACHE_GHA_ENABLED: true - RUSTC_WRAPPER: sccache jobs: build-unix: @@ -25,7 +24,6 @@ jobs: target: aarch64-apple-darwin runs-on: ${{ matrix.os }} env: - RUSTC_WRAPPER: "" CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc steps: - uses: actions/checkout@v4 @@ -59,6 +57,7 @@ jobs: target: aarch64-pc-windows-msvc runs-on: ${{ matrix.os }} env: + RUSTC_WRAPPER: sccache YAZI_GEN_COMPLETIONS: true CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER: lld-link.exe CARGO_TARGET_AARCH64_PC_WINDOWS_MSVC_LINKER: lld-link.exe diff --git a/Cargo.lock b/Cargo.lock index 06a3995a8..456118a91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -394,9 +394,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" +checksum = "fd4db298d517d5fa00b2b84bbe044efd3fde43874a41db0d46f91994646a2da4" dependencies = [ "clap", ] @@ -485,14 +485,14 @@ dependencies = [ [[package]] name = "console" -version = "0.15.8" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", - "lazy_static", "libc", - "windows-sys 0.52.0", + "once_cell", + "windows-sys 0.59.0", ] [[package]] @@ -512,18 +512,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -540,9 +540,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" @@ -719,9 +719,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "equivalent" @@ -1031,11 +1031,11 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/yazi-boot/Cargo.toml b/yazi-boot/Cargo.toml index 7fcfc461d..edea8520f 100644 --- a/yazi-boot/Cargo.toml +++ b/yazi-boot/Cargo.toml @@ -22,7 +22,7 @@ serde = { workspace = true } [build-dependencies] clap = { workspace = true } -clap_complete = "4.5.38" +clap_complete = "4.5.39" clap_complete_fig = "4.5.2" clap_complete_nushell = "4.5.4" vergen-gitcl = { version = "1.0.2", features = [ "build", "rustc" ] } diff --git a/yazi-cli/Cargo.toml b/yazi-cli/Cargo.toml index 84bbf4b59..6500a4e78 100644 --- a/yazi-cli/Cargo.toml +++ b/yazi-cli/Cargo.toml @@ -30,7 +30,7 @@ yazi-shared = { path = "../yazi-shared", version = "0.4.2" } # External build dependencies anyhow = { workspace = true } clap = { workspace = true } -clap_complete = "4.5.38" +clap_complete = "4.5.39" clap_complete_fig = "4.5.2" clap_complete_nushell = "4.5.4" serde_json = { workspace = true } diff --git a/yazi-core/src/manager/commands/bulk_rename.rs b/yazi-core/src/manager/commands/bulk_rename.rs index cf74fc419..f96f9a003 100644 --- a/yazi-core/src/manager/commands/bulk_rename.rs +++ b/yazi-core/src/manager/commands/bulk_rename.rs @@ -22,6 +22,7 @@ impl Manager { let root = max_common_root(&old); let old: Vec<_> = old.into_iter().map(|p| p.strip_prefix(&root).unwrap().to_owned()).collect(); + let cwd = self.cwd().clone(); tokio::spawn(async move { let tmp = PREVIEW.tmpfile("bulk"); let s = old.iter().map(|o| o.as_os_str()).collect::>().join(OsStr::new("\n")); @@ -34,8 +35,11 @@ impl Manager { .await?; defer! { tokio::spawn(fs::remove_file(tmp.clone())); } - TasksProxy::process_exec(vec![OsString::new(), tmp.to_owned().into()], Cow::Borrowed(opener)) - .await; + TasksProxy::process_exec(Cow::Borrowed(opener), cwd, vec![ + OsString::new(), + tmp.to_owned().into(), + ]) + .await; let _permit = HIDER.acquire().await.unwrap(); defer!(AppProxy::resume()); diff --git a/yazi-core/src/manager/commands/open.rs b/yazi-core/src/manager/commands/open.rs index baf0e4994..acdbdca70 100644 --- a/yazi-core/src/manager/commands/open.rs +++ b/yazi-core/src/manager/commands/open.rs @@ -40,6 +40,7 @@ impl Manager { return; } + let cwd = self.cwd().clone(); let (mut done, mut todo) = (Vec::with_capacity(selected.len()), vec![]); for u in selected { if self.mimetype.contains(u) { @@ -53,7 +54,7 @@ impl Manager { if todo.is_empty() { return self - .open_do(OpenDoOpt { hovered, targets: done, interactive: opt.interactive }, tasks); + .open_do(OpenDoOpt { cwd, hovered, targets: done, interactive: opt.interactive }, tasks); } tokio::spawn(async move { @@ -71,7 +72,12 @@ impl Manager { } } - ManagerProxy::open_do(OpenDoOpt { hovered, targets: done, interactive: opt.interactive }); + ManagerProxy::open_do(OpenDoOpt { + cwd, + hovered, + targets: done, + interactive: opt.interactive, + }); }); } @@ -88,7 +94,7 @@ impl Manager { if targets.is_empty() { return; } else if !opt.interactive { - return tasks.process_from_files(opt.hovered, targets); + return tasks.process_from_files(opt.cwd, opt.hovered, targets); } let openers: Vec<_> = OPEN.common_openers(&targets); @@ -102,7 +108,7 @@ impl Manager { openers.iter().map(|o| o.desc.clone()).collect(), )); if let Ok(choice) = result.await { - TasksProxy::open_with(urls, Cow::Borrowed(openers[choice])); + TasksProxy::open_with(Cow::Borrowed(openers[choice]), opt.cwd, urls); } }); } diff --git a/yazi-core/src/tab/commands/shell.rs b/yazi-core/src/tab/commands/shell.rs index 4a2a7723e..f62c7cfff 100644 --- a/yazi-core/src/tab/commands/shell.rs +++ b/yazi-core/src/tab/commands/shell.rs @@ -3,16 +3,19 @@ use std::{borrow::Cow, fmt::Display}; use anyhow::bail; use yazi_config::{open::Opener, popup::InputCfg}; use yazi_proxy::{AppProxy, InputProxy, TasksProxy}; -use yazi_shared::event::{CmdCow, Data}; +use yazi_shared::{event::{CmdCow, Data}, url::Url}; use crate::tab::Tab; pub struct Opt { - run: Cow<'static, str>, + run: Cow<'static, str>, + cwd: Option, + block: bool, orphan: bool, interactive: bool, - cursor: Option, + + cursor: Option, } impl TryFrom for Opt { @@ -20,11 +23,14 @@ impl TryFrom for Opt { fn try_from(mut c: CmdCow) -> Result { let me = Self { - run: c.take_first_str().unwrap_or_default(), + run: c.take_first_str().unwrap_or_default(), + cwd: c.take_url("cwd"), + block: c.bool("block"), orphan: c.bool("orphan"), interactive: c.bool("interactive"), - cursor: c.get("cursor").and_then(Data::as_usize), + + cursor: c.get("cursor").and_then(Data::as_usize), }; if me.cursor.is_some_and(|c| c > me.run.chars().count()) { @@ -46,6 +52,7 @@ impl Tab { Err(e) => return AppProxy::notify_warn("`shell` command", e), }; + let cwd = opt.cwd.take().unwrap_or_else(|| self.cwd().clone()); let selected = self.hovered_and_selected(true).cloned().collect(); tokio::spawn(async move { if opt.interactive { @@ -61,7 +68,6 @@ impl Tab { } TasksProxy::open_with( - selected, Cow::Owned(Opener { run: opt.run.into_owned(), block: opt.block, @@ -70,6 +76,8 @@ impl Tab { for_: None, spread: true, }), + cwd, + selected, ); }); } diff --git a/yazi-core/src/tasks/commands/open_with.rs b/yazi-core/src/tasks/commands/open_with.rs index 00aba4198..3bee010f9 100644 --- a/yazi-core/src/tasks/commands/open_with.rs +++ b/yazi-core/src/tasks/commands/open_with.rs @@ -6,6 +6,7 @@ impl Tasks { pub fn open_with(&mut self, opt: impl TryInto) { if let Ok(opt) = opt.try_into() { self.process_from_opener( + opt.cwd, opt.opener, opt.targets.into_iter().map(|u| u.into_path().into_os_string()).collect(), ); diff --git a/yazi-core/src/tasks/commands/process_exec.rs b/yazi-core/src/tasks/commands/process_exec.rs index e53ba8ce4..0777d42e3 100644 --- a/yazi-core/src/tasks/commands/process_exec.rs +++ b/yazi-core/src/tasks/commands/process_exec.rs @@ -5,7 +5,7 @@ use crate::tasks::Tasks; impl Tasks { pub fn process_exec(&mut self, opt: impl TryInto) { if let Ok(opt) = opt.try_into() { - self.scheduler.process_open(opt.opener, opt.args, Some(opt.done)); + self.scheduler.process_open(opt); } } } diff --git a/yazi-core/src/tasks/process.rs b/yazi-core/src/tasks/process.rs index 9e0d9190e..bcfc518a4 100644 --- a/yazi-core/src/tasks/process.rs +++ b/yazi-core/src/tasks/process.rs @@ -1,12 +1,13 @@ use std::{borrow::Cow, collections::HashMap, ffi::OsString, mem}; use yazi_config::{OPEN, open::Opener}; +use yazi_proxy::options::ProcessExecOpt; use yazi_shared::url::Url; use super::Tasks; impl Tasks { - pub fn process_from_files(&self, hovered: Url, targets: Vec<(Url, Cow)>) { + pub fn process_from_files(&self, cwd: Url, hovered: Url, targets: Vec<(Url, Cow)>) { let mut openers = HashMap::new(); for (url, mime) in targets { if let Some(opener) = OPEN.openers(&url, mime).and_then(|o| o.first().copied()) { @@ -15,27 +16,38 @@ impl Tasks { } for (opener, args) in openers { self.process_from_opener( + cwd.clone(), Cow::Borrowed(opener), args.into_iter().map(|u| u.into_path().into_os_string()).collect(), ); } } - pub fn process_from_opener(&self, opener: Cow<'static, Opener>, mut args: Vec) { + pub fn process_from_opener( + &self, + cwd: Url, + opener: Cow<'static, Opener>, + mut args: Vec, + ) { if opener.spread { - self.scheduler.process_open(opener, args, None); + self.scheduler.process_open(ProcessExecOpt { cwd, opener, args, done: None }); return; } if args.is_empty() { return; } if args.len() == 2 { - self.scheduler.process_open(opener, args, None); + self.scheduler.process_open(ProcessExecOpt { cwd, opener, args, done: None }); return; } let hovered = mem::take(&mut args[0]); for target in args.into_iter().skip(1) { - self.scheduler.process_open(opener.clone(), vec![hovered.clone(), target], None); + self.scheduler.process_open(ProcessExecOpt { + cwd: cwd.clone(), + opener: opener.clone(), + args: vec![hovered.clone(), target], + done: None, + }); } } } diff --git a/yazi-plugin/preset/plugins/zoxide.lua b/yazi-plugin/preset/plugins/zoxide.lua index 9303c1bab..39ff6c94b 100644 --- a/yazi-plugin/preset/plugins/zoxide.lua +++ b/yazi-plugin/preset/plugins/zoxide.lua @@ -67,6 +67,7 @@ local function setup(_, opts) "cd", function() ya.manager_emit("shell", { + cwd = fs.cwd(), orphan = true, "zoxide add " .. ya.quote(tostring(cx.active.current.cwd)), }) diff --git a/yazi-plugin/src/clipboard.rs b/yazi-plugin/src/clipboard.rs index ead9073f3..43351b550 100644 --- a/yazi-plugin/src/clipboard.rs +++ b/yazi-plugin/src/clipboard.rs @@ -16,7 +16,6 @@ impl Clipboard { use std::os::unix::prelude::OsStringExt; use tokio::process::Command; - use yazi_fs::CWD; use yazi_shared::in_ssh_connection; if in_ssh_connection() { @@ -31,13 +30,7 @@ impl Clipboard { ]; for (bin, args) in all { - let Ok(output) = Command::new(bin) - .args(args) - .current_dir(CWD.load().as_ref()) - .kill_on_drop(true) - .output() - .await - else { + let Ok(output) = Command::new(bin).args(args).kill_on_drop(true).output().await else { continue; }; if output.status.success() { @@ -65,7 +58,6 @@ impl Clipboard { use crossterm::execute; use tokio::{io::AsyncWriteExt, process::Command}; - use yazi_fs::CWD; s.as_ref().clone_into(&mut self.content.lock()); execute!(BufWriter::new(stderr()), osc52::SetClipboard::new(s.as_ref())).ok(); @@ -80,7 +72,6 @@ impl Clipboard { for (bin, args) in all { let cmd = Command::new(bin) .args(args) - .current_dir(CWD.load().as_ref()) .stdin(Stdio::piped()) .stdout(Stdio::null()) .stderr(Stdio::null()) diff --git a/yazi-plugin/src/external/fd.rs b/yazi-plugin/src/external/fd.rs index d909773cb..f5097d673 100644 --- a/yazi-plugin/src/external/fd.rs +++ b/yazi-plugin/src/external/fd.rs @@ -2,7 +2,7 @@ use std::process::Stdio; use anyhow::Result; use tokio::{io::{AsyncBufReadExt, BufReader}, process::{Child, Command}, sync::mpsc::{self, UnboundedReceiver}}; -use yazi_fs::{CWD, File}; +use yazi_fs::File; use yazi_shared::url::Url; pub struct FdOpt { @@ -37,7 +37,6 @@ fn spawn(program: &str, opt: &FdOpt) -> std::io::Result { .arg(if opt.hidden { "--hidden" } else { "--no-hidden" }) .args(&opt.args) .arg(&opt.subject) - .current_dir(CWD.load().as_ref()) .kill_on_drop(true) .stdout(Stdio::piped()) .stderr(Stdio::null()) diff --git a/yazi-plugin/src/external/rg.rs b/yazi-plugin/src/external/rg.rs index 4a7172ccd..c4d5674e2 100644 --- a/yazi-plugin/src/external/rg.rs +++ b/yazi-plugin/src/external/rg.rs @@ -18,7 +18,7 @@ pub fn rg(opt: RgOpt) -> Result> { .arg(if opt.hidden { "--hidden" } else { "--no-hidden" }) .args(opt.args) .arg(opt.subject) - .current_dir(&opt.cwd) + .arg(&opt.cwd) .kill_on_drop(true) .stdout(Stdio::piped()) .stderr(Stdio::null()) diff --git a/yazi-plugin/src/fs/fs.rs b/yazi-plugin/src/fs/fs.rs index 596ce1f77..46ada6989 100644 --- a/yazi-plugin/src/fs/fs.rs +++ b/yazi-plugin/src/fs/fs.rs @@ -8,6 +8,7 @@ use crate::{Error, bindings::{Cast, Cha}, file::File, url::{Url, UrlRef}}; pub fn compose(lua: &Lua) -> mlua::Result { let index = lua.create_function(|lua, (ts, key): (Table, mlua::String)| { let value = match key.as_bytes().as_ref() { + b"cwd" => cwd(lua)?, b"cha" => cha(lua)?, b"write" => write(lua)?, b"remove" => remove(lua)?, @@ -27,6 +28,13 @@ pub fn compose(lua: &Lua) -> mlua::Result
{ Ok(fs) } +fn cwd(lua: &Lua) -> mlua::Result { + lua.create_function(|lua, ()| match std::env::current_dir() { + Ok(p) => (Url::cast(lua, p)?, Value::Nil).into_lua_multi(lua), + Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(lua), + }) +} + fn cha(lua: &Lua) -> mlua::Result { lua.create_async_function(|lua, (url, follow): (UrlRef, Option)| async move { let meta = if follow.unwrap_or(false) { diff --git a/yazi-plugin/src/lua.rs b/yazi-plugin/src/lua.rs index d80ef526e..484d0978c 100644 --- a/yazi-plugin/src/lua.rs +++ b/yazi-plugin/src/lua.rs @@ -24,6 +24,7 @@ fn stage_1(lua: &'static Lua) -> Result<()> { let globals = lua.globals(); globals.raw_set("ui", crate::elements::compose(lua)?)?; globals.raw_set("ya", crate::utils::compose(lua, false)?)?; + globals.raw_set("fs", crate::fs::compose(lua)?)?; globals.raw_set("ps", crate::pubsub::compose(lua)?)?; crate::Error::install(lua)?; diff --git a/yazi-plugin/src/process/command.rs b/yazi-plugin/src/process/command.rs index 9df527389..d2db02550 100644 --- a/yazi-plugin/src/process/command.rs +++ b/yazi-plugin/src/process/command.rs @@ -2,7 +2,6 @@ use std::process::Stdio; use mlua::{AnyUserData, ExternalError, IntoLuaMulti, Lua, Table, UserData, Value}; use tokio::process::{ChildStderr, ChildStdin, ChildStdout}; -use yazi_fs::CWD; use super::{Child, output::Output}; use crate::{Error, process::Status}; @@ -19,12 +18,7 @@ impl Command { pub fn install(lua: &Lua) -> mlua::Result<()> { let new = lua.create_function(|_, (_, program): (Table, String)| { let mut inner = tokio::process::Command::new(program); - inner - .current_dir(CWD.load().as_ref()) - .kill_on_drop(true) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()); + inner.kill_on_drop(true).stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null()); Ok(Self { inner }) })?; diff --git a/yazi-proxy/src/options/open.rs b/yazi-proxy/src/options/open.rs index 714556333..0e063ffec 100644 --- a/yazi-proxy/src/options/open.rs +++ b/yazi-proxy/src/options/open.rs @@ -6,6 +6,7 @@ use yazi_shared::{event::CmdCow, url::Url}; // --- Open #[derive(Default)] pub struct OpenDoOpt { + pub cwd: Url, pub hovered: Url, pub targets: Vec<(Url, Cow<'static, str>)>, pub interactive: bool, @@ -17,8 +18,9 @@ impl From for OpenDoOpt { // --- Open with pub struct OpenWithOpt { - pub targets: Vec, pub opener: Cow<'static, Opener>, + pub cwd: Url, + pub targets: Vec, } impl TryFrom for OpenWithOpt { diff --git a/yazi-proxy/src/options/process.rs b/yazi-proxy/src/options/process.rs index 23b6b7c31..e919ce1b8 100644 --- a/yazi-proxy/src/options/process.rs +++ b/yazi-proxy/src/options/process.rs @@ -2,13 +2,14 @@ use std::{borrow::Cow, ffi::OsString}; use tokio::sync::oneshot; use yazi_config::open::Opener; -use yazi_shared::event::CmdCow; +use yazi_shared::{event::CmdCow, url::Url}; // --- Exec pub struct ProcessExecOpt { - pub args: Vec, + pub cwd: Url, pub opener: Cow<'static, Opener>, - pub done: oneshot::Sender<()>, + pub args: Vec, + pub done: Option>, } impl TryFrom for ProcessExecOpt { diff --git a/yazi-proxy/src/tasks.rs b/yazi-proxy/src/tasks.rs index 44dc76fea..667a5a8ea 100644 --- a/yazi-proxy/src/tasks.rs +++ b/yazi-proxy/src/tasks.rs @@ -11,18 +11,23 @@ pub struct TasksProxy; impl TasksProxy { #[inline] - pub fn open_with(targets: Vec, opener: Cow<'static, Opener>) { + pub fn open_with(opener: Cow<'static, Opener>, cwd: Url, targets: Vec) { emit!(Call( - Cmd::new("open_with").with_any("option", OpenWithOpt { targets, opener }), + Cmd::new("open_with").with_any("option", OpenWithOpt { opener, cwd, targets }), Layer::Tasks )); } #[inline] - pub async fn process_exec(args: Vec, opener: Cow<'static, Opener>) { + pub async fn process_exec(opener: Cow<'static, Opener>, cwd: Url, args: Vec) { let (tx, rx) = oneshot::channel(); emit!(Call( - Cmd::new("process_exec").with_any("option", ProcessExecOpt { args, opener, done: tx }), + Cmd::new("process_exec").with_any("option", ProcessExecOpt { + cwd, + opener, + args, + done: Some(tx) + }), Layer::Tasks )); rx.await.ok(); diff --git a/yazi-scheduler/src/process/op.rs b/yazi-scheduler/src/process/op.rs index e00d39a59..cc224e651 100644 --- a/yazi-scheduler/src/process/op.rs +++ b/yazi-scheduler/src/process/op.rs @@ -1,38 +1,45 @@ use std::ffi::OsString; use tokio::sync::mpsc; +use yazi_shared::url::Url; use super::ShellOpt; +// --- Block #[derive(Debug)] pub struct ProcessOpBlock { pub id: usize, + pub cwd: Url, pub cmd: OsString, pub args: Vec, } impl From for ShellOpt { fn from(op: ProcessOpBlock) -> Self { - Self { cmd: op.cmd, args: op.args, piped: false, orphan: false } + Self { cwd: op.cwd, cmd: op.cmd, args: op.args, piped: false, orphan: false } } } +// --- Orphan #[derive(Debug)] pub struct ProcessOpOrphan { pub id: usize, + pub cwd: Url, pub cmd: OsString, pub args: Vec, } impl From for ShellOpt { fn from(op: ProcessOpOrphan) -> Self { - Self { cmd: op.cmd, args: op.args, piped: false, orphan: true } + Self { cwd: op.cwd, cmd: op.cmd, args: op.args, piped: false, orphan: true } } } +// --- Bg #[derive(Debug)] pub struct ProcessOpBg { pub id: usize, + pub cwd: Url, pub cmd: OsString, pub args: Vec, pub cancel: mpsc::Receiver<()>, @@ -40,6 +47,6 @@ pub struct ProcessOpBg { impl From for ShellOpt { fn from(op: ProcessOpBg) -> Self { - Self { cmd: op.cmd, args: op.args, piped: true, orphan: false } + Self { cwd: op.cwd, cmd: op.cmd, args: op.args, piped: true, orphan: false } } } diff --git a/yazi-scheduler/src/process/process.rs b/yazi-scheduler/src/process/process.rs index 26d8f4cd1..f693b19fb 100644 --- a/yazi-scheduler/src/process/process.rs +++ b/yazi-scheduler/src/process/process.rs @@ -53,8 +53,13 @@ impl Process { pub async fn bg(&self, task: ProcessOpBg) -> Result<()> { self.prog.send(TaskProg::New(task.id, 0))?; - let mut child = - super::shell(ShellOpt { cmd: task.cmd, args: task.args, piped: true, ..Default::default() })?; + let mut child = super::shell(ShellOpt { + cwd: task.cwd, + cmd: task.cmd, + args: task.args, + piped: true, + orphan: false, + })?; let mut stdout = BufReader::new(child.stdout.take().unwrap()).lines(); let mut stderr = BufReader::new(child.stderr.take().unwrap()).lines(); diff --git a/yazi-scheduler/src/process/shell.rs b/yazi-scheduler/src/process/shell.rs index 633ed4fd3..36505cad6 100644 --- a/yazi-scheduler/src/process/shell.rs +++ b/yazi-scheduler/src/process/shell.rs @@ -2,10 +2,10 @@ use std::{ffi::OsString, process::Stdio}; use anyhow::Result; use tokio::process::{Child, Command}; -use yazi_fs::CWD; +use yazi_shared::url::Url; -#[derive(Default)] pub struct ShellOpt { + pub cwd: Url, pub cmd: OsString, pub args: Vec, pub piped: bool, @@ -30,12 +30,12 @@ pub fn shell(opt: ShellOpt) -> Result { return Ok(unsafe { Command::new("sh") .arg("-c") - .current_dir(CWD.load().as_ref()) .stdin(opt.stdio()) .stdout(opt.stdio()) .stderr(opt.stdio()) .arg(opt.cmd) .args(opt.args) + .current_dir(opt.cwd) .kill_on_drop(!opt.orphan) .pre_exec(move || { if opt.orphan && libc::setpgid(0, 0) < 0 { @@ -52,10 +52,10 @@ pub fn shell(opt: ShellOpt) -> Result { Command::new("cmd.exe") .raw_arg("/C") .raw_arg(parser::parse(&opt.cmd, &opt.args)) - .current_dir(CWD.load().as_ref()) .stdin(opt.stdio()) .stdout(opt.stdio()) .stderr(opt.stdio()) + .current_dir(opt.cwd) .kill_on_drop(!opt.orphan) .spawn()?, ) diff --git a/yazi-scheduler/src/scheduler.rs b/yazi-scheduler/src/scheduler.rs index 4527b4620..c20ea0b63 100644 --- a/yazi-scheduler/src/scheduler.rs +++ b/yazi-scheduler/src/scheduler.rs @@ -1,13 +1,13 @@ -use std::{borrow::Cow, ffi::OsString, future::Future, sync::Arc, time::Duration}; +use std::{ffi::OsString, future::Future, sync::Arc, time::Duration}; use anyhow::Result; use futures::{FutureExt, future::BoxFuture}; use parking_lot::Mutex; -use tokio::{fs, select, sync::{mpsc::{self, UnboundedReceiver}, oneshot}, task::JoinHandle}; -use yazi_config::{TASKS, open::Opener, plugin::{Fetcher, Preloader}}; +use tokio::{fs, select, sync::mpsc::{self, UnboundedReceiver}, task::JoinHandle}; +use yazi_config::{TASKS, plugin::{Fetcher, Preloader}}; use yazi_dds::Pump; use yazi_fs::{must_be_dir, remove_dir_clean, unique_name}; -use yazi_proxy::{ManagerProxy, options::PluginOpt}; +use yazi_proxy::{ManagerProxy, options::{PluginOpt, ProcessExecOpt}}; use yazi_shared::{Throttle, url::Url}; use super::{Ongoing, TaskProg, TaskStage}; @@ -259,12 +259,7 @@ impl Scheduler { } } - pub fn process_open( - &self, - opener: Cow<'static, Opener>, - args: Vec, - done: Option>, - ) { + pub fn process_open(&self, ProcessExecOpt { cwd, opener, args, done }: ProcessExecOpt) { let name = { let args = args.iter().map(|a| a.to_string_lossy()).collect::>().join(" "); if args.is_empty() { @@ -299,11 +294,11 @@ impl Scheduler { let process = self.process.clone(); self.send_micro(id, NORMAL, async move { if opener.block { - process.block(ProcessOpBlock { id, cmd, args }).await + process.block(ProcessOpBlock { id, cwd, cmd, args }).await } else if opener.orphan { - process.orphan(ProcessOpOrphan { id, cmd, args }).await + process.orphan(ProcessOpOrphan { id, cwd, cmd, args }).await } else { - process.bg(ProcessOpBg { id, cmd, args, cancel: cancel_rx }).await + process.bg(ProcessOpBg { id, cwd, cmd, args, cancel: cancel_rx }).await } }); }