Skip to content

Commit

Permalink
feat: register individual plugin specs for lazy loading
Browse files Browse the repository at this point in the history
by passing a single spec to `load()`
  • Loading branch information
mrcjkb committed Jun 16, 2024
1 parent e123d22 commit b9c03c1
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 52 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,18 @@ require("lz.n").load(plugins)
```

- **plugins**: this should be a `table` or a `string`
- `table`: a list with your [Plugin Spec](#plugin-spec)
- `table`:
- A list with your [Plugin Specs](#plugin-spec)
- Or a single plugin spec.
- `string`: a Lua module name that contains your [Plugin Spec](#plugin-spec).
See [Structuring Your Plugins](#structuring-your-plugins)

> [!TIP]
>
> You can call `load()` as you would call `lazy.nvim`'s `setup()`.
> Or, you can also use it to register individual plugin specs for lazy
> loading.
### Plugin spec

<!-- markdownlint-disable MD013 -->
Expand All @@ -123,6 +131,7 @@ require("lz.n").load(plugins)
| **keys** | `string?` or `string[]` or `lz.n.KeysSpec[]` | Lazy-load on key mapping. | `keys` |
| **colorscheme** | `string?` or `string[]` | Lazy-load on colorscheme. | None. `lazy.nvim` lazy-loads colorschemes automatically[^2]. |
| **priority** | `number?` | Only useful for **start** plugins (not lazy-loaded) to force loading certain plugins first. Default priority is `50` (or `1000` if `colorscheme` is set). | `priority` |
| **load** | `fun(string)?` | Can be used to override the `load()` function for an individual plugin. | None. |
<!-- markdownlint-enable MD013 -->

[^1]: In contrast to `lazy.nvim`'s `name` field, a `lz.n.PluginSpec`'s `name` *is not optional*.
Expand Down
32 changes: 23 additions & 9 deletions lua/lz/n/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,40 @@ end)

---@param spec string | lz.n.Spec
function M.load(spec)
if vim.g.lz_n_did_load then
return vim.notify("lz.n has already loaded your plugins.", vim.log.levels.WARN, { title = "lz.n" })
end
vim.g.lz_n_did_load = true

if type(spec) == "string" then
spec = { import = spec }
end
---@cast spec lz.n.Spec
local plugins = require("lz.n.spec").parse(spec)
--- @cast spec lz.n.Spec
local spec_mod = require("lz.n.spec")
local is_single_plugin_spec = spec_mod.is_single_plugin_spec(spec)
if not is_single_plugin_spec then
if vim.g.lz_n_did_load then
return vim.notify(
"lz.n.load() should only be called on a list of plugin specs once.",
vim.log.levels.WARN,
{ title = "lz.n" }
)
end
vim.g.lz_n_did_load = true
end
local plugins = spec_mod.parse(spec)
require("lz.n.loader").load_startup_plugins(plugins)
require("lz.n.state").plugins = plugins

local state = require("lz.n.state")
if is_single_plugin_spec then
state.plugins = vim.tbl_deep_extend("force", state.plugins, plugins)
else
state.plugins = plugins
end
require("lz.n.handler").init(plugins)
if vim.v.vim_did_enter == 1 then
deferred_ui_enter()
else
elseif not vim.g.lz_n_did_create_deferred_ui_enter_autocmd then
vim.api.nvim_create_autocmd("UIEnter", {
once = true,
callback = deferred_ui_enter,
})
vim.g.lz_n_did_create_deferred_ui_enter_autocmd = true
end
end

Expand Down
2 changes: 1 addition & 1 deletion lua/lz/n/loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function M._load(plugin)
end
require("lz.n.handler").disable(plugin)
---@type fun(name: string) | nil
local load_impl = vim.tbl_get(vim.g, "lz_n", "load")
local load_impl = plugin.load or vim.tbl_get(vim.g, "lz_n", "load")
if type(load_impl) == "function" then
load_impl(plugin.name)
else
Expand Down
4 changes: 4 additions & 0 deletions lua/lz/n/meta.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ error("Cannot import a meta module")
--- Only useful for lazy=false plugins to force loading certain plugins first.
--- Default priority is 50
--- @field priority? number
---
--- Set this to override the `load` function for an individual plugin.
--- Defaults to `vim.g.lz_n.load()`, see |lz.n.Config|.
--- @field load? fun(name: string)

--- @alias lz.n.Event {id:string, event:string[]|string, pattern?:string[]|string}
--- @alias lz.n.EventSpec string|{event?:string|string[], pattern?:string|string[]}|string[]
Expand Down
16 changes: 14 additions & 2 deletions lua/lz/n/spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,28 @@ local function parse(spec)
return result
end

---@param spec lz.n.Spec
---@return boolean
function M.is_spec_list(spec)
return #spec > 1 or vim.islist(spec) and #spec > 1
end

---@param spec lz.n.Spec
---@return boolean
function M.is_single_plugin_spec(spec)
return type(spec[1]) == "string"
end

---@private
---@param spec lz.n.Spec
---@param result table<string, lz.n.Plugin>
function M._normalize(spec, result)
if #spec > 1 or vim.islist(spec) and #spec > 1 then
if M.is_spec_list(spec) then
---@cast spec lz.n.Spec[]
for _, sp in ipairs(spec) do
M._normalize(sp, result)
end
elseif spec[1] then
elseif M.is_single_plugin_spec(spec) then
---@cast spec lz.n.PluginSpec
result[spec[1]] = parse(spec)
elseif spec.import then
Expand Down
111 changes: 72 additions & 39 deletions spec/lz_n_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,77 @@ local loader = require("lz.n.loader")
local spy = require("luassert.spy")

describe("lz.n", function()
it("load", function()
local spy_load = spy.on(loader, "_load")
lz.load({
{
"neorg",
},
{
"crates.nvim",
ft = { "toml", "rust" },
},
{
"telescope.nvim",
keys = "<leader>tt",
cmd = "Telescope",
},
})
assert.spy(spy_load).called(1)
assert.spy(spy_load).called_with({
name = "neorg",
lazy = false,
})
vim.api.nvim_exec_autocmds("FileType", { pattern = "toml" })
assert.spy(spy_load).called(2)
assert.spy(spy_load).called_with({
name = "crates.nvim",
lazy = true,
event = {
require("lz.n.handler.ft").parse("toml"),
require("lz.n.handler.ft").parse("rust"),
},
})
vim.cmd.Telescope()
assert.spy(spy_load).called(3)
assert.spy(spy_load).called_with({
name = "telescope.nvim",
lazy = true,
cmd = { "Telescope" },
keys = { require("lz.n.handler.keys").parse("<leader>tt") },
})
describe("load", function()
it("list of plugin specs", function()
local spy_load = spy.on(loader, "_load")
lz.load({
{
"neorg",
},
{
"crates.nvim",
ft = { "toml", "rust" },
},
{
"telescope.nvim",
keys = "<leader>tt",
cmd = "Telescope",
},
})
assert.spy(spy_load).called(1)
assert.spy(spy_load).called_with({
name = "neorg",
lazy = false,
})
vim.api.nvim_exec_autocmds("FileType", { pattern = "toml" })
assert.spy(spy_load).called(2)
assert.spy(spy_load).called_with({
name = "crates.nvim",
lazy = true,
event = {
require("lz.n.handler.ft").parse("toml"),
require("lz.n.handler.ft").parse("rust"),
},
})
vim.cmd.Telescope()
assert.spy(spy_load).called(3)
assert.spy(spy_load).called_with({
name = "telescope.nvim",
lazy = true,
cmd = { "Telescope" },
keys = { require("lz.n.handler.keys").parse("<leader>tt") },
})
end)
it("individual plugin specs", function()
local spy_load = spy.on(loader, "_load")
lz.load({
"foo.nvim",
keys = "<leader>ff",
})
assert.spy(spy_load).called(0)
local feed = vim.api.nvim_replace_termcodes("<Ignore><leader>ff", true, true, true)
vim.api.nvim_feedkeys(feed, "ix", false)
assert.spy(spy_load).called(1)
lz.load({
"bar.nvim",
cmd = "Bar",
})
vim.cmd.Bar()
assert.spy(spy_load).called(2)
end)
it("can override load implementation via plugin spec", function()
local loaded = false
lz.load({
"baz.nvim",
keys = "<leader>bb",
load = function()
loaded = true
end,
})
assert.False(loaded)
local feed = vim.api.nvim_replace_termcodes("<Ignore><leader>bb", true, true, true)
vim.api.nvim_feedkeys(feed, "ix", false)
assert.True(loaded)
end)
end)
end)

0 comments on commit b9c03c1

Please sign in to comment.