From dce7115850b6421a1408aa82ead1bf19b4f8be47 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sun, 11 Jan 2026 12:52:40 +0800 Subject: [PATCH] Fix the scrolling bug --- Cargo.lock | 20 ++--- Cargo.toml | 4 +- yazi-fs/src/mounts/partition.rs | 3 +- yazi-fs/src/mounts/partitions.rs | 5 +- yazi-plugin/preset/plugins/archive.lua | 105 ++++++++++--------------- 5 files changed, 57 insertions(+), 80 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b29b7c9..c1c20ff6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "ansi-to-tui" -version = "8.0.0" +version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdfd3cbf4843347ca072771a797484f1c3434a14d57f39d31c92dfb93a8799a8" +checksum = "e42366bb9d958f042bf58f0a85e1b2d091997c1257ca49bddd7e4827aadc65fd" dependencies = [ "nom 8.0.0", "ratatui-core", @@ -541,9 +541,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.51" +version = "1.2.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" dependencies = [ "find-msvc-tools", "jobserver", @@ -1063,9 +1063,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "deadpool" @@ -1483,9 +1483,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" +checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" [[package]] name = "finl_unicode" @@ -4478,9 +4478,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.10+spec-1.1.0" +version = "0.9.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0825052159284a1a8b4d6c0c86cbc801f2da5afd2b225fa548c72f2e74002f48" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" dependencies = [ "indexmap", "serde_core", diff --git a/Cargo.toml b/Cargo.toml index 9d46026e..21c213b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ lto = false debug = false [workspace.dependencies] -ansi-to-tui = "8.0.0" +ansi-to-tui = "8.0.1" anyhow = "1.0.100" base64 = "0.22.1" bitflags = { version = "2.10.0", features = [ "serde" ] } @@ -59,7 +59,7 @@ thiserror = "2.0.17" tokio = { version = "1.49.0", features = [ "full" ] } tokio-stream = "0.1.18" tokio-util = "0.7.18" -toml = { version = "0.9.10" } +toml = { version = "0.9.11" } tracing = { version = "0.1.44", features = [ "max_level_debug", "release_max_level_debug" ] } twox-hash = { version = "2.1.2", default-features = false, features = [ "std", "random", "xxhash3_128" ] } typed-path = "0.12.0" diff --git a/yazi-fs/src/mounts/partition.rs b/yazi-fs/src/mounts/partition.rs index 158a833d..e7721f69 100644 --- a/yazi-fs/src/mounts/partition.rs +++ b/yazi-fs/src/mounts/partition.rs @@ -15,8 +15,7 @@ pub struct Partition { impl Partition { // Match mount types that do not reliably emit change notifications, or do not - // update directory metadata on changes, and should be refreshed frequently / - // heuristically. + // update directory metadata on changes, and should be refreshed frequently. pub fn heuristic(&self) -> bool { let b: &[u8] = self.fstype.as_ref().map_or(b"", |s| s.as_encoded_bytes()); matches!(b, b"exfat" | b"fuse.rclone") diff --git a/yazi-fs/src/mounts/partitions.rs b/yazi-fs/src/mounts/partitions.rs index ac0725ab..032ef220 100644 --- a/yazi-fs/src/mounts/partitions.rs +++ b/yazi-fs/src/mounts/partitions.rs @@ -34,12 +34,11 @@ impl Partitions { pub fn heuristic(&self, _cha: Cha) -> bool { #[cfg(any(target_os = "linux", target_os = "macos"))] { - self.by_dev(_cha.dev).is_none_or(|p| p.heuristic()) + self.by_dev(_cha.dev).is_some_and(|p| p.heuristic()) } #[cfg(not(any(target_os = "linux", target_os = "macos")))] { - // For now, assume other targets update directory stat data correctly & do not - // need heuristic polling. + // For now, assume other targets update directory stat data correctly false } } diff --git a/yazi-plugin/preset/plugins/archive.lua b/yazi-plugin/preset/plugins/archive.lua index 069157a7..44d00e97 100644 --- a/yazi-plugin/preset/plugins/archive.lua +++ b/yazi-plugin/preset/plugins/archive.lua @@ -2,23 +2,24 @@ local M = {} function M:peek(job) local limit = job.area.h - local files, bound, err = self.list_archive({ "-p", tostring(job.file.path) }, job.skip, limit) + local files, err = self.list_archive({ "-p", tostring(job.file.path) }, job.skip, limit) local first = (#files == 1 and files[1]) or (#files == 0 and M.list_if_only_one(job.file.path)) if first and M.should_decompress_tar(first) then - files, bound, err = self.list_compressed_tar({ "-p", tostring(job.file.path) }, job.skip, limit) + files, err = self.list_compressed_tar({ "-p", tostring(job.file.path) }, job.skip, limit) end if err then return ya.preview_widget(job, err) - elseif job.skip > 0 and bound < job.skip + limit then - return ya.emit("peek", { math.max(0, bound - limit), only_if = job.file.url, upper_bound = true }) + elseif job.skip > 0 and #files < job.skip + limit then + return ya.emit("peek", { math.max(0, #files - limit), only_if = job.file.url, upper_bound = true }) elseif #files == 0 then files = { M.make_file { path = job.file.url.stem } } end local left, right = {}, {} - for _, f in ipairs(M.treelize(files)) do + for i = job.skip + 1, #files do + local f = files[i] local icon = File({ url = Url(f.path), cha = Cha { mode = tonumber(f.is_dir and "40700" or "100644", 8) }, @@ -105,7 +106,6 @@ end ---@param skip integer ---@param limit integer ---@return table files ----@return integer bound ---@return Error? err function M.list_archive(args, skip, limit) local child = M.spawn_7z { "l", "-ba", "-slt", "-sccUTF-8", table.unpack(args) } @@ -113,10 +113,10 @@ function M.list_archive(args, skip, limit) return {}, 0, Err("Failed to start either `7zz` or `7z`. Do you have 7-zip installed?") end - local files, bound, err = M.parse_7z_slt(child, skip, limit) + local files, err = M.parse_7z_slt(child, skip, limit) child:start_kill() - return files, bound, err + return files, err end ---List files in a compressed tarball @@ -124,7 +124,6 @@ end ---@param skip integer ---@param limit integer ---@return table files ----@return integer bound ---@return Error? err function M.list_compressed_tar(args, skip, limit) local src, dst = M.spawn_7z_piped( @@ -135,11 +134,11 @@ function M.list_compressed_tar(args, skip, limit) return {}, 0, Err("Failed to start either `7zz` or `7z`. Do you have 7-zip installed?") end - local files, bound, err = M.parse_7z_slt(dst, skip, limit) + local files, err = M.parse_7z_slt(dst, skip, limit) src:start_kill() dst:start_kill() - return files, bound, err + return files, err end function M.list_if_only_one(path) @@ -171,7 +170,7 @@ end ---List metadata of an archive ---@param args table ----@return string|nil type +---@return string? type ---@return integer code --- 0: success --- 1: failed to spawn @@ -214,14 +213,14 @@ function M.is_encrypted(s) return s:find(" Wrong password", 1, true) end function M.is_tar(path) return M.list_meta { "-p", tostring(path) } == "tar" end -function M.make_file(fields) - fields = fields or {} - fields.path = type(fields.path or "") == "string" and Path.os(fields.path or "") or fields.path - fields.size = tonumber(fields.size) or 0 - fields.packed_size = tonumber(fields.packed_size) or 0 - fields.attr = fields.attr or "" - fields.folder = fields.folder or "" - return fields +function M.make_file(t) + t = t or {} + t.path = type(t.path or "") == "string" and Path.os(t.path or "") or t.path + t.size = tonumber(t.size) or 0 + t.packed_size = tonumber(t.packed_size) or 0 + t.attr = t.attr or "" + t.folder = t.folder or "" + return t end function M.should_decompress_tar(file) @@ -234,11 +233,10 @@ end ---@param skip integer ---@param limit integer ---@return table files ----@return integer bound ---@return Error? err function M.parse_7z_slt(child, skip, limit) - local i, files, err = 0, { M.make_file() }, nil - local key, value, stderr = "", "", {} + local files, parents, err = { M.make_file() }, {}, nil + local key, value, empty, stderr = "", "", Path.os(""), {} repeat local next, event = child:read_line() if event == 1 and M.is_encrypted(next) then @@ -252,13 +250,11 @@ function M.parse_7z_slt(child, skip, limit) end if next == "\n" or next == "\r\n" then - i = i + 1 - if files[#files].path ~= Path.os("") then + if files[#files].path ~= empty then + M.treelize(files, parents) files[#files + 1] = M.make_file() end goto continue - elseif i < skip then - goto continue end key, value = next:match("^(%u[%a ]+) = (.-)[\r\n]+") @@ -275,7 +271,7 @@ function M.parse_7z_slt(child, skip, limit) end ::continue:: - until i >= skip + limit + until #files > skip + limit if files[#files].path == Path.os("") then files[#files] = nil @@ -283,51 +279,34 @@ function M.parse_7z_slt(child, skip, limit) if #stderr ~= 0 then err = Err("7-zip errored out while listing files, stderr: %s", table.concat(stderr, "\n")) end - return files, i, err + return files, err end ---Convert a flat list of files into a tree structure ---@param files table ----@return table tree -function M.treelize(files) - if #files == 0 then - return files +---@param parents Path[] +function M.treelize(files, parents) + local f = table.remove(files) + while #parents > 0 and not f.path:starts_with(parents[#parents]) do + parents[#parents] = nil end - local parent = files[1].path.parent - while parent do - table.insert(files, 1, M.make_file { path = parent, is_dir = true }) - parent = parent.parent + local buf, it = {}, f.path.parent + while it and it ~= parents[#parents] 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] end - local tree, parents, prev_parent = {}, {}, nil - for _, f in ipairs(files) do - while #parents > 0 and not f.path:starts_with(parents[#parents]) do - parents[#parents] = nil - end + f.depth = #parents + f.is_dir = f.folder == "+" or f.attr:sub(1, 1) == "D" - f.depth = #parents - f.is_dir = f.is_dir or f.folder == "+" or f.attr:sub(1, 1) == "D" - - if f.is_dir then - parents[#parents + 1] = f.path - elseif prev_parent ~= f.path.parent then - local buf, parent = {}, f.path.parent - while parent and parent ~= parents[#parents] do - buf[#buf + 1], parent = parent, parent.parent - end - for j = #buf, 1, -1 do - tree[#tree + 1] = M.make_file { path = buf[j], depth = #parents, is_dir = true } - parents[#parents + 1] = buf[j] - end - f.depth = #parents - end - - tree[#tree + 1] = f - prev_parent = f.path.parent + files[#files + 1] = f + if f.is_dir then + parents[#parents + 1] = f.path end - - return tree end return M