folke / lazy.nvim

💤 A modern plugin manager for Neovim
https://lazy.folke.io/
Apache License 2.0
13.74k stars 328 forks source link

feature: execute hook function when multiple plugins were all loaded #1531

Closed hoofcushion closed 2 months ago

hoofcushion commented 2 months ago

Did you check the docs?

Is your feature request related to a problem? Please describe.

If there is linkage between plugins, and the plugins do not depend on each other, then a hook function is necessary to execute the linkage logic between the plugins. Or it will be hard to manage the loading order of plugins by using the dependencies, because when the outer plugin were loaded, all dependencies will be force load too even they are not depend on each other.

Describe the solution you'd like

The user input will look like this:

local user_input={
 {"LuaSnip","nvim-cmp"},
 function() -- hook function
  local cmp=require("cmp")
  local luasnip=require("luasnip")
  cmp.setup({
   snippet={
    expand=function(args)
     luasnip.lsp_expand(args.body)
    end,
   },
  })
 end,
}

Explain: when LuaSnip and `nvim-cmp are both loaded, the hook function will be executed right after it, and the order doesn't matter.

The logic part will look like this:

local Loader=require("lazy.core.loader")
local Hooks={
 -- A hook spec is translated from user_input
 {
  cond={["LuaSnip"]=true,["nvim-cmp"]=true},
  func=function()
   local cmp=require("cmp")
   local luasnip=require("luasnip")
   cmp.setup({
    snippet={
     expand=function(args)
      luasnip.lsp_expand(args.body)
     end,
    },
   })
  end,
 },
}
local raw_load=Loader._load
--- override the logic of Loader._load
function Loader._load(plugin,reason,opts)
 raw_load(plugin,reason,opts)
 local name=plugin.name
 for key,hook in pairs(Hooks) do
  local cond=hook.cond
  cond[name]=nil
  if next(cond)==nil then
   hook.func()
   Hooks[key]=nil
  end
 end
end

Explain: when any plugin is loaded, try to iterate all hooks and set the cond of the plugin to nil, when all cond is satisfied (all nil), execute the hook function and remove the hook spec.

Describe alternatives you've considered

past

Additional context

These are some useful hook function I have.

--- A lualine, noice linkage hook
_={
  {"lualine.nvim","noice.nvim"},
  function()
   local noice=require("noice")
   local sections={
    {noice.api.status.command.get,cond=noice.api.status.command.has,color={fg="#ff9e64",bg="#4d461e"}},
    {noice.api.status.mode.get,   cond=noice.api.status.mode.has,   color={fg="#ff9e64",bg="#4d461e"}},
   }
   local lualine=require("lualine")
   local opts=lualine.get_config()
   vim.list_extend(opts.sections.lualine_x,sections) -- append the sections
   lualine.setup(opts) -- setup again
  end,
 },
}
--- A lualine, fittencode (ai tool) hook
_={
 {
  {"lualine.nvim","fittencode.nvim"},
  function()
   local fapi=require("fittencode.api").api
   local sections={
    {function() return "AI" end,cond=fapi.has_suggestions,color={fg="#37b0e7",bg="#101945"}},
   }
   local lualine=require("lualine")
   local opts=lualine.get_config()
   vim.list_extend(opts.sections.lualine_x,sections)
   lualine.setup(opts)
  end,
 },
}
--- A lazydev, nvim-cmp hook
_={
 {
  {"lazydev.nvim","nvim-cmp"},
  function()
   local cmp=require("cmp")
   local config=cmp.get_config()
   config.sources=config.sources or {}
   table.insert(config.sources,1,{
    name="lazydev",
    group_index=0,
   })
   cmp.setup(config)
  end,
 },
}
hoofcushion commented 2 months ago

Advantage: (generated by GPT)

  1. Decoupling Plugin Dependencies: It allows for the linking of plugins that do not have direct dependencies on each other. This is particularly useful when the functionality of one plugin needs to be integrated with another, but the relationship isn't naturally one of dependency.

  2. Controlled Initialization Order: The feature provides a way to manage the initialization order of plugins more flexibly. Even if the outer plugin is loaded, dependencies can be managed such that they are not forced to load unless necessary, providing better control over the plugin load sequence.

  3. Enhanced Customization: Users can define custom logic that should be executed only after certain plugins are loaded. This is useful for setting up configurations that involve multiple plugins, where the setup of one plugin may need to wait for another to be ready.

  4. Simplified Plugin Management: By using a hook function, users can encapsulate the logic for linking plugins into a single, manageable function. This simplifies the overall plugin management and reduces the complexity of the configuration scripts.

  5. Dynamic Configuration: The hook function can dynamically adjust the configuration of one plugin based on the presence and state of another. This allows for more complex and interactive setups that can adapt to the specific plugins that are being used.

  6. Improved User Experience: For end-users, this feature can lead to a smoother experience as it enables better integration between plugins, potentially reducing conflicts and ensuring that plugins work together seamlessly.

folke commented 2 months ago

Sorry, but no