From 6bd6db3c02210c714de6fab8189d26997ac25f2c Mon Sep 17 00:00:00 2001 From: Squibid Date: Tue, 24 Jun 2025 01:48:30 -0400 Subject: [PATCH] refine module support and package loading --- lua/dep.lua | 118 ++++++------------------------------- lua/dep/bench.lua | 35 +++++++++++ lua/dep/modules/init.lua | 39 ++++++++++++ lua/dep/modules/module.lua | 55 +++++++++++++++++ lua/dep/package.lua | 48 +++++++++++++++ lua/dep/spec.lua | 6 +- 6 files changed, 200 insertions(+), 101 deletions(-) create mode 100644 lua/dep/bench.lua create mode 100644 lua/dep/modules/init.lua create mode 100644 lua/dep/modules/module.lua diff --git a/lua/dep.lua b/lua/dep.lua index ad0907a..b28cd5c 100644 --- a/lua/dep.lua +++ b/lua/dep.lua @@ -3,107 +3,16 @@ local git = require('dep.git') local fs = require('dep.fs') local packager = require('dep.package') local h = require('dep.helpers') -local spec_man = require("dep.spec") +local modules = require("dep.modules") +local bench = require("dep.bench") -- all functions for convenience local M = {} --- TODO: actually use this (ideally make a view that shows startuptime and --- which plugins are currently loaded) --- performance logging -local perf = {} - -- TODO: maybe add the ability to get a lockfile? it's useful to make a config -- rebuildable, but idk if it's actually useful for a neovim config -- (look into how ofter people who use lazy.nvim us it) ---- get execution time of a function ----@param name string name of performance output ----@param code function function to run ----@vararg any arguments for code -function M.benchmark(name, code, ...) - local start = os.clock() - code(...) - perf[name] = os.clock() - start -end - ---- recurse over all packages and register them ----@param speclist speclist table of specs ----@param overrides spec? a package spec that is used to override options -function M.registertree(speclist, overrides) - overrides = overrides or {} - - -- recurse the packages - local over = overrides - for _, spec in ipairs(speclist) do - -- make sure the overrides override and take into account the packages spec - ---@diagnostic disable-next-line: missing-fields - over = { - pin = overrides.pin or spec.pin, - disable = overrides.disable or spec.disable - } - - -- While a package can fail to load we just don't care, it will work itself - -- out. The goal is to make sure every plugin that can load does load, not - -- keep working plugins from loading because an unrelated one doesn't load. - packager:new(spec, over) - end - - if speclist.modules then - for _, module in ipairs(speclist.modules) do - local name = "" - - if type(module) == "string" then - if speclist.modules.prefix then - if speclist.modules.prefix:sub(#speclist.modules.prefix) ~= "." and - module:sub(1, 2) ~= "." then - module = "."..module - end - module = speclist.modules.prefix..module - end - - name, module = module, require(module) - end - name = module.name or name - - -- allow a module to be a spec - if spec_man.check(module, true) ~= false then - ---@diagnostic disable-next-line: cast-local-type - module = { module } - end - - local ok, err = pcall(M.registertree, module, overrides) - if not ok then - error(string.format("%s <- %s", err, name)) - end - end - end -end - ---- reload all packages in package table spec ----@param force boolean? force all packages to load -function M.reload(force) - local reloaded = packager.get_root():loadtree(force) - - if reloaded then - local ok, err - M.benchmark("reload", function() - ok, err = pcall(vim.cmd, - [[ - silent! helptags ALL - silent! UpdateRemotePlugins - ]]) - end) - - if ok then - logger:log("vim", "reloaded helptags and remote plugins") - else - logger:log("error", - "failed to reload helptags and remote plugins; reason: %s", err) - end - end -end - --- sync a tree of plugins ---@param tree package[] tree of plugins ---@param cb function? callback @@ -123,7 +32,9 @@ function M.synctree(tree, cb) end fs:clean(packager) - M.reload() + for _, package in pairs(tree) do + package:reload() + end if cb then cb() @@ -148,6 +59,7 @@ end -- basically the main function of our program return function(opts) logger.pipe = logger:setup() + bench:setup() --- make comparison for table.sort ---@param a package package spec a @@ -162,7 +74,7 @@ return function(opts) local initialized, err = pcall(function() packager.set_base_dir(opts.base_dir or vim.fn.stdpath("data").."/site/pack/deps/opt/") - M.benchmark("load", function() + bench.mark("load", function() -- register all packages local root = packager:new({ "squibid/dep", @@ -174,7 +86,12 @@ return function(opts) logger:log("error", "couldn't register root package") return end - M.registertree(opts) + + -- setup all packages and modules + if opts.modules then + modules:setup(opts) + end + packager.register_speclist(opts) -- sort package dependencies for _, package in pairs(packager.get_packages()) do @@ -190,7 +107,9 @@ return function(opts) end) -- load packages - M.reload(false) + for _, package in pairs(packager.get_packages()) do + package:reload() + end --- check if a package should be synced ---@param package table package table spec @@ -244,13 +163,14 @@ return function(opts) end, {}) vim.api.nvim_create_user_command("DepReload", function() - M.reload() + for _, package in pairs(packager.get_packages()) do + package:reload() + end end, {}) vim.api.nvim_create_user_command("DepClean", function() -- clean AND reload to make sure that all old packages are gone fs:clean(packager) - M.reload() end, {}) logger:cleanup() diff --git a/lua/dep/bench.lua b/lua/dep/bench.lua new file mode 100644 index 0000000..86d3aff --- /dev/null +++ b/lua/dep/bench.lua @@ -0,0 +1,35 @@ +-- TODO: actually use this (ideally make a view that shows startuptime and +-- which plugins are currently loaded) +-- performance logging + +---@class bench +---@field perf number[] list of all perfs +local bench = {} +local b + +function bench:setup() + local o = {} + self = {} + self.__index = self + setmetatable(o, self) + + o.perf = {} + o.inited = true + + b = o +end + +--- benchmark a peice of code +---@param name string the name of the benchmark +---@param f function the code to benchmark +---@vararg any args for f +---@return any ret the result of f +function bench.mark(name, f, ...) + local start = os.clock() + local ret = f(...) + b.perf[name] = os.clock() - start + + return ret +end + +return bench diff --git a/lua/dep/modules/init.lua b/lua/dep/modules/init.lua new file mode 100644 index 0000000..d212eb6 --- /dev/null +++ b/lua/dep/modules/init.lua @@ -0,0 +1,39 @@ +local module = require("dep.modules.module") + +---@class modules +---@field modules module[] all modules in dep +local modules = {} + +--- Initialize all the modules +---@param self table? +---@param speclist table +---@param overrides spec? overrides +---@return modules modules manager +---@nodisacard +function modules:setup(speclist, overrides) + overrides = overrides or {} + + local o = {} + self = {} + self.__index = self + setmetatable(o, self) + + -- create a list of modules + o.modules = {} + + -- loop through all modules and initialize them + for _, modpath in ipairs(speclist.modules) do + local mod = module.new( + nil, + modpath, + speclist.modules.prefix, + overrides + ) + + table.insert(o.modules, mod) + end + + return self +end + +return modules diff --git a/lua/dep/modules/module.lua b/lua/dep/modules/module.lua new file mode 100644 index 0000000..f83bc11 --- /dev/null +++ b/lua/dep/modules/module.lua @@ -0,0 +1,55 @@ +local spec_man = require("dep.spec") +local packager = require("dep.package") + +---@class module +---@field name string name of the module +---@field path string path to the module +---@field mod table the module +local module = {} + +--- Initialize a module +---@param self table? +---@param modpath string path to the module +---@param prefix string? the prefix to all modules +---@param overrides spec? a module override +---@return module|false module false on failure to load module +---@nodiscard +function module:new(modpath, prefix, overrides) + local ok, err + local o = {} + self = {} + self.__index = self + setmetatable(o, self) + + o.name = "" + if type(modpath) == "string" then + if prefix ~= nil then + if prefix:sub(#prefix) ~= "." and modpath:sub(1, 2) ~= "." then + modpath = "."..modpath + end + o.path = prefix..modpath + else + o.path = modpath + end + o.name = modpath + ok, o.mod = pcall(require, o.path) + if not ok then + return false + end + end + o.name = o.mod.name or o.name + + -- allow a module to be a spec + if spec_man.check(o.mod, true) ~= false then + o.mod = { o.mod } + end + + ok, err = pcall(packager.register_speclist, o.mod, overrides) + if not ok then + error(string.format("%s <- %s", err, o.name)) + end + + return self +end + +return module diff --git a/lua/dep/package.lua b/lua/dep/package.lua index cf0157b..0ae5753 100644 --- a/lua/dep/package.lua +++ b/lua/dep/package.lua @@ -1,5 +1,6 @@ local logger = require('dep.log') local spec_man = require("dep.spec") +local bench = require("dep.bench") ---@class package ---@field id string id of the package @@ -443,4 +444,51 @@ function package.findcycle(pkgs) return false end +--- recurse over all packages and register them +---@param speclist speclist table of specs +---@param overrides spec? a package spec that is used to override options +function package.register_speclist(speclist, overrides) + overrides = overrides or {} + + -- recurse the packages + local over = overrides + for _, spec in ipairs(speclist) do + -- make sure the overrides override and take into account the packages spec + ---@diagnostic disable-next-line: missing-fields + over = { + pin = overrides.pin or spec.pin, + disable = overrides.disable or spec.disable + } + + -- While a package can fail to load we just don't care, it will work itself + -- out. The goal is to make sure every plugin that can load does load, not + -- keep working plugins from loading because an unrelated one doesn't load. + package:new(spec, over) + end +end + +--- reload the package +---@param self package the package to reload +---@param force boolean? force all packages to load +function package:reload(force) + local reloaded = self:loadtree(force) + + if reloaded then + local ok, err + -- TODO: make a benchmark function + bench.mark("reload", function() + ok, err = pcall(vim.cmd, + [[ + silent! helptags ALL + silent! UpdateRemotePlugins + ]]) + end) + + if not ok then + logger:log("error", + "failed to reload helptags and remote plugins; reason: %s", err) + end + end +end + return package diff --git a/lua/dep/spec.lua b/lua/dep/spec.lua index b5ff240..5934a16 100644 --- a/lua/dep/spec.lua +++ b/lua/dep/spec.lua @@ -1,11 +1,11 @@ local logger = require("dep.log") ----@class modules +---@class specmodules ---@field prefix string prefix to prepend to the modules ---@field [integer] string list of all modules to load ---@class speclist ----@field modules modules a list of modules +---@field modules specmodules a list of modules ---@field [integer] spec a spec ---@class spec @@ -53,6 +53,8 @@ function spec:correct_spec() repeat if type(self[1]) ~= "string" then self = self[1] + elseif self[1] == nil then + break end until type(self[1]) == "string" end