Files
glaze.nvim/lua/glaze/init.lua
Tai Groot cd2571d3f2 feat: bug fixes, lazy.nvim-style controls, auto-update checking, repo polish
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
2026-02-19 00:47:19 +00:00

238 lines
5.8 KiB
Lua

---@brief [[
--- glaze.nvim - Centralized Go binary management for Neovim plugins
---
--- A Mason/Lazy-style interface for managing Go binaries across multiple plugins.
--- Register your plugin's binaries once, update them all with a single command.
---
--- Usage:
--- require("glaze").setup({})
--- require("glaze").register("freeze", "github.com/charmbracelet/freeze")
--- require("glaze").register("glow", "github.com/charmbracelet/glow")
---@brief ]]
local M = {}
---@class GlazeBinary
---@field name string Binary name (executable name)
---@field url string Go module URL (without @version)
---@field plugin? string Plugin that registered this binary
---@field callback? fun(success: boolean) Optional callback after install/update
---@class GlazeAutoCheckConfig
---@field enabled boolean Whether to auto-check for updates
---@field frequency string|number Frequency: "daily", "weekly", or hours as number
---@class GlazeConfig
---@field ui GlazeUIConfig
---@field concurrency number Max parallel installations
---@field go_cmd string[] Go command (supports goenv)
---@field auto_check GlazeAutoCheckConfig
---@class GlazeUIConfig
---@field border string Border style
---@field size { width: number, height: number }
---@field icons GlazeIcons
---@class GlazeIcons
---@field pending string
---@field running string
---@field done string
---@field error string
---@field binary string
---@type GlazeConfig
M.config = {
ui = {
border = "rounded",
size = { width = 0.7, height = 0.8 },
icons = {
pending = "",
running = "",
done = "",
error = "",
binary = "󰆍",
},
},
concurrency = 4,
go_cmd = { "go" },
auto_check = {
enabled = true,
frequency = "daily",
},
}
---@type table<string, GlazeBinary>
M._binaries = {}
---@type number?
M._ns = nil
---@param opts? GlazeConfig
function M.setup(opts)
M.config = vim.tbl_deep_extend("force", M.config, opts or {})
M._ns = vim.api.nvim_create_namespace("glaze")
-- Auto-detect goenv
if vim.fn.executable("goenv") == 1 then
M.config.go_cmd = { "goenv", "exec", "go" }
end
-- Create commands
vim.api.nvim_create_user_command("Glaze", function()
require("glaze.view").open()
end, { desc = "Open Glaze UI" })
vim.api.nvim_create_user_command("GlazeUpdate", function(cmd)
if cmd.args and cmd.args ~= "" then
require("glaze.runner").update({ cmd.args })
else
require("glaze.runner").update_all()
end
end, {
desc = "Update Go binaries",
nargs = "?",
complete = function()
return vim.tbl_keys(M._binaries)
end,
})
vim.api.nvim_create_user_command("GlazeInstall", function(cmd)
if cmd.args and cmd.args ~= "" then
require("glaze.runner").install({ cmd.args })
else
require("glaze.runner").install_missing()
end
end, {
desc = "Install Go binaries",
nargs = "?",
complete = function()
return vim.tbl_keys(M._binaries)
end,
})
vim.api.nvim_create_user_command("GlazeCheck", function()
require("glaze.checker").check()
end, { desc = "Check for binary updates" })
-- Auto-check for updates
if M.config.auto_check.enabled then
vim.defer_fn(function()
require("glaze.checker").auto_check()
end, 3000)
end
end
---Register a binary for management.
---@param name string Binary/executable name
---@param url string Go module URL (e.g., "github.com/charmbracelet/freeze")
---@param opts? { plugin?: string, callback?: fun(success: boolean) }
function M.register(name, url, opts)
opts = opts or {}
M._binaries[name] = {
name = name,
url = url,
plugin = opts.plugin,
callback = opts.callback,
}
end
---Unregister a binary.
---@param name string Binary name to unregister
function M.unregister(name)
M._binaries[name] = nil
end
---Get all registered binaries.
---@return table<string, GlazeBinary>
function M.binaries()
return M._binaries
end
---Check if a binary is installed.
---Checks PATH, $GOBIN, $GOPATH/bin, and $(go env GOBIN).
---@param name string Binary name
---@return boolean
function M.is_installed(name)
-- Check PATH first
if vim.fn.executable(name) == 1 then
return true
end
-- Check $GOBIN
local gobin = os.getenv("GOBIN")
if gobin and gobin ~= "" then
local path = gobin .. "/" .. name
if vim.uv.fs_stat(path) then
return true
end
end
-- Check $GOPATH/bin
local gopath = os.getenv("GOPATH")
if gopath and gopath ~= "" then
local path = gopath .. "/bin/" .. name
if vim.uv.fs_stat(path) then
return true
end
end
-- Check default ~/go/bin
local home = os.getenv("HOME") or os.getenv("USERPROFILE") or ""
local default_path = home .. "/go/bin/" .. name
if vim.uv.fs_stat(default_path) then
return true
end
return false
end
---Get the install path for a binary if found.
---@param name string Binary name
---@return string? path Full path to the binary, or nil
function M.bin_path(name)
-- Check PATH
local which = vim.fn.exepath(name)
if which ~= "" then
return which
end
-- Check $GOBIN
local gobin = os.getenv("GOBIN")
if gobin and gobin ~= "" then
local path = gobin .. "/" .. name
if vim.uv.fs_stat(path) then
return path
end
end
-- Check $GOPATH/bin
local gopath = os.getenv("GOPATH")
if gopath and gopath ~= "" then
local path = gopath .. "/bin/" .. name
if vim.uv.fs_stat(path) then
return path
end
end
-- Check default ~/go/bin
local home = os.getenv("HOME") or os.getenv("USERPROFILE") or ""
local default_path = home .. "/go/bin/" .. name
if vim.uv.fs_stat(default_path) then
return default_path
end
return nil
end
---Get binary installation status.
---@param name string Binary name
---@return "installed"|"missing"|"unknown"
function M.status(name)
if not M._binaries[name] then
return "unknown"
end
return M.is_installed(name) and "installed" or "missing"
end
return M