feat: new experimental ya.co() API that creates a coroutine (#3757)

This commit is contained in:
三咲雅 misaki masa 2026-03-12 16:18:30 +08:00 committed by GitHub
parent e4829372db
commit 3534ba0705
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 126 additions and 118 deletions

View file

@ -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 `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 `hey` DDS event fires when static messages are restored from persistence ([#3725])
- New `cx.which` API to access the which component state ([#3617]) - New `cx.which` API to access the which component state ([#3617])
- New experimental `ya.co()` API that creates a coroutine ([#3757])
### Changed ### 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 [#3733]: https://github.com/sxyazi/yazi/pull/3733
[#3744]: https://github.com/sxyazi/yazi/pull/3744 [#3744]: https://github.com/sxyazi/yazi/pull/3744
[#3748]: https://github.com/sxyazi/yazi/pull/3748 [#3748]: https://github.com/sxyazi/yazi/pull/3748
[#3757]: https://github.com/sxyazi/yazi/pull/3757

53
Cargo.lock generated
View file

@ -1970,9 +1970,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]] [[package]]
name = "image" name = "image"
version = "0.25.9" version = "0.25.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"byteorder-lite", "byteorder-lite",
@ -1980,15 +1980,15 @@ dependencies = [
"exr", "exr",
"gif", "gif",
"image-webp", "image-webp",
"moxcms 0.7.11", "moxcms",
"num-traits", "num-traits",
"png", "png",
"qoi", "qoi",
"ravif", "ravif",
"rgb", "rgb",
"tiff", "tiff",
"zune-core 0.5.1", "zune-core",
"zune-jpeg 0.5.12", "zune-jpeg",
] ]
[[package]] [[package]]
@ -2533,16 +2533,6 @@ dependencies = [
"syn 2.0.117", "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]] [[package]]
name = "moxcms" name = "moxcms"
version = "0.8.1" version = "0.8.1"
@ -3590,9 +3580,9 @@ dependencies = [
[[package]] [[package]]
name = "ravif" name = "ravif"
version = "0.12.0" version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285" checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45"
dependencies = [ dependencies = [
"avif-serialize", "avif-serialize",
"imgref", "imgref",
@ -4531,16 +4521,16 @@ dependencies = [
[[package]] [[package]]
name = "tiff" name = "tiff"
version = "0.10.3" version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
dependencies = [ dependencies = [
"fax", "fax",
"flate2", "flate2",
"half", "half",
"quick-error", "quick-error",
"weezl", "weezl",
"zune-jpeg 0.4.21", "zune-jpeg",
] ]
[[package]] [[package]]
@ -5739,7 +5729,7 @@ dependencies = [
"base64", "base64",
"crossterm 0.29.0", "crossterm 0.29.0",
"image", "image",
"moxcms 0.8.1", "moxcms",
"palette", "palette",
"quantette", "quantette",
"ratatui", "ratatui",
@ -6329,12 +6319,6 @@ version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
[[package]]
name = "zune-core"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
[[package]] [[package]]
name = "zune-core" name = "zune-core"
version = "0.5.1" version = "0.5.1"
@ -6352,18 +6336,9 @@ dependencies = [
[[package]] [[package]]
name = "zune-jpeg" name = "zune-jpeg"
version = "0.4.21" version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c"
dependencies = [ dependencies = [
"zune-core 0.4.12", "zune-core",
]
[[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",
] ]

View file

@ -25,7 +25,7 @@ ansi-to-tui = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
base64 = { workspace = true } base64 = { workspace = true }
crossterm = { 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" moxcms = "0.8.1"
palette = { version = "0.7.6", default-features = false } palette = { version = "0.7.6", default-features = false }
quantette = { version = "0.5.1", default-features = false } quantette = { version = "0.5.1", default-features = false }

View file

@ -50,50 +50,57 @@ function M:seek(job)
end end
function M:spot(job) function M:spot(job)
self.size, self.last = 0, 0 local i, url = 0, job.file.url
self:spot_multi(job, false) for rows in self:spot_base(job) do
i, rows[#rows + 1] = i + 1, ui.Row {}
local url = job.file.url ya.spot_table(
local it = fs.calc_size(url) job,
while it do ui.Table(ya.list_merge(rows, require("file"):spot_base(job)))
local next = it:recv() :area(ui.Pos { "center", w = 60, h = 20 })
if next then :row(i == 1 and 1 or nil)
self.size = self.size + next :col(1)
self:spot_multi(job, false) :col_style(th.spot.tbl_col)
else :cell_style(th.spot.tbl_cell)
break :widths { ui.Constraint.Length(14), ui.Constraint.Fill(1) }
end )
end
if self.size then
ya.emit("update_files", { op = fs.op("size", { url = url.parent, sizes = { [url.urn] = self.size } }) })
end 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 end
function M:spot_multi(job, comp) function M:spot_base(job)
local now = ya.time() local function yield(s)
if not comp and now < self.last + 0.1 then coroutine.yield {
return ui.Row({ "Folder" }):style(ui.Style():fg("green")),
ui.Row { " Size:", s },
}
end end
local rows = { self.size = nil
ui.Row({ "Folder" }):style(ui.Style():fg("green")), return ya.co(function()
ui.Row { " Size:", ya.readable_size(self.size) .. (comp and "" or " (?)") }, yield("0B (?)")
ui.Row {},
}
ya.spot_table( local it, size, last = fs.calc_size(job.file.url), 0, 0
job, if not it then
ui.Table(ya.list_merge(rows, require("file"):spot_base(job))) return yield("Error")
:area(ui.Pos { "center", w = 60, h = 20 }) end
:row(self.last == 0 and 1 or nil)
:col(1) while true do
:col_style(th.spot.tbl_col) local next, now = it:recv(), ya.time()
:cell_style(th.spot.tbl_cell) if not next then
:widths { ui.Constraint.Length(14), ui.Constraint.Fill(1) } break
) elseif now >= last + 0.1 then
self.last = now 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 end
return M return M

View file

@ -9,53 +9,55 @@ local selected = ya.sync(function()
end) end)
function M:spot(job) function M:spot(job)
self.sum, self.sizes, self.last, self.selected = 0, {}, 0, selected() local i = 0
self:spot_multi(job, false) for rows in self:spot_base(job, selected()) do
i = i + 1
for _, u in ipairs(self.selected) do ya.spot_table(
local it, size = fs.calc_size(u), 0 job,
while it do ui.Table(rows)
local next = it:recv() :area(ui.Pos { "center", w = 60, h = 20 })
if next then :row(i == 1 and 1 or nil)
size, self.sum = size + next, self.sum + next :col(1)
self:spot_multi(job, false) :col_style(th.spot.tbl_col)
elseif it.cha.is_dir then :cell_style(th.spot.tbl_cell)
self.sizes[u] = size :widths { ui.Constraint.Length(14), ui.Constraint.Fill(1) }
break )
else self:update_sizes()
break
end
end
end end
self:spot_multi(job, true)
end end
function M:spot_multi(job, comp) function M:spot_base(_, selected)
local now = ya.time() local function yield(s)
if not comp and now < self.last + 0.1 then coroutine.yield {
return ui.Row({ "Multi" }):style(ui.Style():fg("green")),
ui.Row { " Size:", s },
ui.Row { " Count:", string.format("%d selected", #selected) },
}
end end
local rows = { self.sizes = {}
ui.Row({ "Multi" }):style(ui.Style():fg("green")), return ya.co(function()
ui.Row { " Size:", ya.readable_size(self.sum) .. (comp and "" or " (?)") }, yield("0B (?)")
ui.Row { " Count:", string.format("%d selected", #self.selected) },
}
ya.spot_table( local sum, last = 0, 0
job, for _, url in ipairs(selected) do
ui.Table(rows) local it, size = fs.calc_size(url), 0
:area(ui.Pos { "center", w = 60, h = 20 }) while it do
:row(self.last == 0 and 1 or nil) local next, now = it:recv(), ya.time()
:col(1) if not next then
:col_style(th.spot.tbl_col) self.sizes[url] = it.cha.is_dir and size or nil
:cell_style(th.spot.tbl_cell) break
:widths { ui.Constraint.Length(14), ui.Constraint.Fill(1) } 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() yield(ya.readable_size(sum))
self.last = now end)
end end
function M:update_sizes() function M:update_sizes()

View file

@ -12,6 +12,27 @@ use super::Utils;
use crate::loader::LOADER; use crate::loader::LOADER;
impl Utils { impl Utils {
pub(super) fn co(lua: &Lua) -> mlua::Result<Function> {
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<Function> { pub(super) fn sync(lua: &Lua) -> mlua::Result<Function> {
lua.create_function(|lua, f: Function| { lua.create_function(|lua, f: Function| {
let mut rt = runtime_mut!(lua)?; let mut rt = runtime_mut!(lua)?;

View file

@ -50,6 +50,7 @@ pub fn compose(
b"spot_widgets" => Utils::spot_widgets(lua)?, b"spot_widgets" => Utils::spot_widgets(lua)?,
// Sync // Sync
b"co" => Utils::co(lua)?,
b"sync" => Utils::sync(lua)?, b"sync" => Utils::sync(lua)?,
b"async" => Utils::r#async(lua, isolate)?, b"async" => Utils::r#async(lua, isolate)?,
b"chan" => Utils::chan(lua)?, b"chan" => Utils::chan(lua)?,