diff --git a/CHANGELOG.md b/CHANGELOG.md index 280879fa..8fcc1df6 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 ([#1234]) ### Changed diff --git a/yazi-plugin/preset/plugins/folder.lua b/yazi-plugin/preset/plugins/folder.lua index 20ce681b..761e3d23 100644 --- a/yazi-plugin/preset/plugins/folder.lua +++ b/yazi-plugin/preset/plugins/folder.lua @@ -50,50 +50,52 @@ 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 = 0 + 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 - - 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 {}, - } + 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 + + 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..1c3f3b5c 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 + 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..47cf1e65 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, 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() + { + 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)?,