mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 14:51:03 +00:00
fix: a race condition in concurrent directory loading on a slow device (#3271)
This commit is contained in:
parent
b16c4894dc
commit
157156b5b8
8 changed files with 107 additions and 64 deletions
4
.github/workflows/validate-form.yml
vendored
4
.github/workflows/validate-form.yml
vendored
|
|
@ -15,9 +15,9 @@ jobs:
|
|||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v5
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-js: 20
|
||||
node-version: 20
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
|
|
|
|||
78
Cargo.lock
generated
78
Cargo.lock
generated
|
|
@ -319,11 +319,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.4"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -527,9 +527,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.49"
|
||||
version = "4.5.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f"
|
||||
checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -537,9 +537,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.49"
|
||||
version = "4.5.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730"
|
||||
checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -740,7 +740,7 @@ version = "0.28.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"crossterm_winapi",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
|
|
@ -756,7 +756,7 @@ version = "0.29.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"crossterm_winapi",
|
||||
"derive_more",
|
||||
"document-features",
|
||||
|
|
@ -1680,9 +1680,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "2.0.6"
|
||||
version = "2.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
|
||||
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
|
|
@ -1690,7 +1693,7 @@ version = "0.11.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
|
|
@ -1768,9 +1771,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
|
|
@ -1941,7 +1944,7 @@ version = "0.1.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
|
@ -2016,9 +2019,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "luajit-src"
|
||||
version = "210.6.1+f9140a6"
|
||||
version = "210.6.2+25a61a1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "813bd31f2759443affa687c0d9c5eb5cf6cb0e898810ab197408431d746054bf"
|
||||
checksum = "89b3e51e810ed7940b3d057d4cb63ef5faa8261fc8f46fb1905947a22f1c89ec"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"which",
|
||||
|
|
@ -2162,7 +2165,7 @@ version = "0.29.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
|
|
@ -2190,7 +2193,7 @@ version = "8.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"kqueue",
|
||||
|
|
@ -2352,7 +2355,7 @@ version = "0.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"objc2",
|
||||
]
|
||||
|
||||
|
|
@ -2373,9 +2376,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
|||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.1"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "onig"
|
||||
|
|
@ -2383,7 +2386,7 @@ version = "6.5.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"onig_sys",
|
||||
|
|
@ -2670,7 +2673,7 @@ version = "0.18.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
|
|
@ -2908,7 +2911,7 @@ version = "0.29.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"cassowary",
|
||||
"compact_str",
|
||||
"crossterm 0.28.1",
|
||||
|
|
@ -2988,7 +2991,7 @@ version = "0.5.18"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3090,7 +3093,7 @@ checksum = "23ca8e9091b72afdc9979bddcd1988ad898fa7bc0b85c8da8c154c29d44319eb"
|
|||
dependencies = [
|
||||
"aes",
|
||||
"base64ct",
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"block-padding",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
|
|
@ -3197,7 +3200,7 @@ version = "0.38.44"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
|
|
@ -3210,7 +3213,7 @@ version = "1.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.11.0",
|
||||
|
|
@ -3978,9 +3981,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.19"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
||||
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
|
|
@ -4243,11 +4246,10 @@ checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3"
|
|||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "7.0.3"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762"
|
||||
checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d"
|
||||
dependencies = [
|
||||
"either",
|
||||
"env_home",
|
||||
"rustix 1.1.2",
|
||||
"winsafe",
|
||||
|
|
@ -4798,7 +4800,7 @@ name = "yazi-config"
|
|||
version = "25.9.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"crossterm 0.29.0",
|
||||
"dirs",
|
||||
"globset",
|
||||
|
|
@ -4930,7 +4932,7 @@ version = "25.9.15"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"core-foundation-sys",
|
||||
"dirs",
|
||||
"foldhash 0.2.0",
|
||||
|
|
@ -4966,7 +4968,7 @@ name = "yazi-parser"
|
|||
version = "25.9.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"crossterm 0.29.0",
|
||||
"hashbrown 0.16.0",
|
||||
"mlua",
|
||||
|
|
@ -5072,7 +5074,7 @@ dependencies = [
|
|||
name = "yazi-sftp"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags 2.10.0",
|
||||
"parking_lot",
|
||||
"russh",
|
||||
"serde",
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ lto = false
|
|||
ansi-to-tui = "7.0.0"
|
||||
anyhow = "1.0.100"
|
||||
base64 = "0.22.1"
|
||||
bitflags = { version = "2.9.4", features = [ "serde" ] }
|
||||
clap = { version = "4.5.49", features = [ "derive" ] }
|
||||
bitflags = { version = "2.10.0", features = [ "serde" ] }
|
||||
clap = { version = "4.5.50", features = [ "derive" ] }
|
||||
core-foundation-sys = "0.8.7"
|
||||
crossterm = { version = "0.29.0", features = [ "event-stream" ] }
|
||||
dirs = "6.0.0"
|
||||
|
|
|
|||
|
|
@ -6,10 +6,12 @@ use yazi_fs::File;
|
|||
use yazi_shared::{Id, Source, event::Cmd, url::UrlBuf};
|
||||
|
||||
pub struct Ctx<'a> {
|
||||
pub core: &'a mut Core,
|
||||
pub tab: usize,
|
||||
pub level: usize,
|
||||
pub source: Source,
|
||||
pub core: &'a mut Core,
|
||||
pub tab: usize,
|
||||
pub level: usize,
|
||||
pub source: Source,
|
||||
#[cfg(debug_assertions)]
|
||||
pub backtrace: Vec<&'static str>,
|
||||
}
|
||||
|
||||
impl Deref for Ctx<'_> {
|
||||
|
|
@ -36,19 +38,40 @@ impl<'a> Ctx<'a> {
|
|||
core.mgr.tabs.cursor
|
||||
};
|
||||
|
||||
Ok(Self { core, tab, level: 0, source: cmd.source })
|
||||
Ok(Self {
|
||||
core,
|
||||
tab,
|
||||
level: 0,
|
||||
source: cmd.source,
|
||||
#[cfg(debug_assertions)]
|
||||
backtrace: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn renew<'b>(cx: &'a mut Ctx<'b>) -> Self {
|
||||
let tab = cx.core.mgr.tabs.cursor;
|
||||
Self { core: cx.core, tab, level: cx.level, source: cx.source }
|
||||
Self {
|
||||
core: cx.core,
|
||||
tab,
|
||||
level: cx.level,
|
||||
source: cx.source,
|
||||
#[cfg(debug_assertions)]
|
||||
backtrace: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn active(core: &'a mut Core) -> Self {
|
||||
let tab = core.mgr.tabs.cursor;
|
||||
Self { core, tab, level: 0, source: Source::Unknown }
|
||||
Self {
|
||||
core,
|
||||
tab,
|
||||
level: 0,
|
||||
source: Source::Unknown,
|
||||
#[cfg(debug_assertions)]
|
||||
backtrace: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ impl Actor for Peek {
|
|||
if !cx.tab().preview.same_file(&hovered, &mime) {
|
||||
cx.tab_mut().preview.reset();
|
||||
}
|
||||
if !cx.tab().preview.same_folder(&hovered.url) {
|
||||
cx.tab_mut().preview.folder_lock = None;
|
||||
}
|
||||
|
||||
if matches!(opt.only_if, Some(u) if u != hovered.url) {
|
||||
succ!();
|
||||
|
|
@ -45,7 +48,7 @@ impl Actor for Peek {
|
|||
}
|
||||
|
||||
if hovered.is_dir() {
|
||||
cx.tab_mut().preview.go_folder(hovered, folder.map(|(_, cha)| cha), opt.force);
|
||||
cx.tab_mut().preview.go_folder(hovered, folder.map(|(_, cha)| cha), mime, opt.force);
|
||||
} else {
|
||||
cx.tab_mut().preview.go(hovered, mime, opt.force);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use yazi_fs::{File, Files, FilesOp, cha::Cha};
|
|||
use yazi_macro::render;
|
||||
use yazi_parser::mgr::PreviewLock;
|
||||
use yazi_plugin::{external::Highlighter, isolate};
|
||||
use yazi_shared::{pool::{InternStr, Symbol}, url::UrlBuf};
|
||||
use yazi_shared::{pool::Symbol, url::UrlBuf};
|
||||
use yazi_vfs::{VfsFiles, VfsFilesOp};
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -17,8 +17,9 @@ pub struct Preview {
|
|||
pub lock: Option<PreviewLock>,
|
||||
pub skip: usize,
|
||||
|
||||
previewer_ct: Option<CancellationToken>,
|
||||
folder_loader: Option<JoinHandle<()>>,
|
||||
previewer_ct: Option<CancellationToken>,
|
||||
pub folder_lock: Option<UrlBuf>,
|
||||
folder_loader: Option<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl Preview {
|
||||
|
|
@ -37,19 +38,17 @@ impl Preview {
|
|||
self.previewer_ct = isolate::peek(&previewer.run, file, mime, self.skip);
|
||||
}
|
||||
|
||||
pub fn go_folder(&mut self, file: File, dir: Option<Cha>, force: bool) {
|
||||
const MIME: &str = "folder/lock";
|
||||
|
||||
let same = self.same_file(&file, MIME);
|
||||
let (wd, cha, internal) = (file.url_owned(), file.cha, file.url.is_internal());
|
||||
|
||||
self.go(file, MIME.intern(), force);
|
||||
if same || !internal {
|
||||
return;
|
||||
pub fn go_folder(&mut self, file: File, dir: Option<Cha>, mime: Symbol<str>, force: bool) {
|
||||
if !file.url.is_internal() {
|
||||
return self.go(file, mime, force);
|
||||
} else if self.folder_lock.as_ref() == Some(&file.url) {
|
||||
return self.go(file, mime, force);
|
||||
}
|
||||
|
||||
self.lock =
|
||||
Some(PreviewLock { url: wd.clone(), cha, mime: MIME.to_owned(), ..Default::default() });
|
||||
let wd = file.url_owned();
|
||||
self.go(file, mime, force);
|
||||
|
||||
self.folder_lock = Some(wd.clone());
|
||||
self.folder_loader.take().map(|h| h.abort());
|
||||
self.folder_loader = Some(tokio::spawn(async move {
|
||||
let Some(new) = Files::assert_stale(&wd, dir.unwrap_or_default()).await else { return };
|
||||
|
|
@ -97,4 +96,6 @@ impl Preview {
|
|||
pub fn same_lock(&self, file: &File, mime: &str) -> bool {
|
||||
self.same_file(file, mime) && matches!(&self.lock, Some(l) if l.skip == self.skip)
|
||||
}
|
||||
|
||||
pub fn same_folder(&self, url: &UrlBuf) -> bool { self.folder_lock.as_ref() == Some(url) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,18 @@ macro_rules! act {
|
|||
};
|
||||
(@impl $layer:ident : $name:ident, $cx:ident, $opt:ident) => {{
|
||||
$cx.level += 1;
|
||||
#[cfg(debug_assertions)]
|
||||
$cx.backtrace.push(concat!(stringify!($layer), ":", stringify!($name)));
|
||||
|
||||
let result = match act!(@pre $layer:$name, $cx, $opt) {
|
||||
Ok(opt) => <act!($layer:$name) as yazi_actor::Actor>::act($cx, opt),
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
|
||||
$cx.level -= 1;
|
||||
#[cfg(debug_assertions)]
|
||||
$cx.backtrace.pop();
|
||||
|
||||
result
|
||||
}};
|
||||
|
||||
|
|
|
|||
|
|
@ -109,6 +109,13 @@ impl PartialOrd for Symbol<str> {
|
|||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { Some(self.cmp(other)) }
|
||||
}
|
||||
|
||||
// --- Display
|
||||
impl std::fmt::Display for Symbol<str> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
// --- Debug
|
||||
impl std::fmt::Debug for Symbol<[u8]> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue