From a8a4b684a15276dde827a02bcace5b99de4a246a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20misaki=20masa?= Date: Wed, 11 Feb 2026 11:07:23 +0800 Subject: [PATCH] feat: deduplicate empty directories in preset archive previewer (#3676) --- yazi-plugin/preset/plugins/archive.lua | 55 +++++++++++++++++++------- yazi-plugin/src/utils/log.rs | 44 +++++++++++++++++---- yazi-shared/src/loc/buf.rs | 8 ---- 3 files changed, 77 insertions(+), 30 deletions(-) diff --git a/yazi-plugin/preset/plugins/archive.lua b/yazi-plugin/preset/plugins/archive.lua index 0ba738ad..cca59da6 100644 --- a/yazi-plugin/preset/plugins/archive.lua +++ b/yazi-plugin/preset/plugins/archive.lua @@ -237,7 +237,7 @@ end ---@return table files ---@return Error? err function M.parse_7z_slt(child, skip, limit) - local files, parents, err = { M.make_file() }, {}, nil + local files, tops, parents, err = { M.make_file() }, {}, {}, nil local key, value, empty, stderr = "", "", Path.os(""), {} repeat local next, event = child:read_line() @@ -253,7 +253,8 @@ function M.parse_7z_slt(child, skip, limit) if next == "\n" or next == "\r\n" then if files[#files].path ~= empty then - M.treelize(files, parents) + M.treelize(files, tops, parents) + M.pop_dup_dir(files, parents, false) files[#files + 1] = M.make_file() end goto continue @@ -273,12 +274,17 @@ function M.parse_7z_slt(child, skip, limit) end ::continue:: - until #files > skip + limit + until #files - 1 > skip + limit if files[#files].path == empty then files[#files] = nil else - M.treelize(files, parents) + M.treelize(files, tops, parents) + end + + M.pop_dup_dir(files, parents, #files <= skip + limit) + if #files > skip + limit then + files[#files] = nil end if #stderr ~= 0 then @@ -289,29 +295,50 @@ end ---Convert a flat list of files into a tree structure ---@param files table ----@param parents Path[] -function M.treelize(files, parents) +---@param tops Path[] +---@param parents table +function M.treelize(files, tops, parents) local f = table.remove(files) - while #parents > 0 and not f.path:starts_with(parents[#parents]) do - parents[#parents] = nil + while #tops > 0 and not f.path:starts_with(tops[#tops]) do + tops[#tops] = nil end local buf, it = {}, f.path.parent - while it and it ~= parents[#parents] do + while it and it ~= tops[#tops] do buf[#buf + 1], it = it, it.parent end for i = #buf, 1, -1 do - files[#files + 1] = M.make_file { path = buf[i], depth = #parents, is_dir = true } - parents[#parents + 1] = buf[i] + files[#files + 1] = M.make_file { path = buf[i], depth = #tops, is_dir = true } + tops[#tops + 1] = buf[i] + M.pop_dup_dir(files, parents, false) end - f.depth = #parents + f.depth = #tops f.is_dir = f.folder == "+" or f.attr:sub(1, 1) == "D" if not f.is_dir then files[#files + 1] = f - elseif f.path ~= parents[#parents] then - files[#files + 1], parents[#parents + 1] = f, f.path + elseif f.path ~= tops[#tops] then + files[#files + 1], tops[#tops + 1] = f, f.path + end +end + +---@param files table +---@param parents table +---@param eof boolean +function M.pop_dup_dir(files, parents, eof) + local n, i = #files, eof and #files or #files - 1 + if not files[i] or not files[i].is_dir then + return + end + + local p = tostring(files[i].path) + if not parents[p] then + parents[p] = true + elseif eof then + files[n] = nil + elseif not files[n].path:starts_with(files[i].path) then + files[i], files[n] = files[n], nil end end diff --git a/yazi-plugin/src/utils/log.rs b/yazi-plugin/src/utils/log.rs index 990b5ced..f46fdc72 100644 --- a/yazi-plugin/src/utils/log.rs +++ b/yazi-plugin/src/utils/log.rs @@ -1,20 +1,48 @@ -use mlua::{Function, Lua, MultiValue}; +use std::{any::TypeId, fmt::Write}; + +use mlua::{Function, Lua, MultiValue, Value}; use tracing::{debug, error}; use super::Utils; impl Utils { pub(super) fn dbg(lua: &Lua) -> mlua::Result { - lua.create_function(|_, values: MultiValue| { - let s = values.into_iter().map(|v| format!("{v:#?}")).collect::>().join(" "); - Ok(debug!("{s}")) - }) + lua.create_function(|_, values: MultiValue| Ok(debug!("{}", Self::format_all(values)?))) } pub(super) fn err(lua: &Lua) -> mlua::Result { - lua.create_function(|_, values: MultiValue| { - let s = values.into_iter().map(|v| format!("{v:#?}")).collect::>().join(" "); - Ok(error!("{s}")) + lua.create_function(|_, values: MultiValue| Ok(error!("{}", Self::format_all(values)?))) + } + + fn format_all(values: MultiValue) -> anyhow::Result { + let mut s = String::new(); + for value in values { + if !s.is_empty() { + s.push(' '); + } + Utils::format_one(&mut s, value)?; + } + Ok(s) + } + + fn format_one(buf: &mut String, value: Value) -> anyhow::Result<()> { + let Value::UserData(ud) = &value else { + return Ok(write!(buf, "{value:#?}")?); + }; + + let id = ud.type_id(); + let ptr = ud.to_pointer(); + Ok(match id { + Some(t) if t == TypeId::of::() => { + write!(buf, "Url({ptr:?}): {:?}", **ud.borrow::()?)? + } + Some(t) if t == TypeId::of::() => { + write!(buf, "Path({ptr:?}): {:?}", **ud.borrow::()?)? + } + Some(t) if t == TypeId::of::() => { + write!(buf, "Id({ptr:?}): {}", **ud.borrow::()?)? + } + _ => write!(buf, "{value:#?}")?, }) } } diff --git a/yazi-shared/src/loc/buf.rs b/yazi-shared/src/loc/buf.rs index 59db3862..52d1cfbf 100644 --- a/yazi-shared/src/loc/buf.rs +++ b/yazi-shared/src/loc/buf.rs @@ -164,14 +164,6 @@ where } } - #[inline] - pub fn to_inner(&self) -> P - where - P: Clone, - { - self.inner.clone() - } - #[inline] pub fn into_inner(self) -> P { self.inner }