feat: show total size when spotting multiple selected files (#3690)

This commit is contained in:
Dan1718 2026-03-03 23:06:03 +05:30 committed by sxyazi
parent be91b4111c
commit b17d130c12
No known key found for this signature in database
6 changed files with 97 additions and 8 deletions

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::mgr::SpotOpt;
use yazi_shared::data::Data;
use yazi_shared::{data::Data, pool::InternStr};
use crate::{Actor, Ctx};
@ -15,7 +15,12 @@ impl Actor for Spot {
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
let Some(hovered) = cx.hovered().cloned() else { succ!() };
let mime = cx.mgr.mimetype.owned(&hovered.url).unwrap_or_default();
let (mime, urls) = if cx.tab().selected.len() >= 2 {
("multi/selected".intern(), Some(cx.tab().selected.values().cloned().collect()))
} else {
(cx.mgr.mimetype.owned(&hovered.url).unwrap_or_default(), None)
};
// if !self.active().spot.same_file(&hovered, &mime) {
// self.active_mut().spot.reset();
// }
@ -26,7 +31,7 @@ impl Actor for Spot {
cx.tab_mut().spot.skip = 0;
}
cx.tab_mut().spot.go(hovered, mime);
cx.tab_mut().spot.go(hovered, mime, urls);
succ!();
}
}

View file

@ -105,6 +105,7 @@ fetchers = [
{ id = "mime", url = "remote://*", run = "mime.remote", prio = "high" },
]
spotters = [
{ mime = "multi/*", run = "multi" },
{ url = "*/", run = "folder" },
# Code
{ mime = "text/*", run = "code" },

View file

@ -15,10 +15,10 @@ pub struct Spot {
}
impl Spot {
pub fn go(&mut self, file: File, mime: Symbol<str>) {
pub fn go(&mut self, file: File, mime: Symbol<str>, urls: Option<Vec<UrlBuf>>) {
if mime.is_empty() {
return; // Wait till mimetype is resolved to avoid flickering
} else if self.same_lock(&file, &mime) {
} else if urls.is_none() && self.same_lock(&file, &mime) {
return;
}
@ -27,7 +27,7 @@ impl Spot {
};
self.abort();
self.ct = Some(isolate::spot(&spotter.run, file, mime, self.skip));
self.ct = Some(isolate::spot(&spotter.run, file, mime, self.skip, urls));
}
pub fn visible(&self) -> bool { self.lock.is_some() }

View file

@ -0,0 +1,74 @@
local M = {}
function M:spot(job)
self.size = 0
self.done = 0
self.total = #job.files
self.last = 0
self:spot_render(job, false)
local sizes = {}
for _, url in ipairs(job.files) do
local cha = fs.cha(url)
if cha and not cha.is_dir then
self.size = self.size + cha.len
self.done = self.done + 1
self:spot_render(job, false)
else
local it = fs.calc_size(url)
local sub = 0
while true do
local next = it:recv()
if next then
sub = sub + next
self.size = self.size + next
self:spot_render(job, false)
else
break
end
end
self.done = self.done + 1
if cha and cha.is_dir then
sizes[url.urn] = sub
end
end
end
if next(sizes) then
local first = job.files[1]
local parent = first.parent
if parent then
local op = fs.op("size", { url = parent, sizes = sizes })
ya.emit("update_files", { op = op })
end
end
self:spot_render(job, true)
end
function M:spot_render(job, comp)
local now = ya.time()
if not comp and now < self.last + 0.1 then
return
end
local progress = string.format("%d/%d", self.done, self.total)
local rows = {
ui.Row({ "Selected" }):style(ui.Style():fg("green")),
ui.Row { " Count:", tostring(self.total) },
ui.Row { " Size:", ya.readable_size(self.size) .. (comp and "" or " (?)") },
ui.Row { " Progress:", comp and "Done" or progress },
}
ya.spot_table(
job,
ui.Table(rows)
:area(ui.Pos { "center", w = 60, h = 20 })
:row(self.last == 0 and 1 or nil)
:col(1)
:col_style(th.spot.tbl_col)
:cell_style(th.spot.tbl_cell)
:widths { ui.Constraint.Length(14), ui.Constraint.Fill(1) }
)
self.last = now
end
return M

View file

@ -2,9 +2,9 @@ use mlua::{ExternalError, ExternalResult, HookTriggers, IntoLua, ObjectLike, VmS
use tokio::{runtime::Handle, select};
use tokio_util::sync::CancellationToken;
use tracing::error;
use yazi_binding::{File, Id};
use yazi_binding::{File, Id, Url};
use yazi_dds::Sendable;
use yazi_shared::{Ids, event::Action, pool::Symbol};
use yazi_shared::{Ids, event::Action, pool::Symbol, url::UrlBuf};
use super::slim_lua;
use crate::loader::LOADER;
@ -16,6 +16,7 @@ pub fn spot(
file: yazi_fs::File,
mime: Symbol<str>,
skip: usize,
urls: Option<Vec<UrlBuf>>,
) -> CancellationToken {
let ct = CancellationToken::new();
let (ct1, ct2) = (ct.clone(), ct.clone());
@ -44,6 +45,13 @@ pub fn spot(
("mime", mime.into_lua(&lua)?),
("skip", skip.into_lua(&lua)?),
])?;
if let Some(urls) = urls {
let files = lua.create_table_with_capacity(urls.len(), 0)?;
for (i, url) in urls.into_iter().enumerate() {
files.raw_set(i + 1, Url::new(url))?;
}
job.raw_set("files", files)?;
}
if ct2.is_cancelled() { Ok(()) } else { plugin.call_async_method("spot", job).await }
};

View file

@ -44,6 +44,7 @@ impl Default for Loader {
("mime.dir".to_owned(), preset!("plugins/mime-dir").into()),
("mime.local".to_owned(), preset!("plugins/mime-local").into()),
("mime.remote".to_owned(), preset!("plugins/mime-remote").into()),
("multi".to_owned(), preset!("plugins/multi").into()),
("noop".to_owned(), preset!("plugins/noop").into()),
("null".to_owned(), preset!("plugins/null").into()),
("pdf".to_owned(), preset!("plugins/pdf").into()),