Compare commits

..

15 Commits

Author SHA1 Message Date
70853bd01e disabled packages were still getting force loaded 2025-07-10 21:20:53 -04:00
9d4322572c should've tested the changes, nvim_create_usercommand doesn't like...
unkown options
2025-07-04 05:27:36 -04:00
3b33a604d8 commands get rerun by default now 2025-07-04 05:25:06 -04:00
5aff147731 add better type definitions, and fix a bug related to...
lua indexing my beloved
2025-07-04 05:04:23 -04:00
edf32fbf06 fix bug: remove the callback from the on_load list 2025-07-03 18:02:44 -04:00
adec93b7f4 fix formatting log lines causing errors 2025-07-03 17:02:33 -04:00
1cd5f63f8e actually error when we fail to setup lazy loading for a package 2025-07-03 17:00:46 -04:00
8e46eddecd Allow users to lazy load on another package 2025-07-03 16:31:04 -04:00
542298c1fe registering a filetype lazy load condition should happen on self not the...
lazy_loader
2025-07-02 21:51:34 -04:00
cfc3f08d53 remove a testcase for specs 2025-07-02 21:13:30 -04:00
1c2f49fcfa unpin dep internally 2025-07-02 21:13:08 -04:00
f6209048f1 Revert "use the correct_spec function to handle dependencies and requirements"
This reverts commit 318a86d786.
2025-07-02 21:07:04 -04:00
5bd30d9397 don't error when the ui is closed 2025-07-02 20:36:14 -04:00
1538046b6f make finding modules synchronous to avoid some bugs when calling...
internal neovim api functions
2025-07-02 20:34:42 -04:00
5deffca36e improve lazy loading on commands, dep will now load on completion 2025-07-02 17:54:43 -04:00
10 changed files with 228 additions and 94 deletions

View File

@ -15,6 +15,7 @@ Table of Contents *dep-table-of-contents*
6. Examples |dep-examples| 6. Examples |dep-examples|
- Declaring Dependencies |dep-examples-declaring-dependencies| - Declaring Dependencies |dep-examples-declaring-dependencies|
- Modules |dep-examples-modules| - Modules |dep-examples-modules|
- Lazy Loading |dep-examples-lazy-loading|
7. Credits & License |dep-credits| 7. Credits & License |dep-credits|
============================================================================== ==============================================================================
@ -216,10 +217,17 @@ is equivalent to the following:
load:cmd("Command", { load:cmd("Command", {
callback = function() callback = function()
load:cleanup() load:cleanup()
if (rerun) then
vim.cmd("Command")
end
end end
}) })
< <
If you wish the second argument may be completely ommitted. If you wish the second argument may be completely ommitted. Note the inclusion
of a `rerun` field, this is a parameter which may be passed into the options table
to re-run the binding after loading the package. You may choose to disable the
built-in logic by passing false.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
LOAD:AUTO *dep-lazy-loading-api-auto* LOAD:AUTO *dep-lazy-loading-api-auto*
@ -293,6 +301,27 @@ into the options table to re-run the binding after loading the package. You
may choose to include your own logic by passing a function to the `rerun` may choose to include your own logic by passing a function to the `rerun`
field or disable the built-in logic by passing false. field or disable the built-in logic by passing false.
------------------------------------------------------------------------------
LOAD:PLUGIN *dep-lazy-loading-api-plugin*
`load:plugin` is a function which allows you to specify another plugin for the
package to load after. It takes two arguments: `plugin` which is the name of
the plugin you want to follow like: 'user/package'. The second argument is
`opts` which is a table with one option: `callback` which is a function. The
following is an example:
>lua
load:plugin("user/package", {})
<
Which is the same as:
>lua
load:plugin("user/package", {
callback = function()
self:cleanup()
end
})
<
When 'user/package' is already loaded the `callback` is called immediately.
LAZY LOADING API SHORTHANDS *dep-lazy-loading-api-shorthands* LAZY LOADING API SHORTHANDS *dep-lazy-loading-api-shorthands*
On occasion you may wish to only define one condition for the package to load. On occasion you may wish to only define one condition for the package to load.
@ -589,6 +618,50 @@ declared in that module.
} }
} }
< <
LAZY LOADING *dep-examples-lazy-loading*
Lazy loading is a very complicated topic, and therefore this part of the
documentation assumes you have experience with regular package managment.
Let's go over loading order, and how the lazy loader determines what needs to
be loaded.
Let's say we have the following spec:
>lua
{ "user/package",
lazy = true,
deps = "user/dependent"
}
<
This is the same as the following:
>lua
{ "user/package",
lazy = true
},
{ "user/dependent",
reqs = "user/package",
lazy = require("dep.lazy.loader.short").plugin("user/package")
}
<
What you're seeing is implicit lazy loading. By default dep will lazy load
dependents who are explicitly defined in the spec. Now if we we're to modify
'user/dependent' like so:
>lua
{ "user/package",
lazy = true
},
{ "user/dependent",
reqs = "user/package",
lazy = function(load)
load:plugin("user/package")
load:cmd("LoadDependent")
end
}
<
If we were to call the command `:LoadDependent` it would first load
'user/package', and then load 'user/dependent'.
============================================================================== ==============================================================================
7. Credits & License *dep-credits* 7. Credits & License *dep-credits*

View File

@ -100,8 +100,7 @@ return function(opts)
local root = packager:new({ local root = packager:new({
"squibid/dep", "squibid/dep",
url = "https://git.squi.bid/squibid/dep.git", url = "https://git.squi.bid/squibid/dep.git",
branch = "lazy", branch = "lazy"
pin = true
}) })
if not root then if not root then
logger:log("error", "couldn't register root package") logger:log("error", "couldn't register root package")

View File

@ -1,10 +1,12 @@
local logger = require('dep.log') local logger = require('dep.log')
local packager = require('dep.package')
---@class lazy_loader ---@class lazy_loader
---@field load function the function to load the plugin ---@field load function the function to load the plugin
---@field command_ids table the commands that have been registered ---@field command_ids string[] the commands that have been registered
---@field auto_ids table the auto commands that have been registered ---@field auto_ids number[] the auto commands that have been registered
---@field keybind_ids table the keybinds that have been registered ---@field keybind_ids table[] the keybinds that have been registered
---@field plugin_ids table[] the plugins that have been registered
local lazy_loader = {} local lazy_loader = {}
--- create a new instance of lazy --- create a new instance of lazy
@ -16,6 +18,7 @@ function lazy_loader:new()
o.command_ids = {} o.command_ids = {}
o.auto_ids = {} o.auto_ids = {}
o.keybind_ids = {} o.keybind_ids = {}
o.plugin_ids = {}
self.__index = self self.__index = self
@ -33,8 +36,32 @@ end
---@param opts vim.api.keyset.user_command? options ---@param opts vim.api.keyset.user_command? options
function lazy_loader:cmd(name, opts) function lazy_loader:cmd(name, opts)
opts = opts or {} opts = opts or {}
vim.api.nvim_create_user_command(name, opts['callback'] or function()
-- move the rerun arg to a seperate variable because keymap.set doesn't like
-- options it doesn't know of
local rerun = opts["rerun"] or true
opts['rerun'] = nil
-- load the plugin on completion
if not opts["complete"] then
opts["complete"] = function(_, line, _)
self:cleanup() self:cleanup()
-- return all completions for the current input, we need this to ensure
-- that the new completions are loaded from the actual plugin, not our
-- definiton of the command
return vim.fn.getcompletion(line, "cmdline")
end
opts["nargs"] = "*"
end
vim.api.nvim_create_user_command(name, opts['callback'] or function(_)
self:cleanup()
-- attempt to rerun the command
if not rerun then
pcall(vim.cmd, name)
end
end, opts) end, opts)
table.insert(self.command_ids, name) table.insert(self.command_ids, name)
@ -57,7 +84,7 @@ end
--- create an auto command which will trigger on filetype --- create an auto command which will trigger on filetype
---@param filetype string filetype to register the auto on ---@param filetype string filetype to register the auto on
function lazy_loader:ft(filetype) function lazy_loader:ft(filetype)
lazy_loader:auto("FileType", { self:auto("FileType", {
pattern = filetype pattern = filetype
}) })
end end
@ -93,29 +120,53 @@ function lazy_loader:keymap(mode, bind, opts)
table.insert(self.keybind_ids, { ['mode'] = mode, ['bind'] = bind }) table.insert(self.keybind_ids, { ['mode'] = mode, ['bind'] = bind })
end end
--- load a plugin when another plugin loads
---@param plugin string plugin name
---@param opts table? options
function lazy_loader:plugin(plugin, opts)
opts = opts or {}
opts["callback"] = opts["callback"] or function()
self:cleanup()
end
if packager.get_packages()[plugin].loaded then
opts["callback"]()
else
local on_load = packager.get_packages()[plugin].on_load
local on_load_idx = #on_load + 1
on_load[on_load_idx] = opts["callback"]
table.insert(self.plugin_ids, { plugin, on_load_idx })
end
end
--- cleanup all the callbacks, and load the plugin --- cleanup all the callbacks, and load the plugin
function lazy_loader:cleanup() function lazy_loader:cleanup()
-- cleanup user commands -- cleanup user commands
for _, command_id in pairs(self.command_ids) do for _, command_id in ipairs(self.command_ids) do
local ok, err = pcall(vim.api.nvim_del_user_command, command_id) local ok, err = pcall(vim.api.nvim_del_user_command, command_id)
if not ok then if not ok then
logger:log("lazy", err or "failed to delete user command") logger:log("lazy", err or "failed to delete user command")
end end
end end
-- cleanup auto commands -- cleanup auto commands
for _, auto_id in pairs(self.auto_ids) do for _, auto_id in ipairs(self.auto_ids) do
local ok, err = pcall(vim.api.nvim_del_autocmd, auto_id) local ok, err = pcall(vim.api.nvim_del_autocmd, auto_id)
if not ok then if not ok then
logger:log("lazy", err or "failed to delete auto command") logger:log("lazy", err or "failed to delete auto command")
end end
end end
-- cleanup keymaps -- cleanup keymaps
for _, keybind_id in pairs(self.keybind_ids) do for _, keybind_id in ipairs(self.keybind_ids) do
local ok, err = pcall(vim.keymap.del, keybind_id.mode, keybind_id.bind, {}) local ok, err = pcall(vim.keymap.del, keybind_id.mode, keybind_id.bind, {})
if not ok then if not ok then
logger:log("lazy", err or "failed to delete keymap") logger:log("lazy", err or "failed to delete keymap")
end end
end end
-- cleanup plugins
for _, plugin_id in ipairs(self.plugin_ids) do
table.remove(packager.get_packages()[plugin_id[1]].on_load, plugin_id[2])
end
-- load the plugin -- load the plugin
self:load() self:load()
end end

View File

@ -59,4 +59,14 @@ function short.keymap(mode, bind, opts)
end end
end end
--- create a single plugin load event for when another plugin loads
---@param plugin string plugin name
---@param opts table? options
---@return function callback
function short.plugin(plugin, opts)
return function(load)
load:plugin(plugin, opts)
end
end
return short return short

View File

@ -30,10 +30,7 @@ function modules:setup(speclist, overrides, config_path)
"lua", (speclist.modules.prefix:gsub("%.", "/")) "lua", (speclist.modules.prefix:gsub("%.", "/"))
) )
h.uv.fs_scandir(path, function(err, handle) local handle = h.uv.fs_scandir(path)
if err then
logger:log("error", "failed to load modules; reason: %s", err)
else
while handle do while handle do
local name = h.uv.fs_scandir_next(handle) local name = h.uv.fs_scandir_next(handle)
if name then if name then
@ -46,13 +43,9 @@ function modules:setup(speclist, overrides, config_path)
-- when attempting to load it -- when attempting to load it
name = name:sub(0, #name - 4) name = name:sub(0, #name - 4)
-- attempt to load the module -- put the module into the list of modules
local mod = module.new(nil, name, speclist.modules.prefix, overrides) table.insert(speclist.modules, name)
if not mod then
goto continue
end
table.insert(o.modules, mod)
::continue:: ::continue::
elseif name == nil then elseif name == nil then
-- no more entries -- no more entries
@ -60,12 +53,11 @@ function modules:setup(speclist, overrides, config_path)
else else
-- if there's a single error bail out -- if there's a single error bail out
logger:log("error", "failed to run clean uv.fs_scandir_next failed") logger:log("error", "failed to run clean uv.fs_scandir_next failed")
return break
end end
end end
end end
end)
else
-- loop through all modules and initialize them -- loop through all modules and initialize them
for _, modpath in ipairs(speclist.modules) do for _, modpath in ipairs(speclist.modules) do
local mod = module.new(nil, modpath, speclist.modules.prefix, overrides) local mod = module.new(nil, modpath, speclist.modules.prefix, overrides)
@ -76,7 +68,6 @@ function modules:setup(speclist, overrides, config_path)
table.insert(o.modules, mod) table.insert(o.modules, mod)
::continue:: ::continue::
end end
end
return self return self
end end

View File

@ -165,18 +165,10 @@ function package:new(spec, overrides)
-- if the child package is lazy loaded make sure the child package -- if the child package is lazy loaded make sure the child package
-- is only loaded when the parent package has finished loading -- is only loaded when the parent package has finished loading
if o.lazy then if o.lazy then
table.insert(o.on_load, function()
local ok = o:loadtree(true)
if not ok then
logger:log("lazy",
"failed to run loadtree for %s, some packages may not be loaded",
o.id)
end
end)
-- tell the dep that it's gonna be lazy -- tell the dep that it's gonna be lazy
pkg.lazy = true pkg.lazy = true
table.insert(pkg.lazy_load, function(_) end) table.insert(pkg.lazy_load,
require("dep.lazy.loader.short").plugin(id))
end end
end end
end end
@ -252,6 +244,10 @@ function package:ensureadded(force)
--- load a package --- load a package
---@param pkg package ---@param pkg package
local function loadpkg(pkg) local function loadpkg(pkg)
if not self.enabled then
return false
end
-- make sure to load the dependencies first -- make sure to load the dependencies first
for _, p in pairs(pkg.requirements) do for _, p in pairs(pkg.requirements) do
if not p.loaded then if not p.loaded then
@ -316,7 +312,7 @@ function package:ensureadded(force)
if load_cond ~= true then if load_cond ~= true then
local ok, err = pcall(load_cond, l) local ok, err = pcall(load_cond, l)
if not ok then if not ok then
logger:log("lazy", "failed to register load conditions for '%s': %s", logger:log("error", "failed to register lazy load conditions for '%s': %s",
self.name, err) self.name, err)
end end
end end

View File

@ -184,7 +184,10 @@ function spec:check(silent)
return false return false
end end
self.reqs = spec.correct_spec(self.reqs) -- turn an id into a spec
if (is == "string") then
self.reqs = { self.reqs }
end
end end
if self.deps ~= nil then -- spec.deps if self.deps ~= nil then -- spec.deps
@ -194,7 +197,10 @@ function spec:check(silent)
return false return false
end end
self.deps = spec.correct_spec(self.deps) -- turn an id into a spec
if (is == "string") then
self.deps = { self.deps }
end
end end
if silent == true then if silent == true then

View File

@ -20,16 +20,29 @@ end
---@param log_line string log line ---@param log_line string log line
---@return chunk[] chunks ---@return chunk[] chunks
function format.log_line(log_line) function format.log_line(log_line)
local log_time = string.sub( log_line, string.find(log_line, "%[") + 1, -- make sure we don't do operations on nil values
if not log_line or log_line == "" then
return {}
end
-- error on any nil values, this should prevent us from parsing an incorrectly
-- formatted log line
local log_time, colon, log_path, log_path_ln, level, rest
local ok = pcall(function()
log_time = string.sub(log_line, string.find(log_line, "%[") + 1,
string.find(log_line, "%]") - 1) string.find(log_line, "%]") - 1)
local colon = string.find(log_line, ":", 11) colon = string.find(log_line, ":", 11)
local log_path = string.sub(log_line, string.find(log_line, "%]") + 2, log_path = string.sub(log_line, string.find(log_line, "%]") + 2,
colon - 1) colon - 1)
local log_path_ln = string.sub(log_line, colon + 1, log_path_ln = string.sub(log_line, colon + 1,
string.find(log_line, ":", colon + 1) - 1) string.find(log_line, ":", colon + 1) - 1)
local level = string.sub(log_line, string.find(log_line, "%(") + 1, level = string.sub(log_line, string.find(log_line, "%(") + 1,
string.find(log_line, "%)") - 1) string.find(log_line, "%)") - 1)
local rest = string.sub(log_line, string.find(log_line, "%)") + 2) rest = string.sub(log_line, string.find(log_line, "%)") + 2)
end)
if not ok then
return {}
end
return { return {
{ "[", "" }, { "[", "" },

View File

@ -44,8 +44,10 @@ local function page_log()
-- put the cursor at the bottom of the page after drawing -- put the cursor at the bottom of the page after drawing
p.post_draw = function() p.post_draw = function()
if ui.winnr then
vim.api.nvim_win_set_cursor(ui.winnr, { #p.content, 0 }) vim.api.nvim_win_set_cursor(ui.winnr, { #p.content, 0 })
end end
end
-- read in the contents of the file, and keep watching for updates -- read in the contents of the file, and keep watching for updates
local function update_contents() local function update_contents()

View File

@ -17,6 +17,14 @@ describe("ui log formatting", function()
}, },
dep_ui_format.log_line("[11:22:33] file.lua:1:(vim) some fancy message") dep_ui_format.log_line("[11:22:33] file.lua:1:(vim) some fancy message")
) )
-- malformed log line
assert.same({},
dep_ui_format.log_line("11:22:33] file.lua:1:(vim) some fancy message"))
-- test nil values
assert.same({}, dep_ui_format.log_line(""))
assert.same({}, dep_ui_format.log_line(nil))
end) end)
end) end)
@ -51,20 +59,5 @@ describe("package specification", function()
} }
} }
) )
assert.same(
dep_spec_man.check({
"user/package",
deps = {
{ { "user/dependency" } }
}
}, true),
{
"user/package",
deps = {
"user/dependency"
}
}
)
end) end)
end) end)