NotAShelf/nvf

Lazy.nvim as a module to allow lazy plugin loading

Closed this issue ยท 10 comments

โš ๏ธ Please verify that this feature request has NOT been suggested before.

  • I checked and didn't find a similar feature request

๐Ÿท๏ธ Feature Type

API Additions

๐Ÿ”– Feature description

Lazy loading is a very nice feature, but implementing it from scratch might be a lot of work.
As such I propose easy access to lazy for allowing it to manage plugins.

โœ”๏ธ Solution

Some sort of API.
It would take nix expressions

lazy = {
    plugin y = {
    link = ...
    setup = ...
    lazy = ...
};
}

This would then be passed along in lua to lazy (As lazy is very integrated with lua)

โ“ Alternatives

There's the option of implementing lazy plugin management, but that would require a lot of overhead in plugin loading

๐Ÿ“ Additional Context

No response

To be fair, I'm not very keen on plugin managers. Never been, never will.

On another hand, lazy's ability to load plugins lazily (and the fact that it's the de-facto plugin manager of most configurations right now) inclines me to add support for it even though I will not use (nor actively support it). Problem though, is that the config schema is really complicated, and perhaps too complicated to even attempt generating from Nix.

The readme example looks as follows:

return {
  -- the colorscheme should be available when starting Neovim
  {
    "folke/tokyonight.nvim",
    lazy = false, -- make sure we load this during startup if it is your main colorscheme
    priority = 1000, -- make sure to load this before all the other start plugins
    config = function()
      -- load the colorscheme here
      vim.cmd([[colorscheme tokyonight]])
    end,
  },

  -- I have a separate config.mappings file where I require which-key.
  -- With lazy the plugin will be automatically loaded when it is required somewhere
  { "folke/which-key.nvim", lazy = true },

  {
    "nvim-neorg/neorg",
    -- lazy-load on filetype
    ft = "norg",
    -- options for neorg. This will automatically call `require("neorg").setup(opts)`
    opts = {
      load = {
        ["core.defaults"] = {},
      },
    },
  },

  {
    "dstein64/vim-startuptime",
    -- lazy-load on a command
    cmd = "StartupTime",
    -- init is called during startup. Configuration for vim plugins typically should be set in an init function
    init = function()
      vim.g.startuptime_tries = 10
    end,
  },

  {
    "hrsh7th/nvim-cmp",
    -- load cmp on InsertEnter
    event = "InsertEnter",
    -- these dependencies will only be loaded when cmp loads
    -- dependencies are always lazy-loaded unless specified otherwise
    dependencies = {
      "hrsh7th/cmp-nvim-lsp",
      "hrsh7th/cmp-buffer",
    },
    config = function()
      -- ...
    end,
  },

  -- if some code requires a module from an unloaded plugin, it will be automatically loaded.
  -- So for api plugins like devicons, we can always set lazy=true
  { "nvim-tree/nvim-web-devicons", lazy = true },

  -- you can use the VeryLazy event for things that can
  -- load later and are not important for the initial UI
  { "stevearc/dressing.nvim", event = "VeryLazy" },

  {
    "Wansmer/treesj",
    keys = {
      { "J", "<cmd>TSJToggle<cr>", desc = "Join Toggle" },
    },
    opts = { use_default_keymaps = false, max_join_length = 150 },
  },

  {
    "monaqa/dial.nvim",
    -- lazy-load on keys
    -- mode is `n` by default. For more advanced options, check the section on key mappings
    keys = { "<C-a>", { "<C-x>", mode = "n" } },
  },

  -- local plugins need to be explicitly configured with dir
  { dir = "~/projects/secret.nvim" },

  -- you can use a custom url to fetch a plugin
  { url = "git@github.com:folke/noice.nvim.git" },

  -- local plugins can also be configure with the dev option.
  -- This will use {config.dev.path}/noice.nvim/ instead of fetching it from Github
  -- With the dev option, you can easily switch between the local and installed version of a plugin
  { "folke/noice.nvim", dev = true },
}

While we can try and generate the top-level attributes (e.g. lazy, priority, ft), config and keys tables look quite difficult to deal with.

I'll go ahead and CC @horriblename to see what he thinks about the implementation as he's looking at a plugin config schema generated from Nix.

Indeed that tables might be difficult to parse. There's the possibly of just using the deprecating the keys option and instead handling something like

#check if lazy.plugin is enabled/installed
if lazy.plugins.PluginX.enabled = true {
    vim.maps.... = {
    action = "Plugin Command"
    }
};

The config part is a literal lua function isn't it? Couldn't it be passed literally?

Indeed that tables might be difficult to parse. There's the possibly of just using the deprecating the keys option and instead handling something like

#check if lazy.plugin is enabled/installed
if lazy.plugins.PluginX.enabled = true {
    vim.maps.... = {
    action = "Plugin Command"
    }
};

I am really not looking to replace the plugin management with lazy - which is why I would not want to deprecate vim.keys

The config part is a literal lua function isn't it? Couldn't it be passed literally?

It could, but at that point why use a module? We have two lua-first APIs that you can use to configure a plugin

I am really not looking to replace the plugin management with lazy - which is why I would not want to deprecate vim.keys

Oh I might have not made myself clear or used the wrong key function.
I meant creating custom bindings or prompting the user to, instead of parsing the lazy "keys" field

It could, but at that point why use a module? We have two lua-first APIs that you can use to configure a plugin

That's true, and excuse me my lack of knowledge on this, but using these APIs wouldn't the plugins be "required" and as such loaded automatically?
Or is that only when requiring manually somewhere?

That's true, and excuse me my lack of knowledge on this, but using these APIs wouldn't the plugins be "required" and as such loaded automatically?
Or is that only when requiring manually somewhere?

If you use the extra plugin API, you would be loading the plugin and providing its configuration at the same time. If, instead, using the extra Lua config API, you can have your plugins and Lazy.nvim in your optionalPlugins (added to path but not loaded) then you can provide raw Lua configuration (for either the plugins or lazy.nvim directly) to completely control their behaviour.

for what it's worth, the extraPlugins API should be fairly easy to add lazy.nvim support.

The main problem is with converting builtin plugins:
we might need to go all in and make lazy.nvim mandatory for everyone, I'm not sure if it's a good idea + its a lot work

lazy loading is something we've been missing but unfortunately there's no easy way out

for what it's worth, the extraPlugins API should be fairly easy to add lazy.nvim support.

how do we want to approach this though, change the extraPlugin API to properly support lazy.nvim or duplicate it in a mutually exclusive module to use lazy.nvim instead?

The main problem is with converting builtin plugins:

can lazy.nvim not coexist with native plugin loading?

mutually excluisve module sounds easier to migrate for the user.

can lazy.nvim not coexist with native plugin loading?

yes it can, I was thinking that perhaps adding lazy.nvim support would mean rewriting most of the lua code and maintaining two versions of the config, but on second thought, that's probably unnecessary.

Then I think we can look at implementing an alternative plugin system that utilizes lazy.nvim for those who prefer to use it. Though, I'd first like to finalize the nix -> lua libraries and finish #181.

Although we ended up not using Lazy, support for lazy-loading has been added as on #407. Closing as the main goal has been achieved.