refactor(image): use multi spawn

This commit is contained in:
Folke Lemaitre 2025-02-17 23:13:08 +01:00
parent a76fe13148
commit c3419cbf8b
No known key found for this signature in database
GPG key ID: 41F8B1FBACAE2040
3 changed files with 50 additions and 74 deletions

View file

@ -1,3 +1,5 @@
local Spawn = require("snacks.util.spawn")
---@class snacks.image.convert
local M = {}
-- vim.list_extend(args, {
@ -58,39 +60,21 @@ function M.tmpfile(src, ext)
end
---@param file string
---@param opts snacks.image.generate
---@return (fun(): boolean) is_ready
function M.generate(file, opts)
local on_done = function(code)
if opts.on_done then
opts.on_done(code)
end
end
---@param ... snacks.spawn.Config
function M.generate(file, ...)
local opts = Snacks.config.merge(...)
opts = Snacks.config.merge(opts, { debug = Snacks.image.config.debug.convert })
if vim.fn.filereadable(file) == 1 then
on_done(0)
return function()
return true
end
end
if Snacks.image.config.debug.convert then
Snacks.debug.cmd(opts)
end
local handle ---@type uv.uv_process_t
handle = uv.spawn(opts.cmd, opts, function(code)
handle:close()
on_done(code)
end)
return function()
return (not handle or handle:is_closing() or false) and vim.fn.filereadable(file) == 1
return
end
return Spawn.new(opts)
end
---@param src string
---@param dest string
---@param opts? {args?: (string|number)[], on_done?: snacks.image.generate.on_done}
---@return (fun(): boolean) is_ready
function M.magick(src, dest, opts)
opts = opts or {}
---@param ...? snacks.spawn.Config
function M.magick(src, dest, ...)
local opts = Snacks.config.merge(...)
local args = opts.args or { src .. "[0]" } ---@type string[]
for a, arg in ipairs(args) do
if arg == "src" then
@ -100,34 +84,29 @@ function M.magick(src, dest, opts)
args[#args + 1] = dest
have_magick = have_magick == nil and vim.fn.executable("magick") == 1 or have_magick
local cmd = have_magick and "magick" or "convert"
local is_win = jit.os:find("Windows")
if is_win and cmd == "convert" then
return function()
return false
end
if Snacks.util.is_win and cmd == "convert" then
return
end
return M.generate(dest, {
cmd = have_magick and "magick" or "convert",
return M.generate(dest, opts, {
cmd = cmd,
args = args,
on_done = opts.on_done,
})
end
---@param src string
---@param dest string
---@param opts? {on_done?: snacks.image.generate.on_done}
---@return (fun(): boolean) is_ready
function M.tex2pdf(src, dest, opts)
return M.generate(dest, {
---@param ... snacks.spawn.Config
function M.tex2pdf(src, dest, ...)
local opts = Snacks.config.merge(...)
return M.generate(dest, opts, {
cmd = "pdflatex",
args = { "-output-directory=" .. vim.fn.fnamemodify(dest, ":h"), src },
on_done = opts and opts.on_done,
})
end
---@param src string
---@param opts? {on_done?: snacks.image.generate.on_done}
---@return string png, (fun(): boolean) is_ready
---@param opts? snacks.spawn.Multi
---@return string png, snacks.spawn.Proc?
function M.convert(src, opts)
local png = M.tmpfile(src, "png")
src = M.norm(src)
@ -136,28 +115,16 @@ function M.convert(src, opts)
src = vim.fs.normalize(src)
png = M.tmpfile(src, "png")
if ext == "png" then
if opts and opts.on_done then
opts.on_done(0)
end
return src, function()
return true
end
return src
elseif ext == "tex" then
local pdf = src:gsub("%.tex$", ".pdf")
local is_ready = function()
return false
end
M.tex2pdf(src, pdf, {
on_done = function(code)
if code == 0 then
opts.args = { "-density", 300, pdf, "-trim" }
is_ready = M.magick(pdf, png, opts)
end
end,
local procs = {} ---@type snacks.spawn.Proc[]
procs[#procs + 1] = M.tex2pdf(src, pdf, vim.deepcopy(opts), { run = false })
procs[#procs + 1] = M.magick(pdf, png, vim.deepcopy(opts), {
run = false,
args = { "-density", 300, "src", "-trim" },
})
return png, function()
return is_ready()
end
return png, Spawn.multi(procs, opts)
end
end
opts.args = {
@ -179,7 +146,7 @@ function M.convert(src, opts)
"-trim",
}
end
return png, M.magick(src, png, opts)
return png, Spawn.multi({ M.magick(src, png, opts) }, opts)
end
return M

View file

@ -5,8 +5,7 @@
---@field sent? boolean image data is sent
---@field placements table<number, snacks.image.Placement> image placements
---@field augroup number
---@field _ready fun(): boolean
---@field closed? boolean
---@field _proc? snacks.spawn.Proc
local M = {}
M.__index = M
@ -25,7 +24,6 @@ function M.new(src)
self.src = src
self.file = self:convert()
if images[self.file] then
self.closed = true
return images[self.file]
end
images[self.file] = self
@ -41,11 +39,18 @@ function M.new(src)
self.placements = {}
self.augroup = vim.api.nvim_create_augroup("snacks.image." .. self.id, { clear = true })
if self._proc then
self._proc:run()
end
if self:ready() then
self:on_ready()
end
return self
end
function M:on_ready()
if not self.sent and not self.closed then
if not self.sent then
self:send()
end
end
@ -57,22 +62,26 @@ function M:on_send()
end
function M:ready()
return self._ready() and self.file and vim.fn.filereadable(self.file) == 1
if self._proc and self._proc:running() then
return false
end
return self.file and vim.fn.filereadable(self.file) == 1
end
function M:convert()
local png, ready = Snacks.image.convert.convert(self.src, {
on_done = function(code)
if code == 0 then
local png, proc = Snacks.image.convert.convert(self.src, {
run = false,
on_exit = function(procs, err)
if err then
Snacks.notify.error("Failed to convert image to " .. self.file)
else
vim.schedule(function()
self:on_ready()
end)
else
Snacks.notify.error("Failed to convert image to " .. self.file)
end
end,
})
self._ready = ready
self._proc = proc
return png
end

View file

@ -40,7 +40,7 @@ function M.proc(opts, ctx)
end
if ctx.picker.opts.debug.proc then
Snacks.debug.cmd(opts)
Snacks.debug.cmd(Snacks.config.merge(opts, { group = true }))
end
local sep = opts.sep or "\n"