diff --git a/Cargo.lock b/Cargo.lock index 38287a6e..91b2e796 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,6 +127,12 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arg_enum_proc_macro" version = "0.3.4" @@ -327,9 +333,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" dependencies = [ "jobserver", "libc", @@ -1349,9 +1355,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ "once_cell", "wasm-bindgen", @@ -1882,9 +1888,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.14" +version = "0.17.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" +checksum = "b67582bd5b65bdff614270e2ea89a1cf15bef71245cc1e5f7ea126977144211d" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -2766,9 +2772,9 @@ dependencies = [ [[package]] name = "trash" -version = "5.2.0" +version = "5.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defe1fdd4232e407b312377885a2c5396764972bddad87baf304753374a1bfc8" +checksum = "a8e5ca62c20366b4685e3e41fba17bc7c9bbdcb82e65a89d6fda2ceea5fffd2f" dependencies = [ "chrono", "libc", @@ -2776,6 +2782,7 @@ dependencies = [ "objc2", "objc2-foundation", "once_cell", + "percent-encoding", "scopeguard", "urlencoding", "windows", @@ -2989,9 +2996,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -3000,13 +3007,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -3015,9 +3021,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3025,9 +3031,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", @@ -3038,9 +3044,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "weezl" @@ -3515,6 +3521,7 @@ name = "yazi-fs" version = "0.3.3" dependencies = [ "anyhow", + "arc-swap", "bitflags 2.6.0", "dirs", "futures", diff --git a/yazi-adapter/src/drivers/chafa.rs b/yazi-adapter/src/drivers/chafa.rs index 63bc9ff2..5c9131d4 100644 --- a/yazi-adapter/src/drivers/chafa.rs +++ b/yazi-adapter/src/drivers/chafa.rs @@ -12,7 +12,7 @@ pub(crate) struct Chafa; impl Chafa { pub(crate) async fn image_show(path: &Path, max: Rect) -> Result { - let output = Command::new("chafa") + let child = Command::new("chafa") .args([ "-f", "symbols", @@ -32,9 +32,9 @@ impl Chafa { .stdout(Stdio::piped()) .stderr(Stdio::null()) .kill_on_drop(true) - .output() - .await?; + .spawn()?; + let output = child.wait_with_output().await?; if !output.status.success() { bail!("chafa failed with status: {}", output.status); } else if output.stdout.is_empty() { diff --git a/yazi-boot/src/boot.rs b/yazi-boot/src/boot.rs index 1f23dea8..f013ad65 100644 --- a/yazi-boot/src/boot.rs +++ b/yazi-boot/src/boot.rs @@ -1,7 +1,7 @@ use std::{collections::HashSet, ffi::OsString, path::PathBuf}; use serde::Serialize; -use yazi_fs::{Xdg, current_cwd, expand_path}; +use yazi_fs::{CWD, Xdg, expand_path}; #[derive(Debug, Default, Serialize)] pub struct Boot { @@ -20,7 +20,7 @@ pub struct Boot { impl Boot { fn parse_entries(entries: &[PathBuf]) -> (Vec, Vec) { if entries.is_empty() { - return (vec![current_cwd().unwrap()], vec![OsString::new()]); + return (vec![CWD.load().to_path_buf()], vec![OsString::new()]); } let mut cwds = Vec::with_capacity(entries.len()); diff --git a/yazi-cli/src/main.rs b/yazi-cli/src/main.rs index 4d59f8b1..1be1827f 100644 --- a/yazi-cli/src/main.rs +++ b/yazi-cli/src/main.rs @@ -7,6 +7,7 @@ use clap::Parser; #[tokio::main] async fn main() -> anyhow::Result<()> { yazi_shared::init(); + yazi_fs::init(); if std::env::args_os().nth(1).is_some_and(|s| s == "-V" || s == "--version") { println!( diff --git a/yazi-cli/src/package/git.rs b/yazi-cli/src/package/git.rs index 6be4a4f3..49e7c14e 100644 --- a/yazi-cli/src/package/git.rs +++ b/yazi-cli/src/package/git.rs @@ -12,11 +12,11 @@ impl Git { } pub(super) async fn fetch(path: &Path) -> Result<()> { - Self::exec(|c| c.current_dir(path).arg("fetch")).await + Self::exec(|c| c.arg("fetch").current_dir(path)).await } pub(super) async fn checkout(path: &Path, rev: &str) -> Result<()> { - Self::exec(|c| c.current_dir(path).args(["checkout", rev])).await + Self::exec(|c| c.args(["checkout", rev]).current_dir(path)).await } pub(super) async fn pull(path: &Path) -> Result<()> { @@ -27,8 +27,8 @@ impl Git { pub(super) async fn hash(path: &Path) -> Result { let output = Command::new("git") - .current_dir(path) .args(["rev-parse", "--short", "HEAD"]) + .current_dir(path) .output() .await .context("Failed to get current revision")?; diff --git a/yazi-core/src/manager/commands/refresh.rs b/yazi-core/src/manager/commands/refresh.rs index 8a0ab86d..fe5f5829 100644 --- a/yazi-core/src/manager/commands/refresh.rs +++ b/yazi-core/src/manager/commands/refresh.rs @@ -1,16 +1,15 @@ -use std::{env, path::MAIN_SEPARATOR}; +use std::path::MAIN_SEPARATOR; use crossterm::{execute, terminal::SetTitle}; use yazi_config::MANAGER; +use yazi_fs::CWD; use yazi_shared::event::CmdCow; use crate::{manager::Manager, tasks::Tasks}; impl Manager { pub fn refresh(&mut self, _: CmdCow, tasks: &Tasks) { - env::set_current_dir(self.cwd()).ok(); - env::set_var("PWD", self.cwd()); - + CWD.set(self.cwd()); if !MANAGER.title_format.is_empty() { execute!(std::io::stderr(), SetTitle(self.title())).ok(); } diff --git a/yazi-fm/src/main.rs b/yazi-fm/src/main.rs index 8379d72d..7d8c4e42 100644 --- a/yazi-fm/src/main.rs +++ b/yazi-fm/src/main.rs @@ -18,6 +18,8 @@ async fn main() -> anyhow::Result<()> { yazi_shared::init(); + yazi_fs::init(); + yazi_config::init()?; yazi_adapter::init()?; diff --git a/yazi-fs/Cargo.toml b/yazi-fs/Cargo.toml index 856010df..15389917 100644 --- a/yazi-fs/Cargo.toml +++ b/yazi-fs/Cargo.toml @@ -14,12 +14,13 @@ yazi-shared = { path = "../yazi-shared", version = "0.3.3" } # External dependencies anyhow = { workspace = true } +arc-swap = "1.7.1" bitflags = { workspace = true } dirs = { workspace = true } futures = { workspace = true } regex = { workspace = true } -tokio = { workspace = true } serde = { workspace = true } +tokio = { workspace = true } [target."cfg(unix)".dependencies] libc = { workspace = true } diff --git a/yazi-fs/src/cwd.rs b/yazi-fs/src/cwd.rs new file mode 100644 index 00000000..2acb6402 --- /dev/null +++ b/yazi-fs/src/cwd.rs @@ -0,0 +1,35 @@ +use std::{ops::Deref, path::PathBuf, sync::Arc}; + +use arc_swap::ArcSwap; +use yazi_shared::{RoCell, url::Url}; + +pub static CWD: RoCell = RoCell::new(); + +pub struct Cwd { + inner: ArcSwap, +} + +impl Deref for Cwd { + type Target = ArcSwap; + + fn deref(&self) -> &Self::Target { &self.inner } +} + +impl Default for Cwd { + fn default() -> Self { + let p = std::env::var_os("PWD") + .map(PathBuf::from) + .filter(|p| p.is_absolute()) + .or_else(|| std::env::current_dir().ok()) + .expect("failed to get current working directory"); + + Self { inner: ArcSwap::new(Arc::new(Url::from(p))) } + } +} + +impl Cwd { + pub fn set(&self, url: &Url) { + self.inner.store(Arc::new(url.clone())); + std::env::set_var("PWD", self.inner.load().as_ref()); + } +} diff --git a/yazi-fs/src/lib.rs b/yazi-fs/src/lib.rs index 235160e5..aa5f90c5 100644 --- a/yazi-fs/src/lib.rs +++ b/yazi-fs/src/lib.rs @@ -1,3 +1,5 @@ #![allow(clippy::if_same_then_else, clippy::option_map_unit_fn)] -yazi_macro::mod_flat!(cha file files filter fns op path sorter sorting stage step xdg); +yazi_macro::mod_flat!(cha cwd file files filter fns op path sorter sorting stage step xdg); + +pub fn init() { CWD.init(<_>::default()); } diff --git a/yazi-fs/src/path.rs b/yazi-fs/src/path.rs index 9eba494c..51e6c46f 100644 --- a/yazi-fs/src/path.rs +++ b/yazi-fs/src/path.rs @@ -3,12 +3,7 @@ use std::{borrow::Cow, env, ffi::OsString, future::Future, io, path::{Component, use tokio::fs; use yazi_shared::url::{Loc, Url}; -pub fn current_cwd() -> Option { - env::var_os("PWD") - .map(PathBuf::from) - .filter(|p| p.is_absolute()) - .or_else(|| env::current_dir().ok()) -} +use crate::CWD; #[inline] pub fn clean_path(path: impl AsRef) -> PathBuf { _clean_path(path.as_ref()) } @@ -65,10 +60,8 @@ fn _expand_path(p: &Path) -> PathBuf { clean_path(dirs::home_dir().unwrap_or_default().join(rest)) } else if p.is_absolute() { clean_path(p) - } else if let Some(cwd) = current_cwd() { - clean_path(cwd.join(p)) } else { - clean_path(p) + clean_path(CWD.load().join(p)) } } diff --git a/yazi-plugin/src/clipboard.rs b/yazi-plugin/src/clipboard.rs index 43351b55..ead9073f 100644 --- a/yazi-plugin/src/clipboard.rs +++ b/yazi-plugin/src/clipboard.rs @@ -16,6 +16,7 @@ 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() { @@ -30,7 +31,13 @@ impl Clipboard { ]; for (bin, args) in all { - let Ok(output) = Command::new(bin).args(args).kill_on_drop(true).output().await else { + let Ok(output) = Command::new(bin) + .args(args) + .current_dir(CWD.load().as_ref()) + .kill_on_drop(true) + .output() + .await + else { continue; }; if output.status.success() { @@ -58,6 +65,7 @@ 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(); @@ -72,6 +80,7 @@ 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 f5097d67..d909773c 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::File; +use yazi_fs::{CWD, File}; use yazi_shared::url::Url; pub struct FdOpt { @@ -37,6 +37,7 @@ 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 5e28cdef..4a7172cc 100644 --- a/yazi-plugin/src/external/rg.rs +++ b/yazi-plugin/src/external/rg.rs @@ -14,11 +14,11 @@ pub struct RgOpt { pub fn rg(opt: RgOpt) -> Result> { let mut child = Command::new("rg") - .current_dir(&opt.cwd) .args(["--color=never", "--files-with-matches", "--smart-case"]) .arg(if opt.hidden { "--hidden" } else { "--no-hidden" }) .args(opt.args) .arg(opt.subject) + .current_dir(&opt.cwd) .kill_on_drop(true) .stdout(Stdio::piped()) .stderr(Stdio::null()) diff --git a/yazi-plugin/src/process/command.rs b/yazi-plugin/src/process/command.rs index d2db0255..9df52738 100644 --- a/yazi-plugin/src/process/command.rs +++ b/yazi-plugin/src/process/command.rs @@ -2,6 +2,7 @@ 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}; @@ -18,7 +19,12 @@ 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.kill_on_drop(true).stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null()); + inner + .current_dir(CWD.load().as_ref()) + .kill_on_drop(true) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()); Ok(Self { inner }) })?; diff --git a/yazi-scheduler/Cargo.toml b/yazi-scheduler/Cargo.toml index 50dd3767..ef1d9e4b 100644 --- a/yazi-scheduler/Cargo.toml +++ b/yazi-scheduler/Cargo.toml @@ -30,4 +30,4 @@ tracing = { workspace = true } libc = { workspace = true } [target.'cfg(not(target_os = "android"))'.dependencies] -trash = "5.2.0" +trash = "5.2.1" diff --git a/yazi-scheduler/src/process/shell.rs b/yazi-scheduler/src/process/shell.rs index 22e699b2..633ed4fd 100644 --- a/yazi-scheduler/src/process/shell.rs +++ b/yazi-scheduler/src/process/shell.rs @@ -2,6 +2,7 @@ use std::{ffi::OsString, process::Stdio}; use anyhow::Result; use tokio::process::{Child, Command}; +use yazi_fs::CWD; #[derive(Default)] pub struct ShellOpt { @@ -29,6 +30,7 @@ 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()) @@ -50,6 +52,7 @@ 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())