mirror of
https://github.com/taigrr/glaze.nvim.git
synced 2026-04-14 00:48:39 -07:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9463ba2b4b | |||
| bb82cde133 | |||
| 9e7f655026 | |||
| 67255b346c | |||
| 93acbc55c5 | |||
| d94fee916b | |||
| ea73ed51b1 | |||
| 5867abd592 |
25
.github/workflows/ci.yml
vendored
Normal file
25
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
pull_request:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check formatting with StyLua
|
||||||
|
uses: JohnnyMorganz/stylua-action@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
version: latest
|
||||||
|
args: --check .
|
||||||
|
|
||||||
|
- name: Lint with luacheck
|
||||||
|
uses: lunarmodules/luacheck@v1
|
||||||
|
with:
|
||||||
|
args: lua/
|
||||||
7
.luacheckrc
Normal file
7
.luacheckrc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
std = "luajit"
|
||||||
|
globals = { "vim" }
|
||||||
|
max_line_length = 150
|
||||||
|
|
||||||
|
ignore = {
|
||||||
|
"212", -- unused argument (common in callbacks)
|
||||||
|
}
|
||||||
6
.stylua.toml
Normal file
6
.stylua.toml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
column_width = 120
|
||||||
|
line_endings = "Unix"
|
||||||
|
indent_type = "Spaces"
|
||||||
|
indent_width = 2
|
||||||
|
quote_style = "AutoPreferDouble"
|
||||||
|
call_parentheses = "Always"
|
||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
BSD Zero Clause License
|
BSD Zero Clause License
|
||||||
|
|
||||||
Copyright (c) 2025 Tai Groot
|
Copyright (c) 2026 Tai Groot
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted.
|
purpose with or without fee is hereby granted.
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="https://github.com/taigrr/glaze.nvim/releases/latest">
|
<a href="https://github.com/taigrr/glaze.nvim/releases/latest">
|
||||||
<img alt="Latest release" src="https://img.shields.io/github/v/release/taigrr/glaze.nvim?style=for-the-badge&logo=starship&color=FF6AD5&logoColor=D9E0EE&labelColor=302D41&include_prerelease&sort=semver">
|
<img alt="Latest release" src="https://img.shields.io/github/v/release/taigrr/glaze.nvim?style=for-the-badge&logo=starship&color=FF6AD5&logoColor=D9E0EE&labelColor=302D41&sort=semver&include_prerelease">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/taigrr/glaze.nvim/pulse">
|
<a href="https://github.com/taigrr/glaze.nvim/pulse">
|
||||||
<img alt="Last commit" src="https://img.shields.io/github/last-commit/taigrr/glaze.nvim?style=for-the-badge&logo=starship&color=8bd5ca&logoColor=D9E0EE&labelColor=302D41">
|
<img alt="Last commit" src="https://img.shields.io/github/last-commit/taigrr/glaze.nvim?style=for-the-badge&logo=starship&color=8bd5ca&labelColor=302D41&logoColor=D9E0EE">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/taigrr/glaze.nvim/blob/master/LICENSE">
|
<a href="https://github.com/taigrr/glaze.nvim/blob/master/LICENSE">
|
||||||
<img alt="License" src="https://img.shields.io/github/license/taigrr/glaze.nvim?style=for-the-badge&logo=starship&color=ee999f&logoColor=D9E0EE&labelColor=302D41">
|
<img alt="License" src="https://img.shields.io/github/license/taigrr/glaze.nvim?style=for-the-badge&logo=starship&color=ee999f&labelColor=302D41&logoColor=D9E0EE">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/taigrr/glaze.nvim/stargazers">
|
<a href="https://github.com/taigrr/glaze.nvim/stargazers">
|
||||||
<img alt="Stars" src="https://img.shields.io/github/stars/taigrr/glaze.nvim?style=for-the-badge&logo=starship&color=c69ff5&logoColor=D9E0EE&labelColor=302D41">
|
<img alt="Stars" src="https://img.shields.io/github/stars/taigrr/glaze.nvim?style=for-the-badge&logo=starship&color=c69ff5&labelColor=302D41&logoColor=D9E0EE">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -127,6 +127,61 @@ function M.get_update_info()
|
|||||||
return M._update_info
|
return M._update_info
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Refresh version info for a single binary (called after install/update).
|
||||||
|
---@param name string Binary name
|
||||||
|
---@param callback? fun() Optional callback when done
|
||||||
|
function M.refresh_version(name, callback)
|
||||||
|
local glaze = require("glaze")
|
||||||
|
local binary = glaze._binaries[name]
|
||||||
|
if not binary then
|
||||||
|
if callback then
|
||||||
|
callback()
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
get_installed_version(name, function(installed)
|
||||||
|
local info = M._update_info[name]
|
||||||
|
or {
|
||||||
|
name = name,
|
||||||
|
installed_version = nil,
|
||||||
|
latest_version = nil,
|
||||||
|
has_update = false,
|
||||||
|
}
|
||||||
|
info.installed_version = installed
|
||||||
|
|
||||||
|
-- If we have latest version cached, check if still needs update
|
||||||
|
if info.latest_version and installed then
|
||||||
|
info.has_update = installed ~= info.latest_version
|
||||||
|
else
|
||||||
|
info.has_update = false
|
||||||
|
end
|
||||||
|
|
||||||
|
M._update_info[name] = info
|
||||||
|
|
||||||
|
-- Persist to state
|
||||||
|
local state = read_state()
|
||||||
|
state.update_info = state.update_info or {}
|
||||||
|
state.update_info[name] = {
|
||||||
|
installed_version = info.installed_version,
|
||||||
|
latest_version = info.latest_version,
|
||||||
|
has_update = info.has_update,
|
||||||
|
}
|
||||||
|
write_state(state)
|
||||||
|
|
||||||
|
-- Refresh UI if open
|
||||||
|
vim.schedule(function()
|
||||||
|
local ok, view = pcall(require, "glaze.view")
|
||||||
|
if ok and view._float and view._float:valid() then
|
||||||
|
view.render()
|
||||||
|
end
|
||||||
|
if callback then
|
||||||
|
callback()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
---Check for updates on all registered binaries.
|
---Check for updates on all registered binaries.
|
||||||
---@param opts? { silent?: boolean }
|
---@param opts? { silent?: boolean }
|
||||||
function M.check(opts)
|
function M.check(opts)
|
||||||
@@ -149,12 +204,9 @@ function M.check(opts)
|
|||||||
end
|
end
|
||||||
|
|
||||||
M._checking = true
|
M._checking = true
|
||||||
local remaining = 0
|
|
||||||
local updates_found = 0
|
local updates_found = 0
|
||||||
|
local remaining = vim.tbl_count(binaries)
|
||||||
for name, _ in pairs(binaries) do
|
for name, binary in pairs(binaries) do
|
||||||
remaining = remaining + 2 -- installed version + latest version
|
|
||||||
|
|
||||||
local info = {
|
local info = {
|
||||||
name = name,
|
name = name,
|
||||||
installed_version = nil,
|
installed_version = nil,
|
||||||
@@ -163,16 +215,6 @@ function M.check(opts)
|
|||||||
}
|
}
|
||||||
M._update_info[name] = info
|
M._update_info[name] = info
|
||||||
|
|
||||||
get_installed_version(name, function()
|
|
||||||
-- callback receives version from the jobstart; re-check via closure
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Simplified: check each binary sequentially-ish
|
|
||||||
remaining = vim.tbl_count(binaries)
|
|
||||||
for name, binary in pairs(binaries) do
|
|
||||||
local info = M._update_info[name]
|
|
||||||
|
|
||||||
get_installed_version(name, function(installed)
|
get_installed_version(name, function(installed)
|
||||||
info.installed_version = installed
|
info.installed_version = installed
|
||||||
|
|
||||||
|
|||||||
@@ -72,10 +72,11 @@ function M.check()
|
|||||||
else
|
else
|
||||||
vim.health.ok(count .. " binary(ies) registered")
|
vim.health.ok(count .. " binary(ies) registered")
|
||||||
for name, binary in pairs(binaries) do
|
for name, binary in pairs(binaries) do
|
||||||
|
local pi = (binary.plugins and #binary.plugins > 0) and (" (" .. table.concat(binary.plugins, ", ") .. ")") or ""
|
||||||
if glaze.is_installed(name) then
|
if glaze.is_installed(name) then
|
||||||
vim.health.ok(" " .. name .. " — installed" .. (binary.plugin and (" (" .. binary.plugin .. ")") or ""))
|
vim.health.ok(" " .. name .. " — installed" .. pi)
|
||||||
else
|
else
|
||||||
vim.health.warn(" " .. name .. " — missing" .. (binary.plugin and (" (" .. binary.plugin .. ")") or ""), {
|
vim.health.warn(" " .. name .. " — missing" .. pi, {
|
||||||
"Run :GlazeInstall " .. name,
|
"Run :GlazeInstall " .. name,
|
||||||
"Or: go install " .. binary.url .. "@latest",
|
"Or: go install " .. binary.url .. "@latest",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ local M = {}
|
|||||||
---@class GlazeBinary
|
---@class GlazeBinary
|
||||||
---@field name string Binary name (executable name)
|
---@field name string Binary name (executable name)
|
||||||
---@field url string Go module URL (without @version)
|
---@field url string Go module URL (without @version)
|
||||||
---@field plugin? string Plugin that registered this binary
|
---@field plugins string[] Plugins that registered this binary
|
||||||
---@field callback? fun(success: boolean) Optional callback after install/update
|
---@field callbacks table<string, fun(success: boolean)> Callbacks keyed by plugin name
|
||||||
|
|
||||||
---@class GlazeAutoCheckConfig
|
---@class GlazeAutoCheckConfig
|
||||||
---@field enabled? boolean Whether to auto-check for updates
|
---@field enabled? boolean Whether to auto-check for updates
|
||||||
@@ -85,6 +85,12 @@ M._binaries = {}
|
|||||||
---@type number?
|
---@type number?
|
||||||
M._ns = nil
|
M._ns = nil
|
||||||
|
|
||||||
|
---@type table<string, boolean> Binaries queued for auto-install
|
||||||
|
M._auto_install_queue = {}
|
||||||
|
|
||||||
|
---@type number? Timer for batched auto-install
|
||||||
|
M._auto_install_timer = nil
|
||||||
|
|
||||||
---@param opts? GlazeConfig
|
---@param opts? GlazeConfig
|
||||||
function M.setup(opts)
|
function M.setup(opts)
|
||||||
M.config = vim.tbl_deep_extend("force", M.config, opts or {})
|
M.config = vim.tbl_deep_extend("force", M.config, opts or {})
|
||||||
@@ -147,23 +153,68 @@ end
|
|||||||
---@param opts? { plugin?: string, callback?: fun(success: boolean) }
|
---@param opts? { plugin?: string, callback?: fun(success: boolean) }
|
||||||
function M.register(name, url, opts)
|
function M.register(name, url, opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
|
local plugin = opts.plugin or "unknown"
|
||||||
|
|
||||||
|
-- Check if this URL is already registered under a different name
|
||||||
|
for existing_name, binary in pairs(M._binaries) do
|
||||||
|
if binary.url == url and existing_name ~= name then
|
||||||
|
-- Same URL, different name - merge into existing entry
|
||||||
|
if not vim.tbl_contains(binary.plugins, plugin) then
|
||||||
|
table.insert(binary.plugins, plugin)
|
||||||
|
end
|
||||||
|
if opts.callback then
|
||||||
|
binary.callbacks[plugin] = opts.callback
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if this name is already registered
|
||||||
|
local existing = M._binaries[name]
|
||||||
|
if existing then
|
||||||
|
-- Merge plugin into existing entry
|
||||||
|
if not vim.tbl_contains(existing.plugins, plugin) then
|
||||||
|
table.insert(existing.plugins, plugin)
|
||||||
|
end
|
||||||
|
if opts.callback then
|
||||||
|
existing.callbacks[plugin] = opts.callback
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- New binary registration
|
||||||
M._binaries[name] = {
|
M._binaries[name] = {
|
||||||
name = name,
|
name = name,
|
||||||
url = url,
|
url = url,
|
||||||
plugin = opts.plugin,
|
plugins = opts.plugin and { opts.plugin } or {},
|
||||||
callback = opts.callback,
|
callbacks = opts.callback and { [plugin] = opts.callback } or {},
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Auto-install if enabled and binary is missing
|
-- Queue for auto-install if enabled and binary is missing.
|
||||||
|
-- Uses a batched timer so multiple registers don't race.
|
||||||
if M.config.auto_install.enabled and not M.is_installed(name) then
|
if M.config.auto_install.enabled and not M.is_installed(name) then
|
||||||
vim.defer_fn(function()
|
M._auto_install_queue[name] = true
|
||||||
if not M.is_installed(name) then
|
if M._auto_install_timer then
|
||||||
|
vim.fn.timer_stop(M._auto_install_timer)
|
||||||
|
end
|
||||||
|
M._auto_install_timer = vim.fn.timer_start(200, function()
|
||||||
|
M._auto_install_timer = nil
|
||||||
|
vim.schedule(function()
|
||||||
|
local to_install = {}
|
||||||
|
for queued_name, _ in pairs(M._auto_install_queue) do
|
||||||
|
if not M.is_installed(queued_name) then
|
||||||
|
table.insert(to_install, queued_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M._auto_install_queue = {}
|
||||||
|
if #to_install > 0 then
|
||||||
if not M.config.auto_install.silent then
|
if not M.config.auto_install.silent then
|
||||||
vim.notify("[glaze] Auto-installing " .. name .. "…", vim.log.levels.INFO)
|
vim.notify("[glaze] Auto-installing " .. table.concat(to_install, ", ") .. "…", vim.log.levels.INFO)
|
||||||
end
|
end
|
||||||
require("glaze.runner").install({ name })
|
require("glaze.runner").install(to_install, { silent = M.config.auto_install.silent })
|
||||||
end
|
end
|
||||||
end, 100)
|
end)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -93,10 +93,17 @@ local function run_task(task)
|
|||||||
task.status = code == 0 and "done" or "error"
|
task.status = code == 0 and "done" or "error"
|
||||||
task.job_id = nil
|
task.job_id = nil
|
||||||
|
|
||||||
-- Call binary callback if set
|
-- Refresh version info on success
|
||||||
if task.binary.callback then
|
if code == 0 then
|
||||||
|
require("glaze.checker").refresh_version(task.binary.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Call all registered callbacks
|
||||||
|
if task.binary.callbacks then
|
||||||
vim.schedule(function()
|
vim.schedule(function()
|
||||||
task.binary.callback(code == 0)
|
for _, cb in pairs(task.binary.callbacks) do
|
||||||
|
cb(code == 0)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -136,12 +143,16 @@ end
|
|||||||
---Run tasks for specified binaries.
|
---Run tasks for specified binaries.
|
||||||
---@param names string[]
|
---@param names string[]
|
||||||
---@param mode "install"|"update"
|
---@param mode "install"|"update"
|
||||||
local function run(names, mode)
|
---@param opts? { silent?: boolean }
|
||||||
|
local function run(names, mode, opts)
|
||||||
|
opts = opts or {}
|
||||||
local glaze = require("glaze")
|
local glaze = require("glaze")
|
||||||
|
|
||||||
-- Reject if already running (race condition fix)
|
-- Reject if already running (race condition fix)
|
||||||
if M._running then
|
if M._running then
|
||||||
|
if not opts.silent then
|
||||||
vim.notify("Glaze: tasks already running. Wait or abort first.", vim.log.levels.WARN)
|
vim.notify("Glaze: tasks already running. Wait or abort first.", vim.log.levels.WARN)
|
||||||
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -157,18 +168,18 @@ local function run(names, mode)
|
|||||||
for _, name in ipairs(names) do
|
for _, name in ipairs(names) do
|
||||||
local binary = glaze._binaries[name]
|
local binary = glaze._binaries[name]
|
||||||
if binary then
|
if binary then
|
||||||
if mode == "install" and glaze.is_installed(name) then
|
if not (mode == "install" and glaze.is_installed(name)) then
|
||||||
-- Skip already installed
|
|
||||||
else
|
|
||||||
table.insert(binaries, binary)
|
table.insert(binaries, binary)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
if not opts.silent then
|
||||||
vim.notify("Unknown binary: " .. name, vim.log.levels.WARN)
|
vim.notify("Unknown binary: " .. name, vim.log.levels.WARN)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if #binaries == 0 then
|
if #binaries == 0 then
|
||||||
if mode == "install" then
|
if mode == "install" and not opts.silent then
|
||||||
vim.notify("All binaries already installed", vim.log.levels.INFO)
|
vim.notify("All binaries already installed", vim.log.levels.INFO)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
@@ -184,9 +195,11 @@ local function run(names, mode)
|
|||||||
M._notify()
|
M._notify()
|
||||||
M._process_queue()
|
M._process_queue()
|
||||||
|
|
||||||
-- Open UI
|
-- Open UI (skip for silent/auto-install operations)
|
||||||
|
if not opts.silent then
|
||||||
require("glaze.view").open()
|
require("glaze.view").open()
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---Update specific binaries.
|
---Update specific binaries.
|
||||||
---@param names string[]
|
---@param names string[]
|
||||||
@@ -202,8 +215,9 @@ end
|
|||||||
|
|
||||||
---Install specific binaries.
|
---Install specific binaries.
|
||||||
---@param names string[]
|
---@param names string[]
|
||||||
function M.install(names)
|
---@param opts? { silent?: boolean }
|
||||||
run(names, "install")
|
function M.install(names, opts)
|
||||||
|
run(names, "install", opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
---Install all missing binaries.
|
---Install all missing binaries.
|
||||||
|
|||||||
@@ -164,16 +164,16 @@ function M.render()
|
|||||||
text:append(" ", nil, { indent = 2 })
|
text:append(" ", nil, { indent = 2 })
|
||||||
text:append(" U ", "GlazeButtonActive"):append(" Update All ", "GlazeButton")
|
text:append(" U ", "GlazeButtonActive"):append(" Update All ", "GlazeButton")
|
||||||
text:append(" ")
|
text:append(" ")
|
||||||
text:append(" u ", "GlazeButtonActive"):append(" Update ", "GlazeButton")
|
text:append(" u ", "GlazeButtonActive"):append(" Update Selected ", "GlazeButton")
|
||||||
text:append(" ")
|
text:append(" ")
|
||||||
text:append(" I ", "GlazeButtonActive"):append(" Install All ", "GlazeButton")
|
text:append(" I ", "GlazeButtonActive"):append(" Install All ", "GlazeButton")
|
||||||
text:append(" ")
|
text:append(" ")
|
||||||
text:append(" i ", "GlazeButtonActive"):append(" Install ", "GlazeButton")
|
text:append(" i ", "GlazeButtonActive"):append(" Install Selected ", "GlazeButton")
|
||||||
text:nl()
|
text:nl()
|
||||||
text:append(" ", nil, { indent = 2 })
|
text:append(" ", nil, { indent = 2 })
|
||||||
text:append(" x ", "GlazeButtonActive"):append(" Abort ", "GlazeButton")
|
text:append(" x ", "GlazeButtonActive"):append(" Abort ", "GlazeButton")
|
||||||
text:append(" ")
|
text:append(" ")
|
||||||
text:append(" ⏎ ", "GlazeButtonActive"):append(" Details ", "GlazeButton")
|
text:append(" <enter> ", "GlazeButtonActive"):append(" Details ", "GlazeButton")
|
||||||
text:append(" ")
|
text:append(" ")
|
||||||
text:append(" q ", "GlazeButtonActive"):append(" Close ", "GlazeButton")
|
text:append(" q ", "GlazeButtonActive"):append(" Close ", "GlazeButton")
|
||||||
text:nl():nl()
|
text:nl():nl()
|
||||||
@@ -323,8 +323,8 @@ function M._render_binary(text, binary, icons, update_info)
|
|||||||
text:append(" " .. icon .. " ", icon_hl)
|
text:append(" " .. icon .. " ", icon_hl)
|
||||||
text:append(binary.name, "GlazeBinary")
|
text:append(binary.name, "GlazeBinary")
|
||||||
|
|
||||||
if binary.plugin then
|
if binary.plugins and #binary.plugins > 0 then
|
||||||
text:append(" (" .. binary.plugin .. ")", "GlazePlugin")
|
text:append(" (" .. table.concat(binary.plugins, ", ") .. ")", "GlazePlugin")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Show update available indicator
|
-- Show update available indicator
|
||||||
@@ -353,9 +353,9 @@ function M._render_binary(text, binary, icons, update_info)
|
|||||||
text:append(bin_path, "GlazeUrl"):nl()
|
text:append(bin_path, "GlazeUrl"):nl()
|
||||||
end
|
end
|
||||||
|
|
||||||
if binary.plugin then
|
if binary.plugins and #binary.plugins > 0 then
|
||||||
text:append("Plugin: ", "GlazeComment", { indent = 6 })
|
text:append("Plugins: ", "GlazeComment", { indent = 6 })
|
||||||
text:append(binary.plugin, "GlazePlugin"):nl()
|
text:append(table.concat(binary.plugins, ", "), "GlazePlugin"):nl()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Show last error output from tasks
|
-- Show last error output from tasks
|
||||||
|
|||||||
Reference in New Issue
Block a user