mirror of https://github.com/folke/lazy.nvim.git
feat: packspec
This commit is contained in:
parent
cd6a829343
commit
c9d691ba49
|
@ -179,6 +179,11 @@ M.defaults = {
|
||||||
-- Track each new require in the Lazy profiling tab
|
-- Track each new require in the Lazy profiling tab
|
||||||
require = false,
|
require = false,
|
||||||
},
|
},
|
||||||
|
packspec = {
|
||||||
|
enabled = true,
|
||||||
|
versions = true, -- Honor dependency versions in packspecs
|
||||||
|
path = vim.fn.stdpath("state") .. "/lazy/packspec.lua",
|
||||||
|
},
|
||||||
debug = false,
|
debug = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,6 +286,14 @@ function M.setup(opts)
|
||||||
require("lazy.manage.checker").start()
|
require("lazy.manage.checker").start()
|
||||||
end, 10)
|
end, 10)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- useful for plugin developers when making changes to a packspec file
|
||||||
|
vim.api.nvim_create_autocmd("BufWritePost", {
|
||||||
|
pattern = "package.lua",
|
||||||
|
callback = function()
|
||||||
|
require("lazy.view.commands").cmd("packspec")
|
||||||
|
end,
|
||||||
|
})
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
local Config = require("lazy.core.config")
|
||||||
|
local Util = require("lazy.util")
|
||||||
|
|
||||||
|
---@class PackSpec
|
||||||
|
---@field dependencies? table<string, string>
|
||||||
|
---@field lazy? LazyPluginSpec
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
M.lazy_file = "lazy.lua"
|
||||||
|
M.pkg_file = "pkg.json"
|
||||||
|
M.enable_lazy_file = false
|
||||||
|
|
||||||
|
---@alias LazyPkg {lazy?:(fun():LazySpec), pkg?:PackSpec}
|
||||||
|
|
||||||
|
---@type table<string, LazyPkg>
|
||||||
|
M.packspecs = nil
|
||||||
|
---@type table<string, LazySpec>
|
||||||
|
M.specs = {}
|
||||||
|
|
||||||
|
---@param spec LazyPkg
|
||||||
|
---@param plugin LazyPlugin
|
||||||
|
---@return LazySpec?
|
||||||
|
local function convert(plugin, spec)
|
||||||
|
---@type LazySpec
|
||||||
|
local ret = {}
|
||||||
|
|
||||||
|
local pkg = spec.pkg
|
||||||
|
if pkg then
|
||||||
|
if pkg.dependencies then
|
||||||
|
for url, version in pairs(pkg.dependencies) do
|
||||||
|
if (not Config.options.packspec.versions) or version == "*" or version == "" then
|
||||||
|
version = nil
|
||||||
|
end
|
||||||
|
-- HACK: Add `.git` to github urls
|
||||||
|
if url:find("github") and not url:match("%.git$") then
|
||||||
|
url = url .. ".git"
|
||||||
|
end
|
||||||
|
ret[#ret + 1] = { url = url, version = version }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local p = pkg.lazy
|
||||||
|
if p then
|
||||||
|
p.url = p.url or plugin.url
|
||||||
|
p.dir = p.dir or plugin.dir
|
||||||
|
ret[#ret + 1] = p
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if spec.lazy then
|
||||||
|
ret[#ret + 1] = spec.lazy()
|
||||||
|
end
|
||||||
|
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
local function load()
|
||||||
|
Util.track("packspec")
|
||||||
|
M.packspecs = {}
|
||||||
|
if vim.loop.fs_stat(Config.options.packspec.path) then
|
||||||
|
Util.try(function()
|
||||||
|
M.packspecs = loadfile(Config.options.packspec.path)()
|
||||||
|
end, "Error loading packspecs:")
|
||||||
|
end
|
||||||
|
Util.track()
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param plugin LazyPlugin
|
||||||
|
---@return LazySpec?
|
||||||
|
function M.get(plugin)
|
||||||
|
if not M.packspecs then
|
||||||
|
load()
|
||||||
|
end
|
||||||
|
|
||||||
|
if not M.packspecs[plugin.dir] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
M.specs[plugin.dir] = M.specs[plugin.dir] or convert(plugin, M.packspecs[plugin.dir])
|
||||||
|
return vim.deepcopy(M.specs[plugin.dir])
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.update()
|
||||||
|
local ret = {}
|
||||||
|
for _, plugin in pairs(Config.plugins) do
|
||||||
|
local spec = {
|
||||||
|
pkg = M.pkg(plugin),
|
||||||
|
lazy = M.enable_lazy_file and M.lazy_pkg(plugin) or nil,
|
||||||
|
}
|
||||||
|
if not vim.tbl_isempty(spec) then
|
||||||
|
ret[plugin.dir] = spec
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local code = "return " .. Util.dump(ret)
|
||||||
|
Util.write_file(Config.options.packspec.path, code)
|
||||||
|
M.packspecs = nil
|
||||||
|
M.specs = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param plugin LazyPlugin
|
||||||
|
function M.lazy_pkg(plugin)
|
||||||
|
local file = Util.norm(plugin.dir .. "/" .. M.lazy_file)
|
||||||
|
if Util.file_exists(file) then
|
||||||
|
---@type LazySpec
|
||||||
|
local chunk = Util.try(function()
|
||||||
|
return loadfile(file)
|
||||||
|
end, "`" .. M.lazy_file .. "` for **" .. plugin.name .. "** has errors:")
|
||||||
|
if chunk then
|
||||||
|
return { _raw = ([[function() %s end]]):format(Util.read_file(file)) }
|
||||||
|
else
|
||||||
|
Util.error("Invalid `package.lua` for **" .. plugin.name .. "**")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param plugin LazyPlugin
|
||||||
|
function M.pkg(plugin)
|
||||||
|
local file = Util.norm(plugin.dir .. "/" .. M.pkg_file)
|
||||||
|
if Util.file_exists(file) then
|
||||||
|
---@type PackSpec
|
||||||
|
return Util.try(function()
|
||||||
|
return vim.json.decode(Util.read_file(file))
|
||||||
|
end, "`" .. M.pkg_file .. "` for **" .. plugin.name .. "** has errors:")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
|
@ -1,4 +1,5 @@
|
||||||
local Config = require("lazy.core.config")
|
local Config = require("lazy.core.config")
|
||||||
|
local Packspec = require("lazy.core.packspec")
|
||||||
local Util = require("lazy.core.util")
|
local Util = require("lazy.core.util")
|
||||||
|
|
||||||
---@class LazyCorePlugin
|
---@class LazyCorePlugin
|
||||||
|
@ -15,6 +16,8 @@ M.loading = false
|
||||||
---@field notifs {msg:string, level:number, file?:string}[]
|
---@field notifs {msg:string, level:number, file?:string}[]
|
||||||
---@field importing? string
|
---@field importing? string
|
||||||
---@field optional? boolean
|
---@field optional? boolean
|
||||||
|
---@field packspecs table<string, boolean>
|
||||||
|
---@field names table<string,string>
|
||||||
local Spec = {}
|
local Spec = {}
|
||||||
M.Spec = Spec
|
M.Spec = Spec
|
||||||
M.last_fid = 0
|
M.last_fid = 0
|
||||||
|
@ -32,7 +35,9 @@ function Spec.new(spec, opts)
|
||||||
self.dirty = {}
|
self.dirty = {}
|
||||||
self.notifs = {}
|
self.notifs = {}
|
||||||
self.ignore_installed = {}
|
self.ignore_installed = {}
|
||||||
|
self.packspecs = {}
|
||||||
self.optional = opts and opts.optional
|
self.optional = opts and opts.optional
|
||||||
|
self.names = {}
|
||||||
if spec then
|
if spec then
|
||||||
self:parse(spec)
|
self:parse(spec)
|
||||||
end
|
end
|
||||||
|
@ -45,6 +50,7 @@ function Spec:parse(spec)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- PERF: optimized code to get package name without using lua patterns
|
-- PERF: optimized code to get package name without using lua patterns
|
||||||
|
---@return string
|
||||||
function Spec.get_name(pkg)
|
function Spec.get_name(pkg)
|
||||||
local name = pkg:sub(-4) == ".git" and pkg:sub(1, -5) or pkg
|
local name = pkg:sub(-4) == ".git" and pkg:sub(1, -5) or pkg
|
||||||
name = name:sub(-1) == "/" and name:sub(1, -2) or name
|
name = name:sub(-1) == "/" and name:sub(1, -2) or name
|
||||||
|
@ -83,7 +89,17 @@ function Spec:add(plugin, results)
|
||||||
-- local plugin
|
-- local plugin
|
||||||
plugin.name = plugin.name or Spec.get_name(plugin.dir)
|
plugin.name = plugin.name or Spec.get_name(plugin.dir)
|
||||||
elseif plugin.url then
|
elseif plugin.url then
|
||||||
plugin.name = plugin.name or Spec.get_name(plugin.url)
|
if plugin.name then
|
||||||
|
self.names[plugin.url] = plugin.name
|
||||||
|
local name = Spec.get_name(plugin.url)
|
||||||
|
if name and self.plugins[name] then
|
||||||
|
self.plugins[name].name = plugin.name
|
||||||
|
self.plugins[plugin.name] = self.plugins[name]
|
||||||
|
self.plugins[name] = nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
plugin.name = self.names[plugin.url] or Spec.get_name(plugin.url)
|
||||||
|
end
|
||||||
-- check for dev plugins
|
-- check for dev plugins
|
||||||
if plugin.dev == nil then
|
if plugin.dev == nil then
|
||||||
for _, pattern in ipairs(Config.options.dev.patterns) do
|
for _, pattern in ipairs(Config.options.dev.patterns) do
|
||||||
|
@ -156,6 +172,15 @@ function Spec:add(plugin, results)
|
||||||
table.remove(M.fid_stack)
|
table.remove(M.fid_stack)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- import the plugin's spec
|
||||||
|
if Config.options.packspec.enabled and plugin.dir and not self.packspecs[plugin.dir] then
|
||||||
|
self.packspecs[plugin.dir] = true
|
||||||
|
local packspec = Packspec.get(plugin)
|
||||||
|
if packspec then
|
||||||
|
self:normalize(packspec, nil, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if self.plugins[plugin.name] then
|
if self.plugins[plugin.name] then
|
||||||
plugin = self:merge(self.plugins[plugin.name], plugin)
|
plugin = self:merge(self.plugins[plugin.name], plugin)
|
||||||
end
|
end
|
||||||
|
|
|
@ -92,6 +92,7 @@ function M.install(opts)
|
||||||
}, opts):wait(function()
|
}, opts):wait(function()
|
||||||
require("lazy.manage.lock").update()
|
require("lazy.manage.lock").update()
|
||||||
require("lazy.help").update()
|
require("lazy.help").update()
|
||||||
|
require("lazy.core.packspec").update()
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -116,6 +117,7 @@ function M.update(opts)
|
||||||
}, opts):wait(function()
|
}, opts):wait(function()
|
||||||
require("lazy.manage.lock").update()
|
require("lazy.manage.lock").update()
|
||||||
require("lazy.help").update()
|
require("lazy.help").update()
|
||||||
|
require("lazy.core.packspec").update()
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
--
|
--
|
||||||
|
|
|
@ -34,6 +34,20 @@ M.commands = {
|
||||||
health = function()
|
health = function()
|
||||||
vim.cmd.checkhealth("lazy")
|
vim.cmd.checkhealth("lazy")
|
||||||
end,
|
end,
|
||||||
|
pkg = function(opts)
|
||||||
|
local Pkg = require("lazy.core.packspec")
|
||||||
|
Pkg.update()
|
||||||
|
require("lazy.manage.reloader").reload({
|
||||||
|
{
|
||||||
|
file = "packspec", --Config.options.packspec.path,
|
||||||
|
what = "changed",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
for _, plugin in pairs(opts and opts.plugins or {}) do
|
||||||
|
local spec = Pkg.get(plugin)
|
||||||
|
Util.info(vim.inspect(spec), { lang = "lua", title = plugin.name })
|
||||||
|
end
|
||||||
|
end,
|
||||||
home = function()
|
home = function()
|
||||||
View.show("home")
|
View.show("home")
|
||||||
end,
|
end,
|
||||||
|
@ -74,7 +88,7 @@ M.commands = {
|
||||||
}
|
}
|
||||||
|
|
||||||
function M.complete(cmd, prefix)
|
function M.complete(cmd, prefix)
|
||||||
if not (ViewConfig.commands[cmd] or {}).plugins then
|
if not (ViewConfig.commands[cmd] or {}).plugins and cmd ~= "pkg" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
---@type string[]
|
---@type string[]
|
||||||
|
|
|
@ -30,6 +30,14 @@ describe("plugin spec url/name", function()
|
||||||
{ { "foo/bar", name = "foobar" }, { [1] = "foo/bar", name = "foobar", url = "https://github.com/foo/bar.git" } },
|
{ { "foo/bar", name = "foobar" }, { [1] = "foo/bar", name = "foobar", url = "https://github.com/foo/bar.git" } },
|
||||||
{ { "foo/bar", url = "123" }, { [1] = "foo/bar", name = "123", url = "123" } },
|
{ { "foo/bar", url = "123" }, { [1] = "foo/bar", name = "123", url = "123" } },
|
||||||
{ { url = "https://foobar" }, { name = "foobar", url = "https://foobar" } },
|
{ { url = "https://foobar" }, { name = "foobar", url = "https://foobar" } },
|
||||||
|
{
|
||||||
|
{ { url = "https://foo", name = "foobar" }, { url = "https://foo" } },
|
||||||
|
{ name = "foobar", url = "https://foo" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ { url = "https://foo" }, { url = "https://foo", name = "foobar" } },
|
||||||
|
{ name = "foobar", url = "https://foo" },
|
||||||
|
},
|
||||||
{ { url = "ssh://foobar" }, { name = "foobar", url = "ssh://foobar" } },
|
{ { url = "ssh://foobar" }, { name = "foobar", url = "ssh://foobar" } },
|
||||||
{ "foo/bar", { [1] = "foo/bar", name = "bar", url = "https://github.com/foo/bar.git" } },
|
{ "foo/bar", { [1] = "foo/bar", name = "bar", url = "https://github.com/foo/bar.git" } },
|
||||||
{ { { { "foo/bar" } } }, { [1] = "foo/bar", name = "bar", url = "https://github.com/foo/bar.git" } },
|
{ { { { "foo/bar" } } }, { [1] = "foo/bar", name = "bar", url = "https://github.com/foo/bar.git" } },
|
||||||
|
@ -46,6 +54,7 @@ describe("plugin spec url/name", function()
|
||||||
plugins[1]._ = {}
|
plugins[1]._ = {}
|
||||||
assert(#spec.notifs == 0)
|
assert(#spec.notifs == 0)
|
||||||
assert.equal(1, #plugins)
|
assert.equal(1, #plugins)
|
||||||
|
plugins[1]._.super = nil
|
||||||
assert.same(test[2], plugins[1])
|
assert.same(test[2], plugins[1])
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue