mirror of
https://github.com/taigrr/glaze.nvim.git
synced 2026-04-02 03:09:10 -07:00
Phase 1 - Bug fixes:
- Fix extmark rendering in text.lua (table vs string hl handling)
- Fix timer leak: WinClosed autocmd now triggers view.close()
- Add GOBIN/GOPATH/~/go/bin awareness to is_installed() and new bin_path()
- Reject update_all() while tasks running (race condition fix)
- Implement _toggle_details with full binary info expansion
Phase 2 - Lazy.nvim-style controls:
- U = Update all, u = update cursor binary
- I = Install all missing, i = install cursor binary
- x = Abort, CR = toggle details, q/Esc = close
- Line-to-binary mapping for cursor-aware actions
Phase 3 - Auto-update checking:
- New checker module with go list/go version -m integration
- auto_check config option (daily/weekly/custom frequency)
- Persistent state in stdpath('data')/glaze/state.json
- :GlazeCheck command for manual checks
- Update indicators in UI (version info + arrows)
Phase 4 - Repo polish:
- MIT LICENSE file
- Doughnut-themed README with badges and Why Glaze? section
- Updated help docs with all new features/keybinds/API
249 lines
5.4 KiB
Lua
249 lines
5.4 KiB
Lua
---@brief [[
|
|
--- glaze.nvim task runner
|
|
--- Handles parallel Go binary installation/updates
|
|
---@brief ]]
|
|
|
|
local M = {}
|
|
|
|
---@class GlazeTask
|
|
---@field binary GlazeBinary
|
|
---@field status "pending"|"running"|"done"|"error"
|
|
---@field output string[]
|
|
---@field start_time? number
|
|
---@field end_time? number
|
|
---@field job_id? number
|
|
|
|
---@type GlazeTask[]
|
|
M._tasks = {}
|
|
|
|
---@type function?
|
|
M._on_update = nil
|
|
|
|
---@type boolean
|
|
M._running = false
|
|
|
|
---Get all current tasks.
|
|
---@return GlazeTask[]
|
|
function M.tasks()
|
|
return M._tasks
|
|
end
|
|
|
|
---Check if runner is active.
|
|
---@return boolean
|
|
function M.is_running()
|
|
return M._running
|
|
end
|
|
|
|
---Set update callback (called when task status changes).
|
|
---@param fn function
|
|
function M.on_update(fn)
|
|
M._on_update = fn
|
|
end
|
|
|
|
---@private
|
|
function M._notify()
|
|
if M._on_update then
|
|
vim.schedule(M._on_update)
|
|
end
|
|
end
|
|
|
|
---@param binary GlazeBinary
|
|
---@return GlazeTask
|
|
local function create_task(binary)
|
|
return {
|
|
binary = binary,
|
|
status = "pending",
|
|
output = {},
|
|
}
|
|
end
|
|
|
|
---@param task GlazeTask
|
|
local function run_task(task)
|
|
local glaze = require("glaze")
|
|
local cmd = vim.list_extend({}, glaze.config.go_cmd)
|
|
table.insert(cmd, "install")
|
|
table.insert(cmd, task.binary.url .. "@latest")
|
|
|
|
task.status = "running"
|
|
task.start_time = vim.uv.hrtime()
|
|
task.output = {}
|
|
M._notify()
|
|
|
|
task.job_id = vim.fn.jobstart(cmd, {
|
|
on_stdout = function(_, data)
|
|
if data then
|
|
for _, line in ipairs(data) do
|
|
if line ~= "" then
|
|
table.insert(task.output, line)
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
on_stderr = function(_, data)
|
|
if data then
|
|
for _, line in ipairs(data) do
|
|
if line ~= "" then
|
|
table.insert(task.output, line)
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
on_exit = function(_, code)
|
|
task.end_time = vim.uv.hrtime()
|
|
task.status = code == 0 and "done" or "error"
|
|
task.job_id = nil
|
|
|
|
-- Call binary callback if set
|
|
if task.binary.callback then
|
|
vim.schedule(function()
|
|
task.binary.callback(code == 0)
|
|
end)
|
|
end
|
|
|
|
M._notify()
|
|
M._process_queue()
|
|
end,
|
|
})
|
|
end
|
|
|
|
---@private
|
|
function M._process_queue()
|
|
local glaze = require("glaze")
|
|
local running = 0
|
|
local pending = {}
|
|
|
|
for _, task in ipairs(M._tasks) do
|
|
if task.status == "running" then
|
|
running = running + 1
|
|
elseif task.status == "pending" then
|
|
table.insert(pending, task)
|
|
end
|
|
end
|
|
|
|
-- Start pending tasks up to concurrency limit
|
|
local to_start = math.min(#pending, glaze.config.concurrency - running)
|
|
for i = 1, to_start do
|
|
run_task(pending[i])
|
|
end
|
|
|
|
-- Check if all done
|
|
if running == 0 and #pending == 0 then
|
|
M._running = false
|
|
M._notify()
|
|
end
|
|
end
|
|
|
|
---Run tasks for specified binaries.
|
|
---@param names string[]
|
|
---@param mode "install"|"update"
|
|
local function run(names, mode)
|
|
local glaze = require("glaze")
|
|
|
|
-- Reject if already running (race condition fix)
|
|
if M._running then
|
|
vim.notify("Glaze: tasks already running. Wait or abort first.", vim.log.levels.WARN)
|
|
return
|
|
end
|
|
|
|
-- Check for Go
|
|
local go_check = glaze.config.go_cmd[1]
|
|
if vim.fn.executable(go_check) ~= 1 then
|
|
vim.notify("Go is not installed. Please install Go first: https://go.dev/dl/", vim.log.levels.ERROR)
|
|
return
|
|
end
|
|
|
|
-- Filter binaries
|
|
local binaries = {}
|
|
for _, name in ipairs(names) do
|
|
local binary = glaze._binaries[name]
|
|
if binary then
|
|
if mode == "install" and glaze.is_installed(name) then
|
|
-- Skip already installed
|
|
else
|
|
table.insert(binaries, binary)
|
|
end
|
|
else
|
|
vim.notify("Unknown binary: " .. name, vim.log.levels.WARN)
|
|
end
|
|
end
|
|
|
|
if #binaries == 0 then
|
|
if mode == "install" then
|
|
vim.notify("All binaries already installed", vim.log.levels.INFO)
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Create tasks
|
|
M._tasks = {}
|
|
for _, binary in ipairs(binaries) do
|
|
table.insert(M._tasks, create_task(binary))
|
|
end
|
|
|
|
M._running = true
|
|
M._notify()
|
|
M._process_queue()
|
|
|
|
-- Open UI
|
|
require("glaze.view").open()
|
|
end
|
|
|
|
---Update specific binaries.
|
|
---@param names string[]
|
|
function M.update(names)
|
|
run(names, "update")
|
|
end
|
|
|
|
---Update all registered binaries.
|
|
function M.update_all()
|
|
local glaze = require("glaze")
|
|
run(vim.tbl_keys(glaze._binaries), "update")
|
|
end
|
|
|
|
---Install specific binaries.
|
|
---@param names string[]
|
|
function M.install(names)
|
|
run(names, "install")
|
|
end
|
|
|
|
---Install all missing binaries.
|
|
function M.install_missing()
|
|
local glaze = require("glaze")
|
|
local missing = {}
|
|
for name, _ in pairs(glaze._binaries) do
|
|
if not glaze.is_installed(name) then
|
|
table.insert(missing, name)
|
|
end
|
|
end
|
|
if #missing > 0 then
|
|
run(missing, "install")
|
|
else
|
|
vim.notify("All binaries already installed", vim.log.levels.INFO)
|
|
end
|
|
end
|
|
|
|
---Abort all running tasks.
|
|
function M.abort()
|
|
for _, task in ipairs(M._tasks) do
|
|
if task.job_id then
|
|
vim.fn.jobstop(task.job_id)
|
|
task.status = "error"
|
|
table.insert(task.output, "Aborted by user")
|
|
end
|
|
end
|
|
M._running = false
|
|
M._notify()
|
|
end
|
|
|
|
---Get task statistics.
|
|
---@return { total: number, done: number, error: number, running: number, pending: number }
|
|
function M.stats()
|
|
local stats = { total = #M._tasks, done = 0, error = 0, running = 0, pending = 0 }
|
|
for _, task in ipairs(M._tasks) do
|
|
stats[task.status] = (stats[task.status] or 0) + 1
|
|
end
|
|
return stats
|
|
end
|
|
|
|
return M
|