mirror of https://github.com/folke/lazy.nvim.git
175 lines
4.2 KiB
Lua
175 lines
4.2 KiB
Lua
local Config = require("lazy.core.config")
|
|
local Util = require("lazy.core.util")
|
|
|
|
--- This class is used to manage the fragments of a plugin spec.
|
|
--- It keeps track of the fragments and their relations to other fragments.
|
|
--- A fragment can be a dependency (dependencies) or a child (specs) of another fragment.
|
|
---@class LazyFragments
|
|
---@field fragments table<number, LazyFragment>
|
|
---@field frag_stack number[]
|
|
---@field dep_stack number[]
|
|
---@field dirty table<number, boolean>
|
|
---@field plugins table<LazyPlugin, number>
|
|
---@field spec LazySpecLoader
|
|
local M = {}
|
|
|
|
M._fid = 0
|
|
|
|
local function next_id()
|
|
M._fid = M._fid + 1
|
|
return M._fid
|
|
end
|
|
|
|
---@param spec LazySpecLoader
|
|
---@return LazyFragments
|
|
function M.new(spec)
|
|
local self = setmetatable({}, { __index = M })
|
|
self.fragments = {}
|
|
self.frag_stack = {}
|
|
self.dep_stack = {}
|
|
self.spec = spec
|
|
self.dirty = {}
|
|
self.plugins = {}
|
|
return self
|
|
end
|
|
|
|
---@param id number
|
|
function M:get(id)
|
|
return self.fragments[id]
|
|
end
|
|
|
|
--- Remove a fragment and all its children.
|
|
--- This will also remove the fragment from its parent's children list.
|
|
---@param id number
|
|
function M: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 = Util.filter(function(fid)
|
|
return fid ~= id
|
|
end, parent.frags)
|
|
end
|
|
if parent.deps then
|
|
---@param fid number
|
|
parent.deps = Util.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
|
|
|
|
--- Add a fragment to the fragments list.
|
|
--- This also resolves its name, url, dir, dependencies and child specs.
|
|
---@param plugin LazyPluginSpec
|
|
function M:add(plugin)
|
|
if self.plugins[plugin] then
|
|
return self.fragments[self.plugins[plugin]]
|
|
end
|
|
|
|
local id = next_id()
|
|
setmetatable(plugin, nil)
|
|
|
|
self.plugins[plugin] = 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
|