From 8932ddd66d4cc8e0e7763fd66d15c5429d95459f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20misaki=20masa?= Date: Tue, 10 Mar 2026 12:39:19 +0800 Subject: [PATCH] perf: preset `multi` spotter only updates sizes for folders to cut memory usage (#3751) --- Cargo.lock | 42 ++++++++---------------- Cargo.toml | 2 +- yazi-adapter/Cargo.toml | 2 +- yazi-binding/src/calculator.rs | 17 +++++++--- yazi-boot/src/actions/debug.rs | 9 ++--- yazi-fs/src/provider/local/calculator.rs | 37 +++++++++++++-------- yazi-plugin/preset/plugins/folder.lua | 2 +- yazi-plugin/preset/plugins/multi.lua | 6 ++-- yazi-vfs/src/provider/calculator.rs | 20 +++++++---- 9 files changed, 76 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c5e7363..3157be1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1368,12 +1368,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "env_home" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" - [[package]] name = "equator" version = "0.4.2" @@ -1931,9 +1925,9 @@ dependencies = [ [[package]] name = "hybrid-array" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b229d73f5803b562cc26e4da0396c8610a4ee209f4fac8fa4f8d709166dc45" +checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1" dependencies = [ "typenum", ] @@ -2231,9 +2225,9 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libc" -version = "0.2.182" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libcrux-intrinsics" @@ -2551,9 +2545,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e5f643aebb3c117fa77e268557e3bf19e250769062820fcaf3ff33ea560adf" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" dependencies = [ "num-traits", "pxfm", @@ -5214,13 +5208,11 @@ dependencies = [ [[package]] name = "which" -version = "8.0.1" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a824aeba0fbb27264f815ada4cff43d65b1741b7a4ed7629ff9089148c4a4e0" +checksum = "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459" dependencies = [ - "env_home", - "rustix 1.1.4", - "winsafe", + "libc", ] [[package]] @@ -5598,12 +5590,6 @@ version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" -[[package]] -name = "winsafe" -version = "0.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" - [[package]] name = "wit-bindgen" version = "0.51.0" @@ -5753,7 +5739,7 @@ dependencies = [ "base64", "crossterm 0.29.0", "image", - "moxcms 0.8.0", + "moxcms 0.8.1", "palette", "quantette", "ratatui", @@ -6299,18 +6285,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.40" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.40" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 6de5ac56..f402dde6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ futures = "0.3.32" globset = "0.4.18" hashbrown = { version = "0.16.1", features = [ "serde" ] } indexmap = { version = "2.13.0", features = [ "serde" ] } -libc = "0.2.182" +libc = "0.2.183" lru = "0.16.3" mlua = { version = "0.11.6", features = [ "anyhow", "async", "error-send", "lua55", "macros", "serde" ] } objc2 = "0.6.4" diff --git a/yazi-adapter/Cargo.toml b/yazi-adapter/Cargo.toml index 0072760a..07a94dc5 100644 --- a/yazi-adapter/Cargo.toml +++ b/yazi-adapter/Cargo.toml @@ -26,7 +26,7 @@ anyhow = { workspace = true } base64 = { workspace = true } crossterm = { workspace = true } image = { version = "0.25.9", default-features = false, features = [ "avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp" ] } -moxcms = "0.8.0" +moxcms = "0.8.1" palette = { version = "0.7.6", default-features = false } quantette = { version = "0.5.1", default-features = false } ratatui = { workspace = true } diff --git a/yazi-binding/src/calculator.rs b/yazi-binding/src/calculator.rs index dbb19884..11f9894b 100644 --- a/yazi-binding/src/calculator.rs +++ b/yazi-binding/src/calculator.rs @@ -1,6 +1,6 @@ -use mlua::{IntoLuaMulti, UserData, UserDataMethods, Value}; +use mlua::{IntoLuaMulti, UserData, UserDataFields, UserDataMethods, Value}; -use crate::Error; +use crate::{Cha, Error}; pub enum SizeCalculator { Local(yazi_fs::provider::local::SizeCalculator), @@ -8,11 +8,20 @@ pub enum SizeCalculator { } impl UserData for SizeCalculator { + fn add_fields>(fields: &mut F) { + fields.add_field_method_get("cha", |_, me| { + Ok(Cha(match me { + Self::Local(c) => c.cha(), + Self::Remote(c) => c.cha(), + })) + }); + } + fn add_methods>(methods: &mut M) { methods.add_async_method_mut("recv", |lua, mut me, ()| async move { let next = match &mut *me { - Self::Local(it) => it.next().await, - Self::Remote(it) => it.next().await, + Self::Local(c) => c.next().await, + Self::Remote(c) => c.next().await, }; match next { diff --git a/yazi-boot/src/actions/debug.rs b/yazi-boot/src/actions/debug.rs index e948364b..5924d710 100644 --- a/yazi-boot/src/actions/debug.rs +++ b/yazi-boot/src/actions/debug.rs @@ -12,10 +12,11 @@ impl Actions { pub(super) fn debug() -> Result { let mut s = String::new(); writeln!(s, "\nYazi")?; - writeln!(s, " Version: {}", Self::version())?; - writeln!(s, " Debug : {}", cfg!(debug_assertions))?; - writeln!(s, " Triple : {}", Self::triple())?; - writeln!(s, " Rustc : {}", Self::rustc())?; + writeln!(s, " Version : {}", Self::version())?; + writeln!(s, " Debug : {}", cfg!(debug_assertions))?; + writeln!(s, " Triple : {}", Self::triple())?; + writeln!(s, " Rustc : {}", Self::rustc())?; + writeln!(s, " Backtrace: {:?}", env::var_os("RUST_BACKTRACE"))?; writeln!(s, "\nYa")?; writeln!(s, " Version: {}", Self::process_output("ya", "--version"))?; diff --git a/yazi-fs/src/provider/local/calculator.rs b/yazi-fs/src/provider/local/calculator.rs index 328c61a8..5ad9afbb 100644 --- a/yazi-fs/src/provider/local/calculator.rs +++ b/yazi-fs/src/provider/local/calculator.rs @@ -3,29 +3,37 @@ use std::{collections::VecDeque, future::poll_fn, io, mem, path::{Path, PathBuf} use either::Either; use tokio::task::JoinHandle; +use crate::cha::Cha; + type Task = Either; pub enum SizeCalculator { - Idle((VecDeque, Option)), - Pending(JoinHandle<(VecDeque, Option)>), + Idle((VecDeque, Option), Cha), + Pending(JoinHandle<(VecDeque, Option)>, Cha), } impl SizeCalculator { pub async fn new(path: &Path) -> io::Result { let p = path.to_owned(); tokio::task::spawn_blocking(move || { - let meta = std::fs::symlink_metadata(&p)?; - if !meta.is_dir() { - return Ok(Self::Idle((VecDeque::new(), Some(meta.len())))); + let cha = Cha::new(p.file_name().unwrap_or_default(), std::fs::symlink_metadata(&p)?); + if !cha.is_dir() { + return Ok(Self::Idle((VecDeque::new(), Some(cha.len)), cha)); } let mut buf = VecDeque::from([Either::Right(std::fs::read_dir(&p)?)]); let size = Self::next_chunk(&mut buf); - Ok(Self::Idle((buf, size))) + Ok(Self::Idle((buf, size), cha)) }) .await? } + pub fn cha(&self) -> Cha { + match *self { + Self::Idle(_, cha) | Self::Pending(_, cha) => cha, + } + } + pub async fn total(path: &Path) -> io::Result { let mut it = Self::new(path).await?; let mut total = 0; @@ -39,7 +47,7 @@ impl SizeCalculator { poll_fn(|cx| { loop { match self { - Self::Idle((buf, size)) => { + Self::Idle((buf, size), cha) => { if let Some(s) = size.take() { return Poll::Ready(Ok(Some(s))); } else if buf.is_empty() { @@ -47,13 +55,16 @@ impl SizeCalculator { } let mut buf = mem::take(buf); - *self = Self::Pending(tokio::task::spawn_blocking(move || { - let size = Self::next_chunk(&mut buf); - (buf, size) - })); + *self = Self::Pending( + tokio::task::spawn_blocking(move || { + let size = Self::next_chunk(&mut buf); + (buf, size) + }), + *cha, + ); } - Self::Pending(handle) => { - *self = Self::Idle(ready!(Pin::new(handle).poll(cx))?); + Self::Pending(handle, cha) => { + *self = Self::Idle(ready!(Pin::new(handle).poll(cx))?, *cha); } } } diff --git a/yazi-plugin/preset/plugins/folder.lua b/yazi-plugin/preset/plugins/folder.lua index e6c7e88d..20ce681b 100644 --- a/yazi-plugin/preset/plugins/folder.lua +++ b/yazi-plugin/preset/plugins/folder.lua @@ -55,7 +55,7 @@ function M:spot(job) local url = job.file.url local it = fs.calc_size(url) - while true do + while it do local next = it:recv() if next then self.size = self.size + next diff --git a/yazi-plugin/preset/plugins/multi.lua b/yazi-plugin/preset/plugins/multi.lua index d6b22d03..7dee4696 100644 --- a/yazi-plugin/preset/plugins/multi.lua +++ b/yazi-plugin/preset/plugins/multi.lua @@ -14,13 +14,15 @@ function M:spot(job) for _, u in ipairs(self.selected) do local it, size = fs.calc_size(u), 0 - while true do + while it do local next = it:recv() if next then size, self.sum = size + next, self.sum + next self:spot_multi(job, false) + elseif it.cha.is_dir then + self.sizes[u] = size + break else - self.sizes[u], size = size, 0 break end end diff --git a/yazi-vfs/src/provider/calculator.rs b/yazi-vfs/src/provider/calculator.rs index b055ad96..e3aba5d0 100644 --- a/yazi-vfs/src/provider/calculator.rs +++ b/yazi-vfs/src/provider/calculator.rs @@ -1,14 +1,14 @@ use std::{collections::VecDeque, io, time::{Duration, Instant}}; use either::Either; -use yazi_fs::provider::{DirReader, FileHolder}; +use yazi_fs::{cha::Cha, provider::{DirReader, FileHolder}}; use yazi_shared::url::{AsUrl, UrlBuf}; use super::ReadDir; pub enum SizeCalculator { - File(Option), - Dir(VecDeque>), + File(Option, Cha), + Dir(VecDeque>, Cha), } impl SizeCalculator { @@ -19,12 +19,18 @@ impl SizeCalculator { let url = url.as_url(); let cha = super::symlink_metadata(url).await?; Ok(if cha.is_dir() { - Self::Dir(VecDeque::from([Either::Left(url.to_owned())])) + Self::Dir(VecDeque::from([Either::Left(url.to_owned())]), cha) } else { - Self::File(Some(cha.len)) + Self::File(Some(cha.len), cha) }) } + pub fn cha(&self) -> Cha { + match *self { + Self::File(_, cha) | Self::Dir(_, cha) => cha, + } + } + pub async fn total(url: U) -> io::Result where U: AsUrl, @@ -39,8 +45,8 @@ impl SizeCalculator { pub async fn next(&mut self) -> io::Result> { Ok(match self { - Self::File(size) => size.take(), - Self::Dir(buf) => Self::next_chunk(buf).await, + Self::File(size, _) => size.take(), + Self::Dir(buf, _) => Self::next_chunk(buf).await, }) }