From 2c40342e0da14c01df1e524a9dce211ff5be83c1 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Tue, 10 Mar 2026 12:32:17 +0800 Subject: [PATCH] perf: preset `multi` spotter only updates sizes for folders to cut memory usage --- 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 ++++++++----- 6 files changed, 60 insertions(+), 31 deletions(-) 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, }) }