mirror of https://github.com/folke/lazy.nvim.git
feat: rewrite of spec resolving
This commit is contained in:
parent
8d35e60eeb
commit
75ffe56f70
|
@ -0,0 +1,159 @@
|
||||||
|
local Config = require("lazy.core.config")
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
M._fid = 0
|
||||||
|
|
||||||
|
local function next_id()
|
||||||
|
M._fid = M._fid + 1
|
||||||
|
return M._fid
|
||||||
|
end
|
||||||
|
|
||||||
|
---@class LazyFragments
|
||||||
|
---@field fragments table<number, LazyFragment>
|
||||||
|
---@field frag_stack number[]
|
||||||
|
---@field dep_stack number[]
|
||||||
|
---@field dirty table<number, boolean>
|
||||||
|
---@field spec LazySpecLoader
|
||||||
|
local F = {}
|
||||||
|
|
||||||
|
---@param spec LazySpecLoader
|
||||||
|
---@return LazyFragments
|
||||||
|
function M.new(spec)
|
||||||
|
local self = setmetatable({}, { __index = F })
|
||||||
|
self.fragments = {}
|
||||||
|
self.frag_stack = {}
|
||||||
|
self.dep_stack = {}
|
||||||
|
self.spec = spec
|
||||||
|
self.dirty = {}
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param id number
|
||||||
|
function F:get(id)
|
||||||
|
return self.fragments[id]
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param id number
|
||||||
|
function F:del(id)
|
||||||
|
-- del fragment
|
||||||
|
local fragment = self.fragments[id]
|
||||||
|
if not fragment then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
self.dirty[id] = true
|
||||||
|
|
||||||
|
-- remove from parent
|
||||||
|
local pid = fragment.pid
|
||||||
|
if pid then
|
||||||
|
local parent = self.fragments[pid]
|
||||||
|
if parent.frags then
|
||||||
|
---@param fid number
|
||||||
|
parent.frags = vim.tbl_filter(function(fid)
|
||||||
|
return fid ~= id
|
||||||
|
end, parent.frags)
|
||||||
|
end
|
||||||
|
if parent.deps then
|
||||||
|
---@param fid number
|
||||||
|
parent.deps = vim.tbl_filter(function(fid)
|
||||||
|
return fid ~= id
|
||||||
|
end, parent.deps)
|
||||||
|
end
|
||||||
|
self.dirty[pid] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- remove children
|
||||||
|
if fragment.frags then
|
||||||
|
for _, fid in ipairs(fragment.frags) do
|
||||||
|
self:del(fid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.fragments[id] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param plugin LazyPluginSpec
|
||||||
|
function F:add(plugin)
|
||||||
|
local id = next_id()
|
||||||
|
|
||||||
|
local pid = self.frag_stack[#self.frag_stack]
|
||||||
|
|
||||||
|
---@type LazyFragment
|
||||||
|
local fragment = {
|
||||||
|
id = id,
|
||||||
|
pid = pid,
|
||||||
|
name = plugin.name,
|
||||||
|
url = plugin.url,
|
||||||
|
dir = plugin.dir,
|
||||||
|
spec = plugin --[[@as LazyPlugin]],
|
||||||
|
}
|
||||||
|
|
||||||
|
-- short url / ref
|
||||||
|
if plugin[1] then
|
||||||
|
local slash = plugin[1]:find("/", 1, true)
|
||||||
|
if slash then
|
||||||
|
local prefix = plugin[1]:sub(1, 4)
|
||||||
|
if prefix == "http" or prefix == "git@" then
|
||||||
|
fragment.url = fragment.url or plugin[1]
|
||||||
|
else
|
||||||
|
fragment.name = fragment.name or plugin[1]:sub(slash + 1)
|
||||||
|
fragment.url = fragment.url or Config.options.git.url_format:format(plugin[1])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
fragment.name = fragment.name or plugin[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- name
|
||||||
|
fragment.name = fragment.name
|
||||||
|
or fragment.url and self.spec.get_name(fragment.url)
|
||||||
|
or fragment.dir and self.spec.get_name(fragment.dir)
|
||||||
|
if not fragment.name then
|
||||||
|
return self.spec:error("Invalid plugin spec " .. vim.inspect(plugin))
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(plugin.config) == "table" then
|
||||||
|
self.spec:warn(
|
||||||
|
"{" .. fragment.name .. "}: setting a table to `Plugin.config` is deprecated. Please use `Plugin.opts` instead"
|
||||||
|
)
|
||||||
|
---@diagnostic disable-next-line: assign-type-mismatch
|
||||||
|
plugin.opts = plugin.config
|
||||||
|
plugin.config = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
self.fragments[id] = fragment
|
||||||
|
|
||||||
|
-- add to parent
|
||||||
|
if pid then
|
||||||
|
local parent = self.fragments[pid]
|
||||||
|
parent.frags = parent.frags or {}
|
||||||
|
table.insert(parent.frags, id)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- add to parent's deps
|
||||||
|
local did = self.dep_stack[#self.dep_stack]
|
||||||
|
if did and did == pid then
|
||||||
|
fragment.dep = true
|
||||||
|
local parent = self.fragments[did]
|
||||||
|
parent.deps = parent.deps or {}
|
||||||
|
table.insert(parent.deps, id)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(self.frag_stack, id)
|
||||||
|
-- dependencies
|
||||||
|
if plugin.dependencies then
|
||||||
|
table.insert(self.dep_stack, id)
|
||||||
|
self.spec:normalize(plugin.dependencies)
|
||||||
|
table.remove(self.dep_stack)
|
||||||
|
end
|
||||||
|
-- child specs
|
||||||
|
if plugin.specs then
|
||||||
|
self.spec:normalize(plugin.specs)
|
||||||
|
end
|
||||||
|
table.remove(self.frag_stack)
|
||||||
|
|
||||||
|
return fragment
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
|
@ -105,7 +105,7 @@ function M.startup()
|
||||||
M.source(vim.env.VIMRUNTIME .. "/filetype.lua")
|
M.source(vim.env.VIMRUNTIME .. "/filetype.lua")
|
||||||
|
|
||||||
-- backup original rtp
|
-- backup original rtp
|
||||||
local rtp = vim.opt.rtp:get()
|
local rtp = vim.opt.rtp:get() --[[@as string[] ]]
|
||||||
|
|
||||||
-- 1. run plugin init
|
-- 1. run plugin init
|
||||||
Util.track({ start = "init" })
|
Util.track({ start = "init" })
|
||||||
|
@ -136,7 +136,7 @@ function M.startup()
|
||||||
if not path:find("after/?$") then
|
if not path:find("after/?$") then
|
||||||
-- these paths don't will already have their ftdetect ran,
|
-- these paths don't will already have their ftdetect ran,
|
||||||
-- by sourcing filetype.lua above, so skip them
|
-- by sourcing filetype.lua above, so skip them
|
||||||
M.did_ftdetect[path] = true
|
M.did_ftdetect[path] = path
|
||||||
M.packadd(path)
|
M.packadd(path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -144,7 +144,9 @@ function M.startup()
|
||||||
|
|
||||||
-- 4. load after plugins
|
-- 4. load after plugins
|
||||||
Util.track({ start = "after" })
|
Util.track({ start = "after" })
|
||||||
for _, path in ipairs(vim.opt.rtp:get()) do
|
for _, path in
|
||||||
|
ipairs(vim.opt.rtp:get() --[[@as string[] ]])
|
||||||
|
do
|
||||||
if path:find("after/?$") then
|
if path:find("after/?$") then
|
||||||
M.source_runtime(path, "plugin")
|
M.source_runtime(path, "plugin")
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,245 @@
|
||||||
|
local Config = require("lazy.core.config")
|
||||||
|
local Util = require("lazy.core.util")
|
||||||
|
|
||||||
|
---@class LazyMeta
|
||||||
|
---@field plugins table<string, LazyPlugin>
|
||||||
|
---@field str_to_meta table<string, LazyPlugin>
|
||||||
|
---@field frag_to_meta table<number, LazyPlugin>
|
||||||
|
---@field dirty table<string, boolean>
|
||||||
|
---@field spec LazySpecLoader
|
||||||
|
---@field fragments LazyFragments
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
---@param spec LazySpecLoader
|
||||||
|
---@return LazyMeta
|
||||||
|
function M.new(spec)
|
||||||
|
local self = setmetatable({}, { __index = M })
|
||||||
|
self.spec = spec
|
||||||
|
self.fragments = require("lazy.core.fragments").new(spec)
|
||||||
|
self.plugins = {}
|
||||||
|
self.frag_to_meta = {}
|
||||||
|
self.str_to_meta = {}
|
||||||
|
self.dirty = {}
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param name string
|
||||||
|
function M:del(name)
|
||||||
|
local meta = self.plugins[name]
|
||||||
|
if not meta then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for _, fid in ipairs(meta._.frags or {}) do
|
||||||
|
self.fragments:del(fid)
|
||||||
|
end
|
||||||
|
self.plugins[name] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param plugin LazyPluginSpec
|
||||||
|
function M:add(plugin)
|
||||||
|
local fragment = self.fragments:add(plugin)
|
||||||
|
if not fragment then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local meta = self.plugins[fragment.name]
|
||||||
|
or fragment.url and self.str_to_meta[fragment.url]
|
||||||
|
or fragment.dir and self.str_to_meta[fragment.dir]
|
||||||
|
|
||||||
|
if not meta then
|
||||||
|
meta = { name = fragment.name, _ = { frags = {} } }
|
||||||
|
local url, dir = fragment.url, fragment.dir
|
||||||
|
-- add to index
|
||||||
|
if url then
|
||||||
|
self.str_to_meta[url] = meta
|
||||||
|
end
|
||||||
|
if dir then
|
||||||
|
self.str_to_meta[dir] = meta
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(meta._.frags, fragment.id)
|
||||||
|
|
||||||
|
if plugin.name then
|
||||||
|
-- handle renames
|
||||||
|
if meta.name ~= plugin.name then
|
||||||
|
self.plugins[meta.name] = nil
|
||||||
|
meta.name = plugin.name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.plugins[meta.name] = meta
|
||||||
|
self.frag_to_meta[fragment.id] = meta
|
||||||
|
self.dirty[meta.name] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:rebuild()
|
||||||
|
for fid in pairs(self.fragments.dirty) do
|
||||||
|
local meta = self.frag_to_meta[fid]
|
||||||
|
if meta then
|
||||||
|
if self.fragments:get(fid) then
|
||||||
|
-- fragment still exists, so mark plugin as dirty
|
||||||
|
self.dirty[meta.name] = true
|
||||||
|
else
|
||||||
|
-- fragment was deleted, so remove it from plugin
|
||||||
|
---@param f number
|
||||||
|
meta._.frags = vim.tbl_filter(function(f)
|
||||||
|
return f ~= fid
|
||||||
|
end, meta._.frags)
|
||||||
|
-- if no fragments left, delete plugin
|
||||||
|
if #meta._.frags == 0 then
|
||||||
|
self:del(meta.name)
|
||||||
|
else
|
||||||
|
self.dirty[meta.name] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.fragments.dirty = {}
|
||||||
|
for n, _ in pairs(self.dirty) do
|
||||||
|
self:_rebuild(n)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param name string
|
||||||
|
function M:_rebuild(name)
|
||||||
|
local plugin = self.plugins[name]
|
||||||
|
if not plugin or #plugin._.frags == 0 then
|
||||||
|
self.plugins[name] = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
setmetatable(plugin, nil)
|
||||||
|
plugin.dependencies = {}
|
||||||
|
|
||||||
|
local super = nil
|
||||||
|
plugin.url = nil
|
||||||
|
plugin._.dep = true
|
||||||
|
plugin.optional = true
|
||||||
|
|
||||||
|
assert(#plugin._.frags > 0, "no fragments found for plugin " .. name)
|
||||||
|
|
||||||
|
for _, fid in ipairs(plugin._.frags) do
|
||||||
|
local fragment = self.fragments:get(fid)
|
||||||
|
assert(fragment, "fragment " .. fid .. " not found, for plugin " .. name)
|
||||||
|
---@diagnostic disable-next-line: no-unknown
|
||||||
|
super = setmetatable(fragment.spec, super and { __index = super } or nil)
|
||||||
|
plugin._.dep = plugin._.dep and fragment.dep
|
||||||
|
plugin.optional = plugin.optional and (rawget(fragment.spec, "optional") == true)
|
||||||
|
plugin.url = fragment.url or plugin.url
|
||||||
|
|
||||||
|
-- dependencies
|
||||||
|
for _, dep in ipairs(fragment.deps or {}) do
|
||||||
|
table.insert(plugin.dependencies, self.fragments:get(dep).name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
super = super or {}
|
||||||
|
|
||||||
|
-- dir / dev
|
||||||
|
plugin.dev = super.dev
|
||||||
|
plugin.dir = super.dir
|
||||||
|
if plugin.dir then
|
||||||
|
plugin.dir = Util.norm(plugin.dir)
|
||||||
|
else
|
||||||
|
if plugin.dev == nil and plugin.url then
|
||||||
|
for _, pattern in ipairs(Config.options.dev.patterns) do
|
||||||
|
if plugin.url:find(pattern, 1, true) then
|
||||||
|
plugin.dev = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if plugin.dev == true then
|
||||||
|
local dev_dir = type(Config.options.dev.path) == "string" and Config.options.dev.path .. "/" .. plugin.name
|
||||||
|
or Util.norm(Config.options.dev.path(plugin))
|
||||||
|
if not Config.options.dev.fallback or vim.fn.isdirectory(dev_dir) == 1 then
|
||||||
|
plugin.dir = dev_dir
|
||||||
|
else
|
||||||
|
plugin.dev = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
plugin.dir = plugin.dir or Config.options.root .. "/" .. plugin.name
|
||||||
|
end
|
||||||
|
|
||||||
|
if #plugin.dependencies == 0 and not super.dependencies then
|
||||||
|
plugin.dependencies = nil
|
||||||
|
end
|
||||||
|
if not plugin.optional and not super.optional then
|
||||||
|
plugin.optional = nil
|
||||||
|
end
|
||||||
|
setmetatable(plugin, { __index = super })
|
||||||
|
|
||||||
|
self.dirty[plugin.name] = nil
|
||||||
|
return plugin
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param plugin LazyPlugin
|
||||||
|
function M:disable(plugin)
|
||||||
|
plugin._.kind = "disabled"
|
||||||
|
self:del(plugin.name)
|
||||||
|
self.spec.disabled[plugin.name] = plugin
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:fix_cond()
|
||||||
|
for _, plugin in pairs(self.plugins) do
|
||||||
|
local cond = plugin.cond
|
||||||
|
if cond == nil then
|
||||||
|
cond = Config.options.defaults.cond
|
||||||
|
end
|
||||||
|
if cond == false or (type(cond) == "function" and not cond(plugin)) then
|
||||||
|
plugin._.cond = false
|
||||||
|
local stack = { plugin }
|
||||||
|
while #stack > 0 do
|
||||||
|
local p = table.remove(stack) --[[@as LazyPlugin]]
|
||||||
|
if not self.spec.ignore_installed[p.name] then
|
||||||
|
for _, dep in ipairs(p.dependencies or {}) do
|
||||||
|
table.insert(stack, self.plugins[dep])
|
||||||
|
end
|
||||||
|
self.spec.ignore_installed[p.name] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
plugin.enabled = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:fix_optional()
|
||||||
|
if self.spec.optional then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
local changes = 0
|
||||||
|
for _, plugin in pairs(self.plugins) do
|
||||||
|
if plugin.optional then
|
||||||
|
changes = changes + 1
|
||||||
|
self:del(plugin.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:rebuild()
|
||||||
|
return changes
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:fix_disabled()
|
||||||
|
local changes = 0
|
||||||
|
for _, plugin in pairs(self.plugins) do
|
||||||
|
if plugin.enabled == false or (type(plugin.enabled) == "function" and not plugin.enabled()) then
|
||||||
|
changes = changes + 1
|
||||||
|
self:disable(plugin)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:rebuild()
|
||||||
|
return changes
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:fix()
|
||||||
|
Util.track("resolve plugins")
|
||||||
|
self:rebuild()
|
||||||
|
|
||||||
|
self:fix_cond()
|
||||||
|
|
||||||
|
-- selene: allow(empty_loop)
|
||||||
|
while self:fix_disabled() + self:fix_optional() > 0 do
|
||||||
|
end
|
||||||
|
Util.track()
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
|
@ -1,4 +1,5 @@
|
||||||
local Config = require("lazy.core.config")
|
local Config = require("lazy.core.config")
|
||||||
|
local Meta = require("lazy.core.meta")
|
||||||
local Pkg = require("lazy.pkg")
|
local Pkg = require("lazy.pkg")
|
||||||
local Util = require("lazy.core.util")
|
local Util = require("lazy.core.util")
|
||||||
|
|
||||||
|
@ -7,46 +8,49 @@ local M = {}
|
||||||
M.loading = false
|
M.loading = false
|
||||||
|
|
||||||
---@class LazySpecLoader
|
---@class LazySpecLoader
|
||||||
|
---@field meta LazyMeta
|
||||||
---@field plugins table<string, LazyPlugin>
|
---@field plugins table<string, LazyPlugin>
|
||||||
---@field fragments table<number, LazyPlugin>
|
|
||||||
---@field disabled table<string, LazyPlugin>
|
---@field disabled table<string, LazyPlugin>
|
||||||
---@field dirty table<string, true>
|
|
||||||
---@field ignore_installed table<string, true>
|
---@field ignore_installed table<string, true>
|
||||||
---@field modules string[]
|
---@field modules string[]
|
||||||
---@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 pkgs table<string, boolean>
|
---@field pkgs table<string, boolean>
|
||||||
---@field names table<string,string>
|
|
||||||
local Spec = {}
|
local Spec = {}
|
||||||
M.Spec = Spec
|
M.Spec = Spec
|
||||||
M.last_fid = 0
|
|
||||||
M.fid_stack = {} ---@type number[]
|
|
||||||
M.LOCAL_SPEC = ".lazy.lua"
|
M.LOCAL_SPEC = ".lazy.lua"
|
||||||
|
|
||||||
---@param spec? LazySpec
|
---@param spec? LazySpec
|
||||||
---@param opts? {optional?:boolean}
|
---@param opts? {optional?:boolean}
|
||||||
function Spec.new(spec, opts)
|
function Spec.new(spec, opts)
|
||||||
local self = setmetatable({}, { __index = Spec })
|
local self = setmetatable({}, Spec)
|
||||||
self.plugins = {}
|
self.meta = Meta.new(self)
|
||||||
self.fragments = {}
|
|
||||||
self.disabled = {}
|
self.disabled = {}
|
||||||
self.modules = {}
|
self.modules = {}
|
||||||
self.dirty = {}
|
|
||||||
self.notifs = {}
|
self.notifs = {}
|
||||||
self.ignore_installed = {}
|
self.ignore_installed = {}
|
||||||
self.pkgs = {}
|
self.pkgs = {}
|
||||||
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
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Spec:__index(key)
|
||||||
|
if Spec[key] then
|
||||||
|
return Spec[key]
|
||||||
|
end
|
||||||
|
if key == "plugins" then
|
||||||
|
self.meta:rebuild()
|
||||||
|
return self.meta.plugins
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Spec:parse(spec)
|
function Spec:parse(spec)
|
||||||
self:normalize(spec)
|
self:normalize(spec)
|
||||||
self:fix_disabled()
|
self.meta:fix()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- PERF: optimized code to get package name without using lua patterns
|
-- PERF: optimized code to get package name without using lua patterns
|
||||||
|
@ -58,136 +62,22 @@ function Spec.get_name(pkg)
|
||||||
return slash and name:sub(#name - slash + 2) or pkg:gsub("%W+", "_")
|
return slash and name:sub(#name - slash + 2) or pkg:gsub("%W+", "_")
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param plugin LazyPlugin
|
---@param plugin LazyPluginSpec
|
||||||
---@param results? string[]
|
function Spec:add(plugin)
|
||||||
function Spec:add(plugin, results)
|
self.meta:add(plugin)
|
||||||
-- check if we already processed this spec. Can happen when a user uses the same instance of a spec in multiple specs
|
|
||||||
-- see https://github.com/folke/lazy.nvim/issues/45
|
|
||||||
if rawget(plugin, "_") then
|
|
||||||
if results then
|
|
||||||
table.insert(results, plugin.name)
|
|
||||||
end
|
|
||||||
return plugin
|
|
||||||
end
|
|
||||||
|
|
||||||
local is_ref = plugin[1] and not plugin[1]:find("/", 1, true)
|
---@diagnostic disable-next-line: cast-type-mismatch
|
||||||
|
---@cast plugin LazyPlugin
|
||||||
if not plugin.url and not is_ref and plugin[1] then
|
|
||||||
local prefix = plugin[1]:sub(1, 4)
|
|
||||||
if prefix == "http" or prefix == "git@" then
|
|
||||||
plugin.url = plugin[1]
|
|
||||||
else
|
|
||||||
plugin.url = Config.options.git.url_format:format(plugin[1])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
---@type string?
|
|
||||||
local dir
|
|
||||||
|
|
||||||
if plugin.dir then
|
|
||||||
dir = Util.norm(plugin.dir)
|
|
||||||
-- local plugin
|
|
||||||
plugin.name = plugin.name or Spec.get_name(plugin.dir)
|
|
||||||
elseif plugin.url then
|
|
||||||
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
|
|
||||||
if plugin.dev == nil then
|
|
||||||
for _, pattern in ipairs(Config.options.dev.patterns) do
|
|
||||||
if plugin.url:find(pattern, 1, true) then
|
|
||||||
plugin.dev = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif is_ref then
|
|
||||||
plugin.name = plugin[1]
|
|
||||||
else
|
|
||||||
self:error("Invalid plugin spec " .. vim.inspect(plugin))
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if not plugin.name or plugin.name == "" then
|
|
||||||
self:error("Plugin spec " .. vim.inspect(plugin) .. " has no name")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- dev plugins
|
|
||||||
if plugin.dev then
|
|
||||||
local dir_dev
|
|
||||||
if type(Config.options.dev.path) == "string" then
|
|
||||||
dir_dev = Config.options.dev.path .. "/" .. plugin.name
|
|
||||||
else
|
|
||||||
dir_dev = Util.norm(Config.options.dev.path(plugin))
|
|
||||||
end
|
|
||||||
if not Config.options.dev.fallback or vim.fn.isdirectory(dir_dev) == 1 then
|
|
||||||
dir = dir_dev
|
|
||||||
end
|
|
||||||
elseif plugin.dev == false then
|
|
||||||
-- explicitly select the default path
|
|
||||||
dir = Config.options.root .. "/" .. plugin.name
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(plugin.config) == "table" then
|
|
||||||
self:warn(
|
|
||||||
"{" .. plugin.name .. "}: setting a table to `Plugin.config` is deprecated. Please use `Plugin.opts` instead"
|
|
||||||
)
|
|
||||||
---@diagnostic disable-next-line: assign-type-mismatch
|
|
||||||
plugin.opts = plugin.config
|
|
||||||
plugin.config = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local fpid = M.fid_stack[#M.fid_stack]
|
|
||||||
|
|
||||||
M.last_fid = M.last_fid + 1
|
|
||||||
plugin._ = {
|
|
||||||
dir = dir,
|
|
||||||
fid = M.last_fid,
|
|
||||||
fpid = fpid,
|
|
||||||
dep = fpid ~= nil,
|
|
||||||
module = self.importing,
|
|
||||||
}
|
|
||||||
self.fragments[plugin._.fid] = plugin
|
|
||||||
-- remote plugin
|
|
||||||
plugin.dir = plugin._.dir or (plugin.name and (Config.options.root .. "/" .. plugin.name)) or nil
|
|
||||||
|
|
||||||
if fpid then
|
|
||||||
local parent = self.fragments[fpid]
|
|
||||||
parent._.fdeps = parent._.fdeps or {}
|
|
||||||
table.insert(parent._.fdeps, plugin._.fid)
|
|
||||||
end
|
|
||||||
|
|
||||||
if plugin.dependencies then
|
|
||||||
table.insert(M.fid_stack, plugin._.fid)
|
|
||||||
plugin.dependencies = self:normalize(plugin.dependencies, {})
|
|
||||||
table.remove(M.fid_stack)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- import the plugin's spec
|
-- import the plugin's spec
|
||||||
if Config.options.pkg.enabled and plugin.dir and not self.pkgs[plugin.dir] then
|
if Config.options.pkg.enabled and plugin.dir and not self.pkgs[plugin.dir] then
|
||||||
self.pkgs[plugin.dir] = true
|
self.pkgs[plugin.dir] = true
|
||||||
local pkg = Pkg.get_spec(plugin)
|
local pkg = Pkg.get_spec(plugin)
|
||||||
if pkg then
|
if pkg then
|
||||||
self:normalize(pkg, nil)
|
self:normalize(pkg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.plugins[plugin.name] then
|
|
||||||
plugin = self:merge(self.plugins[plugin.name], plugin)
|
|
||||||
end
|
|
||||||
self.plugins[plugin.name] = plugin
|
|
||||||
if results then
|
|
||||||
table.insert(results, plugin.name)
|
|
||||||
end
|
|
||||||
return plugin
|
return plugin
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -199,166 +89,6 @@ function Spec:warn(msg)
|
||||||
self:log(msg, vim.log.levels.WARN)
|
self:log(msg, vim.log.levels.WARN)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Rebuilds a plugin spec excluding any removed fragments
|
|
||||||
---@param name? string
|
|
||||||
function Spec:rebuild(name)
|
|
||||||
if not name then
|
|
||||||
for n, _ in pairs(self.dirty) do
|
|
||||||
self:rebuild(n)
|
|
||||||
end
|
|
||||||
self.dirty = {}
|
|
||||||
end
|
|
||||||
local plugin = self.plugins[name]
|
|
||||||
if not plugin then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local fragments = {} ---@type LazyPlugin[]
|
|
||||||
|
|
||||||
repeat
|
|
||||||
local super = plugin._.super
|
|
||||||
if self.fragments[plugin._.fid] then
|
|
||||||
plugin._.dep = plugin._.fpid ~= nil
|
|
||||||
plugin._.super = nil
|
|
||||||
if plugin._.fdeps then
|
|
||||||
plugin.dependencies = {}
|
|
||||||
for _, cid in ipairs(plugin._.fdeps) do
|
|
||||||
if self.fragments[cid] then
|
|
||||||
table.insert(plugin.dependencies, self.fragments[cid].name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
setmetatable(plugin, nil)
|
|
||||||
table.insert(fragments, 1, plugin)
|
|
||||||
end
|
|
||||||
plugin = super
|
|
||||||
until not plugin
|
|
||||||
|
|
||||||
if #fragments == 0 then
|
|
||||||
self.plugins[name] = nil
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
plugin = fragments[1]
|
|
||||||
for i = 2, #fragments do
|
|
||||||
plugin = self:merge(plugin, fragments[i])
|
|
||||||
end
|
|
||||||
self.plugins[name] = plugin
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Recursively removes all fragments from a plugin spec or a given fragment
|
|
||||||
---@param id string|number Plugin name or fragment id
|
|
||||||
---@param opts {self: boolean}
|
|
||||||
function Spec:remove_fragments(id, opts)
|
|
||||||
local fids = {} ---@type number[]
|
|
||||||
|
|
||||||
if type(id) == "number" then
|
|
||||||
fids[1] = id
|
|
||||||
else
|
|
||||||
local plugin = self.plugins[id]
|
|
||||||
repeat
|
|
||||||
if plugin._.fpid then
|
|
||||||
local parent = self.fragments[plugin._.fpid]
|
|
||||||
if parent then
|
|
||||||
parent._.fdeps = vim.tbl_filter(function(fid)
|
|
||||||
return fid ~= plugin._.fid
|
|
||||||
end, parent._.fdeps)
|
|
||||||
self.dirty[parent.name] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
fids[#fids + 1] = plugin._.fid
|
|
||||||
plugin = plugin._.super
|
|
||||||
until not plugin
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, fid in ipairs(fids) do
|
|
||||||
local fragment = self.fragments[fid]
|
|
||||||
if fragment then
|
|
||||||
for _, cid in ipairs(fragment._.fdeps or {}) do
|
|
||||||
self:remove_fragments(cid, { self = true })
|
|
||||||
end
|
|
||||||
if opts.self then
|
|
||||||
self.fragments[fid] = nil
|
|
||||||
end
|
|
||||||
self.dirty[fragment.name] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Spec:fix_cond()
|
|
||||||
for _, plugin in pairs(self.plugins) do
|
|
||||||
local cond = plugin.cond
|
|
||||||
if cond == nil then
|
|
||||||
cond = Config.options.defaults.cond
|
|
||||||
end
|
|
||||||
if cond == false or (type(cond) == "function" and not cond(plugin)) then
|
|
||||||
plugin._.cond = false
|
|
||||||
local stack = { plugin }
|
|
||||||
while #stack > 0 do
|
|
||||||
local p = table.remove(stack)
|
|
||||||
if not self.ignore_installed[p.name] then
|
|
||||||
for _, dep in ipairs(p.dependencies or {}) do
|
|
||||||
table.insert(stack, self.plugins[dep])
|
|
||||||
end
|
|
||||||
self.ignore_installed[p.name] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
plugin.enabled = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Spec:fix_optional()
|
|
||||||
if not self.optional then
|
|
||||||
---@param plugin LazyPlugin
|
|
||||||
local function all_optional(plugin)
|
|
||||||
return (not plugin) or (rawget(plugin, "optional") and all_optional(plugin._.super))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- handle optional plugins
|
|
||||||
for _, plugin in pairs(self.plugins) do
|
|
||||||
if plugin.optional and all_optional(plugin) then
|
|
||||||
-- remove all optional fragments
|
|
||||||
self:remove_fragments(plugin.name, { self = true })
|
|
||||||
self.plugins[plugin.name] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Spec:fix_disabled()
|
|
||||||
for _, plugin in pairs(self.plugins) do
|
|
||||||
if not plugin.name or not plugin.dir then
|
|
||||||
self:error("Plugin spec for **" .. plugin.name .. "** not found.\n```lua\n" .. vim.inspect(plugin) .. "\n```")
|
|
||||||
self.plugins[plugin.name] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self:fix_optional()
|
|
||||||
self:rebuild()
|
|
||||||
|
|
||||||
self:fix_cond()
|
|
||||||
self:rebuild()
|
|
||||||
|
|
||||||
self.dirty = {}
|
|
||||||
|
|
||||||
for _, plugin in pairs(self.plugins) do
|
|
||||||
local disabled = plugin.enabled == false or (type(plugin.enabled) == "function" and not plugin.enabled())
|
|
||||||
if disabled then
|
|
||||||
plugin._.kind = "disabled"
|
|
||||||
-- remove all child fragments
|
|
||||||
self:remove_fragments(plugin.name, { self = false })
|
|
||||||
self.plugins[plugin.name] = nil
|
|
||||||
self.disabled[plugin.name] = plugin
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self:rebuild()
|
|
||||||
|
|
||||||
-- check optional plugins again
|
|
||||||
self:fix_optional()
|
|
||||||
self:rebuild()
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param msg string
|
---@param msg string
|
||||||
---@param level number
|
---@param level number
|
||||||
function Spec:log(msg, level)
|
function Spec:log(msg, level)
|
||||||
|
@ -378,25 +108,17 @@ function Spec:report(level)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param spec LazySpec|LazySpecImport
|
---@param spec LazySpec|LazySpecImport
|
||||||
---@param results? string[]
|
function Spec:normalize(spec)
|
||||||
function Spec:normalize(spec, results)
|
|
||||||
if type(spec) == "string" then
|
if type(spec) == "string" then
|
||||||
if not spec:find("/", 1, true) then
|
self:add({ spec })
|
||||||
-- spec is a plugin name
|
|
||||||
if results then
|
|
||||||
table.insert(results, spec)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self:add({ spec }, results)
|
|
||||||
end
|
|
||||||
elseif #spec > 1 or Util.is_list(spec) then
|
elseif #spec > 1 or Util.is_list(spec) then
|
||||||
---@cast spec LazySpec[]
|
---@cast spec LazySpec[]
|
||||||
for _, s in ipairs(spec) do
|
for _, s in ipairs(spec) do
|
||||||
self:normalize(s, results)
|
self:normalize(s)
|
||||||
end
|
end
|
||||||
elseif spec[1] or spec.dir or spec.url then
|
elseif spec[1] or spec.dir or spec.url then
|
||||||
---@cast spec LazyPlugin
|
---@cast spec LazyPluginSpec
|
||||||
local plugin = self:add(spec, results)
|
local plugin = self:add(spec)
|
||||||
---@diagnostic disable-next-line: cast-type-mismatch
|
---@diagnostic disable-next-line: cast-type-mismatch
|
||||||
---@cast plugin LazySpecImport
|
---@cast plugin LazySpecImport
|
||||||
if plugin and plugin.import then
|
if plugin and plugin.import then
|
||||||
|
@ -408,7 +130,6 @@ function Spec:normalize(spec, results)
|
||||||
else
|
else
|
||||||
self:error("Invalid plugin spec " .. vim.inspect(spec))
|
self:error("Invalid plugin spec " .. vim.inspect(spec))
|
||||||
end
|
end
|
||||||
return results
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param spec LazySpecImport
|
---@param spec LazySpecImport
|
||||||
|
@ -492,41 +213,6 @@ function Spec:import(spec)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param old LazyPlugin
|
|
||||||
---@param new LazyPlugin
|
|
||||||
---@return LazyPlugin
|
|
||||||
function Spec:merge(old, new)
|
|
||||||
new._.dep = old._.dep and new._.dep
|
|
||||||
|
|
||||||
if new.url and old.url and new.url ~= old.url then
|
|
||||||
self:warn("Two plugins with the same name and different url:\n" .. vim.inspect({ old = old, new = new }))
|
|
||||||
end
|
|
||||||
|
|
||||||
if new.dependencies and old.dependencies then
|
|
||||||
Util.extend(new.dependencies, old.dependencies)
|
|
||||||
end
|
|
||||||
|
|
||||||
local new_dir = new._.dir or old._.dir or (new.name and (Config.options.root .. "/" .. new.name)) or nil
|
|
||||||
if new_dir ~= old.dir then
|
|
||||||
local msg = "Plugin `" .. new.name .. "` changed `dir`:\n- from: `" .. old.dir .. "`\n- to: `" .. new_dir .. "`"
|
|
||||||
if new._.rtp_loaded or old._.rtp_loaded then
|
|
||||||
msg = msg
|
|
||||||
.. "\n\nThis plugin was already partially loaded, so we did not change it's `dir`.\nPlease fix your config."
|
|
||||||
self:error(msg)
|
|
||||||
new_dir = old.dir
|
|
||||||
else
|
|
||||||
self:warn(msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
new.dir = new_dir
|
|
||||||
new._.rtp_loaded = new._.rtp_loaded or old._.rtp_loaded
|
|
||||||
|
|
||||||
new._.super = old
|
|
||||||
setmetatable(new, { __index = old })
|
|
||||||
|
|
||||||
return new
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.update_state()
|
function M.update_state()
|
||||||
---@type string[]
|
---@type string[]
|
||||||
local cloning = {}
|
local cloning = {}
|
||||||
|
@ -631,6 +317,7 @@ function M.load()
|
||||||
Config.spec = Spec.new()
|
Config.spec = Spec.new()
|
||||||
|
|
||||||
local specs = {
|
local specs = {
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
vim.deepcopy(Config.options.spec),
|
vim.deepcopy(Config.options.spec),
|
||||||
}
|
}
|
||||||
specs[#specs + 1] = M.find_local_spec()
|
specs[#specs + 1] = M.find_local_spec()
|
||||||
|
@ -655,10 +342,10 @@ function M.load()
|
||||||
for name, plugin in pairs(existing) do
|
for name, plugin in pairs(existing) do
|
||||||
if Config.plugins[name] then
|
if Config.plugins[name] then
|
||||||
local dep = Config.plugins[name]._.dep
|
local dep = Config.plugins[name]._.dep
|
||||||
local super = Config.plugins[name]._.super
|
local frags = Config.plugins[name]._.frags
|
||||||
Config.plugins[name]._ = plugin._
|
Config.plugins[name]._ = plugin._
|
||||||
Config.plugins[name]._.dep = dep
|
Config.plugins[name]._.dep = dep
|
||||||
Config.plugins[name]._.super = super
|
Config.plugins[name]._.frags = frags
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Util.track()
|
Util.track()
|
||||||
|
@ -725,8 +412,9 @@ function M._values(root, plugin, prop, is_list)
|
||||||
if not plugin[prop] then
|
if not plugin[prop] then
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
|
local super = getmetatable(plugin)
|
||||||
---@type table
|
---@type table
|
||||||
local ret = plugin._.super and M._values(root, plugin._.super, prop, is_list) or {}
|
local ret = super and M._values(root, super.__index, prop, is_list) or {}
|
||||||
local values = rawget(plugin, prop)
|
local values = rawget(plugin, prop)
|
||||||
|
|
||||||
if not values then
|
if not values then
|
||||||
|
@ -742,6 +430,7 @@ function M._values(root, plugin, prop, is_list)
|
||||||
else
|
else
|
||||||
---@type {path:string[], list:any[]}[]
|
---@type {path:string[], list:any[]}[]
|
||||||
local lists = {}
|
local lists = {}
|
||||||
|
---@diagnostic disable-next-line: no-unknown
|
||||||
for _, key in ipairs(plugin[prop .. "_extend"] or {}) do
|
for _, key in ipairs(plugin[prop .. "_extend"] or {}) do
|
||||||
local path = vim.split(key, ".", { plain = true })
|
local path = vim.split(key, ".", { plain = true })
|
||||||
local r = Util.key_get(ret, path)
|
local r = Util.key_get(ret, path)
|
||||||
|
|
|
@ -93,7 +93,7 @@ function M.pretty_trace(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@generic R
|
---@generic R
|
||||||
---@param fn fun():R
|
---@param fn fun():R?
|
||||||
---@param opts? string|{msg:string, on_error:fun(msg)}
|
---@param opts? string|{msg:string, on_error:fun(msg)}
|
||||||
---@return R
|
---@return R
|
||||||
function M.try(fn, opts)
|
function M.try(fn, opts)
|
||||||
|
|
|
@ -59,7 +59,6 @@ function M.check()
|
||||||
else
|
else
|
||||||
for _, plugin in pairs(spec.plugins) do
|
for _, plugin in pairs(spec.plugins) do
|
||||||
M.check_valid(plugin)
|
M.check_valid(plugin)
|
||||||
M.check_override(plugin)
|
|
||||||
end
|
end
|
||||||
if #spec.notifs > 0 then
|
if #spec.notifs > 0 then
|
||||||
error("Issues were reported when loading your specs:")
|
error("Issues were reported when loading your specs:")
|
||||||
|
@ -88,23 +87,6 @@ function M.check_valid(plugin)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param plugin LazyPlugin
|
|
||||||
function M.check_override(plugin)
|
|
||||||
if not plugin._.super then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local Handler = require("lazy.core.handler")
|
|
||||||
local skip = { "dependencies", "_", "opts", 1 }
|
|
||||||
vim.list_extend(skip, vim.tbl_values(Handler.types))
|
|
||||||
|
|
||||||
for key, value in pairs(plugin._.super) do
|
|
||||||
if not vim.tbl_contains(skip, key) and plugin[key] and plugin[key] ~= value then
|
|
||||||
warn("{" .. plugin.name .. "}: overriding <" .. key .. ">")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
M.valid = {
|
M.valid = {
|
||||||
1,
|
1,
|
||||||
"_",
|
"_",
|
||||||
|
|
|
@ -2,30 +2,26 @@
|
||||||
---@alias LazyPluginKind "normal"|"clean"|"disabled"
|
---@alias LazyPluginKind "normal"|"clean"|"disabled"
|
||||||
|
|
||||||
---@class LazyPluginState
|
---@class LazyPluginState
|
||||||
---@field fid number id of the plugin spec fragment
|
|
||||||
---@field fpid? number parent id of the plugin spec fragment
|
|
||||||
---@field fdeps? number[] children ids of the fragment
|
|
||||||
---@field loaded? {[string]:string}|{time:number}
|
|
||||||
---@field installed? boolean
|
|
||||||
---@field tasks? LazyTask[]
|
|
||||||
---@field working? boolean
|
|
||||||
---@field dirty? boolean
|
|
||||||
---@field updated? {from:string, to:string}
|
|
||||||
---@field is_local? boolean
|
|
||||||
---@field updates? {from:GitInfo, to:GitInfo}
|
|
||||||
---@field cloned? boolean
|
|
||||||
---@field outdated? boolean
|
|
||||||
---@field kind? LazyPluginKind
|
|
||||||
---@field dep? boolean True if this plugin is only in the spec as a dependency
|
|
||||||
---@field cond? boolean
|
|
||||||
---@field super? LazyPlugin
|
|
||||||
---@field module? string
|
|
||||||
---@field dir? string Explicit dir or dev set for this plugin
|
|
||||||
---@field rtp_loaded? boolean
|
|
||||||
---@field handlers? LazyPluginHandlers
|
|
||||||
---@field cache? table<string,any>
|
---@field cache? table<string,any>
|
||||||
|
---@field cloned? boolean
|
||||||
|
---@field cond? boolean
|
||||||
|
---@field dep? boolean True if this plugin is only in the spec as a dependency
|
||||||
|
---@field dir? string Explicit dir or dev set for this plugin
|
||||||
|
---@field dirty? boolean
|
||||||
|
---@field frags? number[]
|
||||||
|
---@field handlers? LazyPluginHandlers
|
||||||
|
---@field installed? boolean
|
||||||
|
---@field is_local? boolean
|
||||||
|
---@field kind? LazyPluginKind
|
||||||
|
---@field loaded? {[string]:string}|{time:number}
|
||||||
|
---@field outdated? boolean
|
||||||
---@field rocks? LazyRock[]
|
---@field rocks? LazyRock[]
|
||||||
---@field rocks_installed? boolean
|
---@field rocks_installed? boolean
|
||||||
|
---@field rtp_loaded? boolean
|
||||||
|
---@field tasks? LazyTask[]
|
||||||
|
---@field updated? {from:string, to:string}
|
||||||
|
---@field updates? {from:GitInfo, to:GitInfo}
|
||||||
|
---@field working? boolean
|
||||||
|
|
||||||
---@alias PluginOpts table|fun(self:LazyPlugin, opts:table):table?
|
---@alias PluginOpts table|fun(self:LazyPlugin, opts:table):table?
|
||||||
|
|
||||||
|
@ -66,6 +62,7 @@
|
||||||
|
|
||||||
---@class LazyPlugin: LazyPluginBase,LazyPluginHandlers,LazyPluginHooks,LazyPluginRef
|
---@class LazyPlugin: LazyPluginBase,LazyPluginHandlers,LazyPluginHooks,LazyPluginRef
|
||||||
---@field dependencies? string[]
|
---@field dependencies? string[]
|
||||||
|
---@field specs? string|string[]|LazyPluginSpec[]
|
||||||
---@field _ LazyPluginState
|
---@field _ LazyPluginState
|
||||||
|
|
||||||
---@class LazyPluginSpecHandlers
|
---@class LazyPluginSpecHandlers
|
||||||
|
@ -77,6 +74,7 @@
|
||||||
|
|
||||||
---@class LazyPluginSpec: LazyPluginBase,LazyPluginSpecHandlers,LazyPluginHooks,LazyPluginRef
|
---@class LazyPluginSpec: LazyPluginBase,LazyPluginSpecHandlers,LazyPluginHooks,LazyPluginRef
|
||||||
---@field dependencies? string|string[]|LazyPluginSpec[]
|
---@field dependencies? string|string[]|LazyPluginSpec[]
|
||||||
|
---@field specs? string|string[]|LazyPluginSpec[]
|
||||||
|
|
||||||
---@alias LazySpec string|LazyPluginSpec|LazySpecImport|LazySpec[]
|
---@alias LazySpec string|LazyPluginSpec|LazySpecImport|LazySpec[]
|
||||||
|
|
||||||
|
@ -85,3 +83,14 @@
|
||||||
---@field name? string
|
---@field name? string
|
||||||
---@field enabled? boolean|(fun():boolean)
|
---@field enabled? boolean|(fun():boolean)
|
||||||
---@field cond? boolean|(fun():boolean)
|
---@field cond? boolean|(fun():boolean)
|
||||||
|
|
||||||
|
---@class LazyFragment
|
||||||
|
---@field id number
|
||||||
|
---@field pid? number
|
||||||
|
---@field deps? number[]
|
||||||
|
---@field frags? number[]
|
||||||
|
---@field dep? boolean
|
||||||
|
---@field name string
|
||||||
|
---@field url? string
|
||||||
|
---@field dir? string
|
||||||
|
---@field spec LazyPlugin
|
||||||
|
|
|
@ -6,6 +6,10 @@ local assert = require("luassert")
|
||||||
|
|
||||||
Config.setup()
|
Config.setup()
|
||||||
|
|
||||||
|
local function inspect(obj)
|
||||||
|
return vim.inspect(obj):gsub("%s+", " ")
|
||||||
|
end
|
||||||
|
|
||||||
---@param plugins LazyPlugin[]|LazyPlugin
|
---@param plugins LazyPlugin[]|LazyPlugin
|
||||||
local function clean(plugins)
|
local function clean(plugins)
|
||||||
local p = plugins
|
local p = plugins
|
||||||
|
@ -14,6 +18,7 @@ local function clean(plugins)
|
||||||
plugin._.fid = nil
|
plugin._.fid = nil
|
||||||
plugin._.fpid = nil
|
plugin._.fpid = nil
|
||||||
plugin._.fdeps = nil
|
plugin._.fdeps = nil
|
||||||
|
plugin._.frags = nil
|
||||||
if plugin._.dep == false then
|
if plugin._.dep == false then
|
||||||
plugin._.dep = nil
|
plugin._.dep = nil
|
||||||
end
|
end
|
||||||
|
@ -28,7 +33,7 @@ describe("plugin spec url/name", function()
|
||||||
{ { "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" } },
|
||||||
{ { "https://foo.bar" }, { [1] = "https://foo.bar", name = "foo.bar", url = "https://foo.bar" } },
|
{ { "https://foo.bar" }, { [1] = "https://foo.bar", name = "foo.bar", url = "https://foo.bar" } },
|
||||||
{ { "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 = "bar", 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" } },
|
{ { url = "https://foo", name = "foobar" }, { url = "https://foo" } },
|
||||||
|
@ -45,18 +50,22 @@ describe("plugin spec url/name", function()
|
||||||
|
|
||||||
for _, test in ipairs(tests) do
|
for _, test in ipairs(tests) do
|
||||||
test[2]._ = {}
|
test[2]._ = {}
|
||||||
it("parses " .. vim.inspect(test[1]):gsub("%s+", " "), function()
|
it("parses " .. inspect(test[1]), function()
|
||||||
if not test[2].dir then
|
if not test[2].dir then
|
||||||
test[2].dir = Config.options.root .. "/" .. test[2].name
|
test[2].dir = Config.options.root .. "/" .. test[2].name
|
||||||
end
|
end
|
||||||
local spec = Plugin.Spec.new(test[1])
|
local spec = Plugin.Spec.new(test[1])
|
||||||
local plugins = vim.tbl_values(spec.plugins)
|
local all = vim.deepcopy(spec.plugins)
|
||||||
plugins[1]._ = {}
|
local plugins = vim.tbl_values(all)
|
||||||
|
plugins = vim.tbl_map(function(plugin)
|
||||||
|
plugin._ = {}
|
||||||
|
return plugin
|
||||||
|
end, plugins)
|
||||||
local notifs = vim.tbl_filter(function(notif)
|
local notifs = vim.tbl_filter(function(notif)
|
||||||
return notif.level > 3
|
return notif.level > 3
|
||||||
end, spec.notifs)
|
end, spec.notifs)
|
||||||
assert(#notifs == 0, vim.inspect(spec.notifs))
|
assert(#notifs == 0, vim.inspect(spec.notifs))
|
||||||
assert.equal(1, #plugins)
|
assert.equal(1, #plugins, vim.inspect(all))
|
||||||
plugins[1]._.super = nil
|
plugins[1]._.super = nil
|
||||||
assert.same(test[2], plugins[1])
|
assert.same(test[2], plugins[1])
|
||||||
end)
|
end)
|
||||||
|
@ -90,7 +99,40 @@ describe("plugin spec dir", function()
|
||||||
for _, test in ipairs(tests) do
|
for _, test in ipairs(tests) do
|
||||||
local dir = vim.fn.expand(test[1])
|
local dir = vim.fn.expand(test[1])
|
||||||
local input = vim.list_slice(test, 2)
|
local input = vim.list_slice(test, 2)
|
||||||
it("parses dir " .. vim.inspect(input):gsub("%s+", " "), function()
|
it("parses dir " .. inspect(input), function()
|
||||||
|
local spec = Plugin.Spec.new(input)
|
||||||
|
local plugins = vim.tbl_values(spec.plugins)
|
||||||
|
assert(spec:report() == 0)
|
||||||
|
assert.equal(1, #plugins)
|
||||||
|
assert.same(dir, plugins[1].dir)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("plugin dev", function()
|
||||||
|
local tests = {
|
||||||
|
{
|
||||||
|
{ "lewis6991/gitsigns.nvim", opts = {}, dev = true },
|
||||||
|
{ "lewis6991/gitsigns.nvim" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ "lewis6991/gitsigns.nvim", opts = {}, dev = true },
|
||||||
|
{ "gitsigns.nvim" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ "lewis6991/gitsigns.nvim", opts = {} },
|
||||||
|
{ "lewis6991/gitsigns.nvim", dev = true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ "lewis6991/gitsigns.nvim", opts = {} },
|
||||||
|
{ "gitsigns.nvim", dev = true },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test in ipairs(tests) do
|
||||||
|
local dir = vim.fn.expand("~/projects/gitsigns.nvim")
|
||||||
|
local input = test
|
||||||
|
it("parses dir " .. inspect(input), function()
|
||||||
local spec = Plugin.Spec.new(input)
|
local spec = Plugin.Spec.new(input)
|
||||||
local plugins = vim.tbl_values(spec.plugins)
|
local plugins = vim.tbl_values(spec.plugins)
|
||||||
assert(spec:report() == 0)
|
assert(spec:report() == 0)
|
||||||
|
@ -126,7 +168,7 @@ describe("plugin spec opt", function()
|
||||||
for _, plugin in pairs(spec.plugins) do
|
for _, plugin in pairs(spec.plugins) do
|
||||||
plugin.dir = nil
|
plugin.dir = nil
|
||||||
end
|
end
|
||||||
assert.same(clean(spec.plugins), {
|
assert.same({
|
||||||
bar = {
|
bar = {
|
||||||
"foo/bar",
|
"foo/bar",
|
||||||
_ = {},
|
_ = {},
|
||||||
|
@ -150,7 +192,7 @@ describe("plugin spec opt", function()
|
||||||
name = "dep2",
|
name = "dep2",
|
||||||
url = "https://github.com/foo/dep2.git",
|
url = "https://github.com/foo/dep2.git",
|
||||||
},
|
},
|
||||||
})
|
}, clean(spec.plugins))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -369,45 +411,45 @@ describe("plugin spec opt", function()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("plugin opts", function()
|
describe("plugin opts", function()
|
||||||
it("correctly parses opts", function()
|
---@type {spec:LazySpec, opts:table}[]
|
||||||
---@type {spec:LazySpec, opts:table}[]
|
local tests = {
|
||||||
local tests = {
|
{
|
||||||
{
|
spec = { { "foo/foo", opts = { a = 1, b = 1 } }, { "foo/foo", opts = { a = 2 } } },
|
||||||
spec = { { "foo/foo", opts = { a = 1, b = 1 } }, { "foo/foo", opts = { a = 2 } } },
|
opts = { a = 2, b = 1 },
|
||||||
opts = { a = 2, b = 1 },
|
},
|
||||||
},
|
{
|
||||||
{
|
spec = { { "foo/foo", config = { a = 1, b = 1 } }, { "foo/foo", opts = { a = 2 } } },
|
||||||
spec = { { "foo/foo", config = { a = 1, b = 1 } }, { "foo/foo", opts = { a = 2 } } },
|
opts = { a = 2, b = 1 },
|
||||||
opts = { a = 2, b = 1 },
|
},
|
||||||
},
|
{
|
||||||
{
|
spec = { { "foo/foo", opts = { a = 1, b = 1 } }, { "foo/foo", config = { a = 2 } } },
|
||||||
spec = { { "foo/foo", opts = { a = 1, b = 1 } }, { "foo/foo", config = { a = 2 } } },
|
opts = { a = 2, b = 1 },
|
||||||
opts = { a = 2, b = 1 },
|
},
|
||||||
},
|
{
|
||||||
{
|
spec = { { "foo/foo", config = { a = 1, b = 1 } }, { "foo/foo", config = { a = 2 } } },
|
||||||
spec = { { "foo/foo", config = { a = 1, b = 1 } }, { "foo/foo", config = { a = 2 } } },
|
opts = { a = 2, b = 1 },
|
||||||
opts = { a = 2, b = 1 },
|
},
|
||||||
},
|
{
|
||||||
{
|
spec = { { "foo/foo", config = { a = 1, b = 1 } }, { "foo/foo", config = { a = vim.NIL } } },
|
||||||
spec = { { "foo/foo", config = { a = 1, b = 1 } }, { "foo/foo", config = { a = vim.NIL } } },
|
opts = { b = 1 },
|
||||||
opts = { b = 1 },
|
},
|
||||||
},
|
{
|
||||||
{
|
spec = { { "foo/foo", config = { a = 1, b = 1 } }, { "foo/foo" } },
|
||||||
spec = { { "foo/foo", config = { a = 1, b = 1 } }, { "foo/foo" } },
|
opts = { a = 1, b = 1 },
|
||||||
opts = { a = 1, b = 1 },
|
},
|
||||||
},
|
{
|
||||||
{
|
spec = { { "foo/foo" }, { "foo/foo" } },
|
||||||
spec = { { "foo/foo" }, { "foo/foo" } },
|
opts = {},
|
||||||
opts = {},
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for _, test in ipairs(tests) do
|
for _, test in ipairs(tests) do
|
||||||
|
it("correctly parses opts for " .. inspect(test.spec), function()
|
||||||
local spec = Plugin.Spec.new(test.spec)
|
local spec = Plugin.Spec.new(test.spec)
|
||||||
assert(spec.plugins.foo)
|
assert(spec.plugins.foo)
|
||||||
assert.same(test.opts, Plugin.values(spec.plugins.foo, "opts"))
|
assert.same(test.opts, Plugin.values(spec.plugins.foo, "opts"))
|
||||||
end
|
end)
|
||||||
end)
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("plugin spec", function()
|
describe("plugin spec", function()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
---@module 'luassert'
|
||||||
local Keys = require("lazy.core.handler.keys")
|
local Keys = require("lazy.core.handler.keys")
|
||||||
|
|
||||||
describe("keys", function()
|
describe("keys", function()
|
||||||
|
|
Loading…
Reference in New Issue