Closed fent closed 11 months ago
:h nvim_do_autocmd
in config?
Hello @fent,
The expected behavior you describe is already supported.
As the user, only you know how lazy.nvim
needs to load a specific plugin.
That said, the following issue is interesting: feature: Allow plugins to configure their own laziness
Some plugins depend on autocmd events such as BufEnter, FileType, etc that are set during that pugin's setup
The solution: Specify the proper event
instead of just VeryLazy
.
There are other mechanisms as well: ft
, cmd
, keys
.
Plugins are loaded automatically when required
, just setting lazy=true
is also an option.
You should only specify VeryLazy
when you know that the plugin is able to function correctly when its scheduled to load after VimEnter
/UIEnter
.
The source code of LazyVim
provides some good examples of how to load various popular plugins.
The lazy loading of nvim-lspconfig
is not broken.
This is a heavily optimized plugin, loaded on "BufReadPre", "BufNewFile"
in LazyVim.
When you open neovim without arguments, the plugin is not loaded. When the plugin loads it registers filetype autocommands
, for each lsp
you configured. Thus, the lsp
only kicks in when the filetype matches.
Sometimes, loading a plugin lazily is not the best option, due to the nature of that plugin. It is possible to tell lazy.nvim
that a plugin should not be lazy loaded. That's the default behavior when your spec does not contain any lazy handlers
(event
, ft
, cmd
, keys
)
Best regards!
:h nvim_do_autocmd in config?
the problem with this is
1) running vim.api.nvim_exec_autocmds(event)
will run all autocmds for that event, even ones set by other plugins, which can result in unexpected behavior. events.lua solves this by taking note of which autocmds exist before the plugin is loaded, and then filters those out
2) it would be nice if this works out of the box without extra setup by users. a user may assume lazy loading works for a plugin, and then get puzzled when it doesn't (example: https://www.reddit.com/r/neovim/comments/1308ie7/help_how_to_lazy_load_lspconfig/)
You should only specify VeryLazy when you know that the plugin is able to function correctly when its scheduled to load after VimEnter/UIEnter.
My goal is to load a plugin as lazily as possible, even if that plugin depends on BufReadPre
/BufNewFile
. another goal I have is to reduce neovim startup time. if it's an option to lazy load a plugin, and that plugin's function is not needed immediately at startup, we should provide the option to
@fent,
Just a non-authoritative opinion:
Do note that setting up the handlers wrapping ft
, event
, keys
or cmd
also takes time. Forcing the plugin to load on an event it's not designed for adds a lot of complexity.
You explicitly state that the lazy loading of nvim-lspconfig
is broken. As said, I don't think that is correct.
I also do not completely understand the title of your issue. In my opinion, all autocommands are fired. Lazy.nvim only catches the autocommands you configure in the spec. Perhaps, your issue should be of type feature
instead of bug
.
Regarding the user, the aforementioned feature request is still open.
That's because you load lspconfig on VeryLazy
. That indeed won't work.
Use this instead: event = { "BufReadPre", "BufNewFile" },
But I would like to lazy load it on VeryLazy
, to save on nvim startup time. that is one of the goals of this project right?
Here is a proof of concept I made for loading on VeryLazy
to show that it would work to re-execute autocmd events before it for plugins such a lspconfig
local M = {}
-- Events to check autocmds for. We target events that could fire before vim fully loads.
local events = { "BufEnter", "BufRead", "BufReadPost", "BufReadPre", "BufWinEnter", "FileType" }
local getAutocmdKey = function(autocmd)
return table.concat({
autocmd.event,
autocmd.group or "",
autocmd.id or "",
autocmd.command or "",
autocmd.buffer or "",
}, "-")
end
local existingAutocmds = {}
vim.api.nvim_create_autocmd("User", {
pattern = "VeryLazy",
once = true,
callback = function()
-- Take note of which autocmds exist before any plugins are loaded.
for _, autocmd in pairs(vim.api.nvim_get_autocmds({ event = events })) do
existingAutocmds[getAutocmdKey(autocmd)] = true
end
for _, autocmd in pairs(vim.api.nvim_get_autocmds({ event = events, buffer = vim.api.nvim_list_bufs() })) do
existingAutocmds[getAutocmdKey(autocmd)] = true
end
end
})
M.veryLazy = function(spec)
local originalConfig = spec.config
return vim.tbl_extend("force", spec, {
event = "VeryLazy",
config = function(plugin, opts)
if type(originalConfig) == "function" then
originalConfig(plugin, opts)
end
-- Execute any missed autocmd events that fired before the plugin was loaded,
-- and only for autocmds that were set by this plugin.
for _, autocmd in pairs(vim.api.nvim_get_autocmds({ event = events })) do
local autocmd_key = getAutocmdKey(autocmd)
if not existingAutocmds[autocmd_key] then
existingAutocmds[getAutocmdKey(autocmd)] = true
vim.api.nvim_exec_autocmds(autocmd.event, { group = autocmd.group })
end
end
for _, autocmd in pairs(vim.api.nvim_get_autocmds({ event = events, buffer = vim.api.nvim_list_bufs() })) do
local autocmd_key = getAutocmdKey(autocmd)
if not existingAutocmds[autocmd_key] then
existingAutocmds[getAutocmdKey(autocmd)] = true
vim.api.nvim_exec_autocmds(autocmd.event, { group = autocmd.group, buffer = autocmd.buffer })
end
end
-- Source any ftplugin files for opened buffers.
for _, bufnr in pairs(vim.api.nvim_list_bufs()) do
vim.api.nvim_buf_call(bufnr, function()
local ftplugin_file = plugin.dir .. "/ftplugin/" .. vim.bo.filetype .. ".vim"
if vim.fn.filereadable(ftplugin_file) == 1 then
vim.cmd("source " .. ftplugin_file)
end
end)
end
end
})
end
return M
If you do it as I mentioned, it IS lazy-loaded and will properly work.
But I would like to lazy load it on VeryLazy, to save one nvim startup time. that is one of the goals of this project right?
NO! The goal of this project is to provide a plugin manager and additionally multiple ways (like event
) to support lazy-loading plugins.
You can't just use VeryLazy
for everything.
Did you check docs and existing issues?
Neovim version (nvim -v)
0.9.0
Operating system/version
MacOS 13.4
Describe the bug
Some plugins depend on autocmd events such as
BufEnter
,FileType
, etc that are set during that pugin's setup. If these plugins are lazy loaded, they may miss some of these events being fired, and so, the plugin won't properly setup and may not work properly or at all.This is partly mitigated in https://github.com/folke/lazy.nvim/blob/main/lua/lazy/core/handler/event.lua by executing the autocmds in which the plugin is lazy loaded, but it's not enough. For example, a plugin lazy loaded by the
FileType
event may depend on theBufRead
event, which happens beforeFileType
. In this case, theBufRead
event, and any event beforeFileType
would have to be re-executed, not justFileType
.Here's the order of autocmd events that plugins can depend on (likely not complete) (source):
Buf even if these plugins are lazy loaded via the
VeryLazy
, a command, or a keymap, it may still need these events to fire for proper setup.example of plugins where lazy loading is broken:
Steps To Reproduce
nvim -u repro.lua
to open nvim and setup plugins:LspInstall lua_ls
to install the lsp servernvim -u repro.lua repro.lua
to open that lua file with nvim:LspInfo
will show that no lsp sersver is attached:e
on the file, then:LspInfo
does show lsp is attached (this is because :e will make all of the autocmds run again from re-opening the file)nvim -u repro.lua repro.lua
againExpected Behavior
to be able to lazy load the plugin and have it work
Repro