fix: set the current working directory in a thread-safe way (#2043)

This commit is contained in:
三咲雅 · Misaki Masa 2024-12-14 13:26:37 +08:00 committed by GitHub
parent c1048debc5
commit 6e1948e7e1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 53 additions and 34 deletions

20
Cargo.lock generated
View file

@ -272,9 +272,9 @@ dependencies = [
[[package]]
name = "bstr"
version = "1.11.0"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22"
checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8"
dependencies = [
"memchr",
"serde",
@ -333,9 +333,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.3"
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d"
checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf"
dependencies = [
"jobserver",
"libc",
@ -2119,9 +2119,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.5.7"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [
"bitflags 2.6.0",
]
@ -2250,9 +2250,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.23"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
[[package]]
name = "serde"
@ -3738,9 +3738,9 @@ dependencies = [
[[package]]
name = "zune-jpeg"
version = "0.4.13"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16099418600b4d8f028622f73ff6e3deaabdff330fb9a2a131dea781ee8b0768"
checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028"
dependencies = [
"zune-core",
]

View file

@ -19,7 +19,7 @@ Yazi (means "duck") is a terminal file manager written in Rust, based on non-blo
- 💫 Vim-like input/pick/confirm/which/notify component, auto-completion for cd paths
- 🏷️ Multi-Tab Support, Cross-directory selection, Scrollable Preview (for videos, PDFs, archives, code, directories, etc.)
- 🔄 Bulk Renaming, Visual Mode, File Chooser
- 🎨 Theme System, Mouse Support, Trash Bin, Custom Layouts, CSI u
- 🎨 Theme System, Mouse Support, Trash Bin, Custom Layouts, CSI u, OSC 52
- ... and more!
https://github.com/sxyazi/yazi/assets/17523360/92ff23fa-0cd5-4f04-b387-894c12265cc7

View file

@ -9,8 +9,7 @@ use crate::{manager::Manager, tasks::Tasks};
impl Manager {
pub fn refresh(&mut self, _: CmdCow, tasks: &Tasks) {
CWD.set(self.cwd());
if !MANAGER.title_format.is_empty() {
if CWD.set(self.cwd()) && !MANAGER.title_format.is_empty() {
execute!(std::io::stderr(), SetTitle(self.title())).ok();
}

View file

@ -1,18 +1,16 @@
use std::{ops::Deref, path::PathBuf, sync::Arc};
use std::{env::{current_dir, set_current_dir}, ops::Deref, path::PathBuf, sync::{Arc, atomic::{self, AtomicBool}}};
use arc_swap::ArcSwap;
use yazi_shared::{RoCell, url::Url};
pub static CWD: RoCell<Cwd> = RoCell::new();
pub struct Cwd {
inner: ArcSwap<Url>,
}
pub struct Cwd(ArcSwap<Url>);
impl Deref for Cwd {
type Target = ArcSwap<Url>;
fn deref(&self) -> &Self::Target { &self.inner }
fn deref(&self) -> &Self::Target { &self.0 }
}
impl Default for Cwd {
@ -20,16 +18,40 @@ impl Default for Cwd {
let p = std::env::var_os("PWD")
.map(PathBuf::from)
.filter(|p| p.is_absolute())
.or_else(|| std::env::current_dir().ok())
.or_else(|| current_dir().ok())
.expect("failed to get current working directory");
Self { inner: ArcSwap::new(Arc::new(Url::from(p))) }
Self(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());
pub fn set(&self, url: &Url) -> bool {
if self.load().as_ref() == url {
return false;
}
self.store(Arc::new(url.clone()));
std::env::set_var("PWD", url);
Self::sync_cwd();
true
}
fn sync_cwd() {
static SYNCING: AtomicBool = AtomicBool::new(false);
if SYNCING.swap(true, atomic::Ordering::Relaxed) {
return;
}
tokio::task::spawn_blocking(move || {
_ = set_current_dir(CWD.load().as_ref());
let p = current_dir().unwrap_or_default();
SYNCING.store(false, atomic::Ordering::Relaxed);
if p != CWD.load().as_path() {
set_current_dir(CWD.load().as_ref()).ok();
}
});
}
}

View file

@ -2,9 +2,6 @@ use mlua::{Function, Lua};
use super::Utils;
#[cfg(unix)]
static HOSTNAME_CACHE: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
impl Utils {
#[cfg(unix)]
pub(super) fn uid(lua: &Lua) -> mlua::Result<Function> {
@ -46,12 +43,6 @@ impl Utils {
#[cfg(unix)]
pub(super) fn host_name(lua: &Lua) -> mlua::Result<Function> {
lua.create_function(|lua, ()| {
HOSTNAME_CACHE
.get_or_init(|| yazi_shared::hostname().ok())
.as_ref()
.map(|s| lua.create_string(s))
.transpose()
})
lua.create_function(|lua, ()| yazi_shared::hostname().map(|s| lua.create_string(s)).transpose())
}
}

View file

@ -2,7 +2,14 @@
pub static USERS_CACHE: crate::RoCell<uzers::UsersCache> = crate::RoCell::new();
#[cfg(unix)]
pub fn hostname() -> Result<String, std::io::Error> {
pub fn hostname() -> Option<&'static str> {
static CACHE: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
CACHE.get_or_init(|| hostname_impl().ok()).as_deref()
}
#[cfg(unix)]
fn hostname_impl() -> Result<String, std::io::Error> {
use std::io::{Error, ErrorKind};
use libc::{gethostname, strlen};