nvim-neorocks / lz.n

πŸ¦₯ A dead simple lazy-loading Lua library for Neovim plugins.
GNU General Public License v2.0
53 stars 6 forks source link
lazy-loading neovim neovim-plugin nvim nvim-plugin plugin

:sloth: lz.n

Neovim Lua LuaRocks

A dead simple lazy-loading Lua library for Neovim plugins.

It is intended to be used

[!NOTE]

Should I lazy-load plugins?

It should be a plugin author's responsibility to ensure their plugin doesn't unnecessarily impact startup time, not yours!

See our "DO's and DONT's" guide for plugin developers.

Regardless, the current status quo is horrible, and some authors may not have the will or capacity to improve their plugins' startup impact.

If you find a plugin that takes too long to load, or worse, forces you to load it manually at startup with a call to a heavy setup function, consider opening an issue on the plugin's issue tracker.

:star2: Features

:moon: Introduction

lz.n provides abstractions for lazy-loading Neovim plugins, with an API that is loosely based on lazy.nvim, but reduced down to the very basics required for lazy-loading only.

:milky_way: Philosophy

lz.n is designed based on the UNIX philosophy: Do one thing well.

:zzz: Comparison with lazy.nvim

:pencil: Requirements

:wrench: Configuration

You can override the function used to load plugins. lz.n has the following default:

vim.g.lz_n = {
    ---@type fun(name: string)
    load = vim.cmd.packadd,
}

:books: Usage

require("lz.n").load(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

Property Type Description lazy.nvim equivalent
[1] string The plugin's name (not the module name). This is what is passed to the load(name) function. name[^1]
enabled boolean? or fun():boolean When false, or if the function returns false, then this plugin will not be included in the spec. enabled
beforeAll fun(lz.n.Plugin)? Always executed before any plugins are loaded. init
before fun(lz.n.Plugin)? Executed before a plugin is loaded. None
after fun(lz.n.Plugin)? Executed after a plugin is loaded. config
event string? or {event?:string\|string[], pattern?:string\|string[]}\ or string[] Lazy-load on event. Events can be specified as BufEnter or with a pattern like BufEnter *.lua. event
cmd string? or string[] Lazy-load on command. cmd
ft string? or string[] Lazy-load on filetype. ft
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 vim.g.lz_n.load() function for an individual plugin. None.

[^1]: In contrast to lazy.nvim's name field, a lz.n.PluginSpec's name is not optional. This is because lz.n is not a plugin manager and needs to be told which plugins to load. [^2]: The reason this library doesn't lazy-load colorschemes automatically is that it would have to know where the plugin is installed in order to determine which plugin to load.

User events

[^3]: This is equivalent to lazy.nvim's VeryLazy event.

Examples

require("lz.n").load {
    {
        "neo-tree.nvim",
        keys = {
            -- Create a key mapping and lazy-load when it is used
            { "<leader>ft", "<CMD>Neotree toggle<CR>", desc = "NeoTree toggle" },
        },
        after = function()
            require("neo-tree").setup()
        end,
    },
    {
        "crates.nvim",
        -- lazy-load when opening a toml file
        ft = "toml",
    },
    {
        "sweetie.nvim",
        -- lazy-load when setting the `sweetie` colorscheme
        colorscheme = "sweetie",
    },
    {
        "vim-startuptime",
        cmd = "StartupTime",
        before = function()
            -- Configuration for plugins that don't force you to call a `setup` function
            -- for initialization should typically go in a `before`
            --- or `beforeAll` function.
            vim.g.startuptime_tries = 10
        end,
    },
    {
        "nvim-cmp",
        -- load cmp on InsertEnter
        event = "InsertEnter",
    },
    {
        "dial.nvim",
        -- lazy-load on keys. -- Mode is `n` by default.
        keys = { "<C-a>", { "<C-x>", mode = "n" } },
    },
}
paq-nvim example ```lua require "paq" { { "nvim-telescope/telescope.nvim", opt = true } { "NTBBloodBatch/sweetie.nvim", opt = true } } require("lz.n").load { { "telescope.nvim", cmd = "Telescope", }, { "sweetie.nvim", colorscheme = "sweetie", }, } ```
Nix (Home Manager) example ```nix programs.neovim = { enable = true; plugins = with pkgs.vimPlugins [ lz-n { plugin = pkgs.vimPlugins.telescope-nvim; config = '' require("lz.n").load { "telescope.nvim", cmd = "Telescope", } ''; type = "lua"; optional = true; } { plugin = pkgs.vimPlugins.sweetie-nvim; config = '' require("lz.n").load { "sweetie.nvim", colorscheme = "sweetie", } ''; type = "lua"; optional = true; } ]; }; ```

Structuring Your Plugins

As is the case with lazy.nvim, you can also split your plugin specs into multiple files. Instead of passing a spec table to load(), you can use a Lua module. The function will merge specs from the module and any top-level sub-modules together in the final spec, so it is not needed to add require calls in your main plugin file to the other files.

Example:

require("lz.n").load("plugins")
return {
    { "sweetie.nvim" },
    { "telescope.nvim", cmd = "Telescope" },
}

[^4]: It does not merge multiple specs for the same plugin from different files.

Example structure:

── nvim
  β”œβ”€β”€ lua
  β”‚  └── plugins # Your plugin specs go here.
  β”‚     └── init.lua # Optional top-level module returning a list of specs
  β”‚     └── neorg.lua # Single spec
  β”‚     └── telescope/init.lua # Single spec
  β”œβ”€β”€ init.lua

Or

── nvim
  β”œβ”€β”€ lua
  β”‚  └── plugins.lua # Optional top-level module returning a list of specs
  β”œβ”€β”€ init.lua

Custom Handlers

You may register your own handlers to lazy-load plugins via other triggers not already covered by the plugin spec.

You should register all handlers before calling require('lz.n').load, because they will not be retroactively applied to the load calls that occur before they are registered.

The register_handler function returns a boolean that indicates success.

---@param handler lz.n.Handler
---@return boolean success
require("lz.n").register_handler(handler)

lz.n.Handler

Property Type Description
spec_field string the lz.n.PluginSpec field defined by the handler
add fun(plugin: lz.n.Plugin) adds a plugin to the handler
del fun(plugin: lz.n.Plugin)? removes a plugin from the handler

When writing custom handlers, you can load the plugin and run the hooks from the spec with the following function:

  ---@type fun(plugins: string | lz.n.Plugin | string[] | lz.n.Plugin[])
  require('lz.n').trigger_load

The function accepts plugin names or parsed plugin specs. It will call the handler's del function (if it exists) after the before hooks, and before load of the plugin's spec.

:green_heart: Contributing

All contributions are welcome! See CONTRIBUTING.md.

:book: License

This library is licensed according to GPL version 2 or (at your option) any later version.