diff --git a/CHANGELOG.md b/CHANGELOG.md index 280879fa..ccecb23f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): - New `ind-which-activate` DDS event to change the which component behavior ([#3608]) - New `hey` DDS event fires when static messages are restored from persistence ([#3725]) - New `cx.which` API to access the which component state ([#3617]) +- New experimental `ya.co()` API that creates a coroutine ([#3757]) ### Changed @@ -1680,3 +1681,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): [#3733]: https://github.com/sxyazi/yazi/pull/3733 [#3744]: https://github.com/sxyazi/yazi/pull/3744 [#3748]: https://github.com/sxyazi/yazi/pull/3748 +[#3757]: https://github.com/sxyazi/yazi/pull/3757 diff --git a/Cargo.lock b/Cargo.lock index 3157be1d..332e723f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1970,9 +1970,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "image" -version = "0.25.9" +version = "0.25.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" dependencies = [ "bytemuck", "byteorder-lite", @@ -1980,15 +1980,15 @@ dependencies = [ "exr", "gif", "image-webp", - "moxcms 0.7.11", + "moxcms", "num-traits", "png", "qoi", "ravif", "rgb", "tiff", - "zune-core 0.5.1", - "zune-jpeg 0.5.12", + "zune-core", + "zune-jpeg", ] [[package]] @@ -2533,16 +2533,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "moxcms" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" -dependencies = [ - "num-traits", - "pxfm", -] - [[package]] name = "moxcms" version = "0.8.1" @@ -3590,9 +3580,9 @@ dependencies = [ [[package]] name = "ravif" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285" +checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45" dependencies = [ "avif-serialize", "imgref", @@ -4531,16 +4521,16 @@ dependencies = [ [[package]] name = "tiff" -version = "0.10.3" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" dependencies = [ "fax", "flate2", "half", "quick-error", "weezl", - "zune-jpeg 0.4.21", + "zune-jpeg", ] [[package]] @@ -5739,7 +5729,7 @@ dependencies = [ "base64", "crossterm 0.29.0", "image", - "moxcms 0.8.1", + "moxcms", "palette", "quantette", "ratatui", @@ -6329,12 +6319,6 @@ version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" -[[package]] -name = "zune-core" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" - [[package]] name = "zune-core" version = "0.5.1" @@ -6352,18 +6336,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.21" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c" dependencies = [ - "zune-core 0.4.12", -] - -[[package]] -name = "zune-jpeg" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410e9ecef634c709e3831c2cfdb8d9c32164fae1c67496d5b68fff728eec37fe" -dependencies = [ - "zune-core 0.5.1", + "zune-core", ] diff --git a/yazi-adapter/Cargo.toml b/yazi-adapter/Cargo.toml index 07a94dc5..400c75e5 100644 --- a/yazi-adapter/Cargo.toml +++ b/yazi-adapter/Cargo.toml @@ -25,7 +25,7 @@ ansi-to-tui = { workspace = true } anyhow = { workspace = true } base64 = { workspace = true } crossterm = { workspace = true } -image = { version = "0.25.9", default-features = false, features = [ "avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp" ] } +image = { version = "0.25.10", default-features = false, features = [ "avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp" ] } moxcms = "0.8.1" palette = { version = "0.7.6", default-features = false } quantette = { version = "0.5.1", default-features = false } diff --git a/yazi-plugin/preset/plugins/folder.lua b/yazi-plugin/preset/plugins/folder.lua index 20ce681b..43d75ab2 100644 --- a/yazi-plugin/preset/plugins/folder.lua +++ b/yazi-plugin/preset/plugins/folder.lua @@ -50,50 +50,57 @@ function M:seek(job) end function M:spot(job) - self.size, self.last = 0, 0 - self:spot_multi(job, false) - - local url = job.file.url - local it = fs.calc_size(url) - while it do - local next = it:recv() - if next then - self.size = self.size + next - self:spot_multi(job, false) - else - break - end + local i, url = 0, job.file.url + for rows in self:spot_base(job) do + i, rows[#rows + 1] = i + 1, ui.Row {} + ya.spot_table( + job, + ui.Table(ya.list_merge(rows, require("file"):spot_base(job))) + :area(ui.Pos { "center", w = 60, h = 20 }) + :row(i == 1 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) } + ) + end + if self.size then + ya.emit("update_files", { op = fs.op("size", { url = url.parent, sizes = { [url.urn] = self.size } }) }) end - - local op = fs.op("size", { url = url.parent, sizes = { [url.urn] = self.size } }) - ya.emit("update_files", { op = op }) - - 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 +function M:spot_base(job) + local function yield(s) + coroutine.yield { + ui.Row({ "Folder" }):style(ui.Style():fg("green")), + ui.Row { " Size:", s }, + } end - local rows = { - ui.Row({ "Folder" }):style(ui.Style():fg("green")), - ui.Row { " Size:", ya.readable_size(self.size) .. (comp and "" or " (?)") }, - ui.Row {}, - } + self.size = nil + return ya.co(function() + yield("0B (?)") - ya.spot_table( - job, - ui.Table(ya.list_merge(rows, require("file"):spot_base(job))) - :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 + local it, size, last = fs.calc_size(job.file.url), 0, 0 + if not it then + return yield("Error") + end + + while true do + local next, now = it:recv(), ya.time() + if not next then + break + elseif now >= last + 0.1 then + last, size = now, size + next + yield(ya.readable_size(size) .. " (?)") + else + size = size + next + end + end + + self.size = size + yield(ya.readable_size(size)) + end) end return M diff --git a/yazi-plugin/preset/plugins/multi.lua b/yazi-plugin/preset/plugins/multi.lua index 600092c2..9951140f 100644 --- a/yazi-plugin/preset/plugins/multi.lua +++ b/yazi-plugin/preset/plugins/multi.lua @@ -9,53 +9,55 @@ local selected = ya.sync(function() 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 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 - break - end - end + local i = 0 + for rows in self:spot_base(job, selected()) do + i = i + 1 + ya.spot_table( + job, + ui.Table(rows) + :area(ui.Pos { "center", w = 60, h = 20 }) + :row(i == 1 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() 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 +function M:spot_base(_, selected) + local function yield(s) + coroutine.yield { + ui.Row({ "Multi" }):style(ui.Style():fg("green")), + ui.Row { " Size:", s }, + ui.Row { " Count:", string.format("%d selected", #selected) }, + } end - local rows = { - ui.Row({ "Multi" }):style(ui.Style():fg("green")), - ui.Row { " Size:", ya.readable_size(self.sum) .. (comp and "" or " (?)") }, - ui.Row { " Count:", string.format("%d selected", #self.selected) }, - } + self.sizes = {} + return ya.co(function() + yield("0B (?)") - 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) } - ) + local sum, last = 0, 0 + for _, url in ipairs(selected) do + local it, size = fs.calc_size(url), 0 + while it do + local next, now = it:recv(), ya.time() + if not next then + self.sizes[url] = it.cha.is_dir and size or nil + break + elseif now >= last + 0.1 then + last, size, sum = now, size + next, sum + next + yield(ya.readable_size(sum) .. " (?)") + else + size, sum = size + next, sum + next + end + end + end - self:update_sizes() - self.last = now + yield(ya.readable_size(sum)) + end) end function M:update_sizes() diff --git a/yazi-plugin/src/utils/sync.rs b/yazi-plugin/src/utils/sync.rs index b624f542..d6b7ed54 100644 --- a/yazi-plugin/src/utils/sync.rs +++ b/yazi-plugin/src/utils/sync.rs @@ -12,6 +12,27 @@ use super::Utils; use crate::loader::LOADER; impl Utils { + pub(super) fn co(lua: &Lua) -> mlua::Result { + lua.create_function(|lua, f: Function| { + let thread = lua.create_thread(f)?; + lua.create_async_function(move |lua, mut args: MultiValue| { + let thread = thread.clone(); + async move { + loop { + let values: MultiValue = thread.resume(args)?; + if let Some(Value::LightUserData(ud)) = values.get(0) + && *ud == Lua::poll_pending() + { + args = lua.yield_with(values).await?; + } else { + return Ok(values); + } + } + } + }) + }) + } + pub(super) fn sync(lua: &Lua) -> mlua::Result { lua.create_function(|lua, f: Function| { let mut rt = runtime_mut!(lua)?; diff --git a/yazi-plugin/src/utils/utils.rs b/yazi-plugin/src/utils/utils.rs index 32936581..3d5db587 100644 --- a/yazi-plugin/src/utils/utils.rs +++ b/yazi-plugin/src/utils/utils.rs @@ -50,6 +50,7 @@ pub fn compose( b"spot_widgets" => Utils::spot_widgets(lua)?, // Sync + b"co" => Utils::co(lua)?, b"sync" => Utils::sync(lua)?, b"async" => Utils::r#async(lua, isolate)?, b"chan" => Utils::chan(lua)?,