diff --git a/CHANGELOG.md b/CHANGELOG.md index ecc6e586..9e9f6a5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): - Custom tab name ([#3666]) - New `--in` for `search` action to set search directory ([#3696]) +- Multi-file spotter ([#3733]) - New `hovered` condition specifying different icons for hovered files ([#3728]) - Allow using `ps.sub()` in `init.lua` directly without a plugin ([#3638]) - New `sort_fallback` option to control fallback sorting behavior ([#3077]) @@ -1672,3 +1673,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): [#3708]: https://github.com/sxyazi/yazi/pull/3708 [#3725]: https://github.com/sxyazi/yazi/pull/3725 [#3728]: https://github.com/sxyazi/yazi/pull/3728 +[#3733]: https://github.com/sxyazi/yazi/pull/3733 diff --git a/yazi-actor/src/mgr/spot.rs b/yazi-actor/src/mgr/spot.rs index eafe6e69..dc35f2dd 100644 --- a/yazi-actor/src/mgr/spot.rs +++ b/yazi-actor/src/mgr/spot.rs @@ -1,7 +1,7 @@ use anyhow::Result; -use yazi_macro::succ; +use yazi_macro::{act, succ}; use yazi_parser::mgr::SpotOpt; -use yazi_shared::data::Data; +use yazi_shared::{data::Data, pool::InternStr}; use crate::{Actor, Ctx}; @@ -13,9 +13,15 @@ impl Actor for Spot { const NAME: &str = "spot"; fn act(cx: &mut Ctx, opt: Self::Options) -> Result { + act!(mgr:escape_visual, cx)?; let Some(hovered) = cx.hovered().cloned() else { succ!() }; - let mime = cx.mgr.mimetype.owned(&hovered.url).unwrap_or_default(); + let mime = if cx.tab().selected.is_empty() { + cx.mgr.mimetype.owned(&hovered.url).unwrap_or_default() + } else { + "multi/unknown".intern() + }; + // if !self.active().spot.same_file(&hovered, &mime) { // self.active_mut().spot.reset(); // } diff --git a/yazi-config/preset/yazi-default.toml b/yazi-config/preset/yazi-default.toml index 319338cf..0e68e6c2 100644 --- a/yazi-config/preset/yazi-default.toml +++ b/yazi-config/preset/yazi-default.toml @@ -105,6 +105,9 @@ fetchers = [ { id = "mime", url = "remote://*", run = "mime.remote", prio = "high" }, ] spotters = [ + # Multi-file + { mime = "multi/*", run = "multi" }, + # Folder { url = "*/", run = "folder" }, # Code { mime = "text/*", run = "code" }, diff --git a/yazi-plugin/preset/plugins/multi.lua b/yazi-plugin/preset/plugins/multi.lua new file mode 100644 index 00000000..a8a80d3c --- /dev/null +++ b/yazi-plugin/preset/plugins/multi.lua @@ -0,0 +1,73 @@ +--- @sync peek + +local M = {} + +local selected = ya.sync(function() + local urls = {} + for _, u in pairs(cx.active.selected) do + urls[#urls + 1] = u + end + return urls +end) + +function M:spot(job) + self.sum, self.sizes, self.last, self.selected = 0, {}, 0, selected() + self:spot_multi(job, false) + + for _, u in ipairs(self.selected) do + local it, size = fs.calc_size(u), 0 + while true do + local next = it:recv() + if next then + size, self.sum = size + next, self.sum + next + self:spot_multi(job, false) + else + self.sizes[u], size = size, 0 + break + end + end + end + + self:spot_multi(job, true) +end + +function M:spot_multi(job, comp) + local now = ya.time() + if not comp and now < self.last + 0.1 then + return + end + + local rows = { + ui.Row({ "Multi" }):style(ui.Style():fg("green")), + ui.Row { " Count:", string.format("%d selected", #self.selected) }, + ui.Row { " Size:", ya.readable_size(self.sum) .. (comp and "" or " (?)") }, + } + + 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:update_sizes() + self.last = now +end + +function M:update_sizes() + local parents = {} + for url, size in pairs(self.sizes) do + local p = url.parent + parents[p] = parents[p] or {} + parents[p][url.urn] = size + end + for parent, sizes in pairs(parents) do + ya.emit("update_files", { op = fs.op("size", { url = parent, sizes = sizes }) }) + end +end + +return M diff --git a/yazi-plugin/src/loader/loader.rs b/yazi-plugin/src/loader/loader.rs index 481b9743..e6748c2c 100644 --- a/yazi-plugin/src/loader/loader.rs +++ b/yazi-plugin/src/loader/loader.rs @@ -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()),