Closed vitaly closed 7 months ago
For me, the perfect solution would be for the User pluginname command to always be fired when a plugin loads, lazily or not.
Same here - but there are other posts that have requested this and since it doesn't look like something the @junegunn is keen on, I've sort of cobbled something using VimEnter
Plug 'something/somewhere', { 'on' : 'Vimenter'}
It's clunky - you don't have the 'on' trigger anymore and I'd prefer something in built, but hey - it gets the job done.
as I said, VimEnter
is a bit too late ;)
VimEnter is a bit too late
Why is it so? The existence of VimEnter
is the very reason I decided not to fire User autocmd for non-lazily loaded plugins.
https://github.com/junegunn/vim-plug/issues/702#issuecomment-521839867
Well, for starters, VimEnter
happens after executing -c
commands, so if you setup a command
In a hook it won’t be available yet.
Also, let’s say I’ve setup a plug-in to lazy load, but then I want to try to load it eagerly. Now, apart from the lazy option itself, I need to change the hook to a different event, it just doesn’t feel clean, especially if the hook config is in a different place.
Also, if the loading happens after VimEnter
already fired, e. g. after initial install, I’ll have 2 problems:
I'm using https://github.com/ouuan/vim-plug-config
That would a be a really nice future to have. It's indeed cumbersome to keep hopping back and forth to load/unload/configure a plugin
@junegunn Is there any plans to append such a feature?
I'm not convinced. This would be useful only if you frequently turn on and off on
/for
options. But why? And how often do you do that?
Also, please note that I no longer recommend using lazy-loading options.
https://github.com/junegunn/vim-plug/wiki/faq#when-should-i-use-on-or-for-option
I'm not convinced. This would be useful only if you frequently turn on and off
on
/for
options. But why? And how often do you do that?
I'm not requesting this feature as I'm already using ouuan/vim-plug-config to solve this problem.
But how does this have anything to do with toggling on
/for
options? I don't get it.
Because otherwise, you can just use VimEnter
for non-lazily loaded plugins, and User
for lazily loaded plugins.
Actually, most plugins are customized via g:***
variables, so autocmd
s are usually not even necessary.
It was explained in this thread above that VimEnter
could be too late. And I think maybe it could be easier to organize the configs if they follow the same format (the same event) so that we don't need to care about whether a plugin is lazy-loaded or not (so that maybe this process could be automated?).
BTW, perhaps my expectation is different from this issue. I'm looking for a way to manage configs modularly, i.e. the issue title. But according to the issue body, the feature being requested is to make User pluginname
always be fired when a plugin loads. It seems that the goal is to run commands after some plugins are loaded, which helps the OP to manage the configs modularly, but I personally don't need to run commands after some plugins are loaded. So the issue title may be misleading.
This would be useful only if you frequently turn on and off on/for options.
In this case, It's only requested for modular configuration.
you can just use VimEnter for non-lazily loaded plugins
As others have raised some gotchas that has to do with this autocmd, i'm a bit skeptic about that.
It was explained in this thread above that VimEnter could be too late
I can't think of a non-hypothetical scenario where that is really a problem. Can you give an example? For that to be an issue two conditions should be met.
call foo#bar#configure({ 'level': 1 })
) which can't be put between plug#begin
and plug#end
vim -c Foobar
)As I mentioned above, most plugins are configured via g:*
variables, and I rarely run a plugin command using -c
on the command-line, so I haven't run into such a case yet.
But if you do have such a problem, so you can't use VimEnter
, you can still set up a custom User
autocmd and trigger it after plug#end()
to defer the execution.
call plug#begin()
autocmd! User after_plug
Plug 'foo/bar'
autocmd User after_plug call bar#bar()
Plug 'foo/baz'
autocmd User after_plug call baz#baz()
call plug#end()
doautocmd User after_plug
The modular config feature may be useful for some people(heavy users). But it increases complexity. I think it is opposite of vim-plug's policy.
If you really need the feature and you have heavy plugin config, you should use other plugin manager.
call plug#begin()
autocmd! User after_plug
Plug 'foo/bar'
autocmd User after_plug call bar#bar()
Plug 'foo/baz'
autocmd User after_plug call baz#baz()
call plug#end()
doautocmd User after_plug
That seems like a lot of boilerplate. was hoping for a more straightforward solution.
Still, If what @Shougo mentioned
If you really need the feature and you have heavy plugin config, you should use other plugin manager.
would be the case, and ultimately settle for this way, then please close this issue.
That seems like a lot of boilerplate
I don't think so. The autocmd!
can be removed, and we are left with only one extra doautocmd
. I wouldn't say that's "a lot".
hoping for a more straightforward solution
I don't agree with this either. How is autocmd! User bar
more straightforward than autocmd User after_plug_or_whatever_name_you_prefer
? To understand what autocmd! User bar
does, you have to know in advance that a User autocmd with the name of a plugin is triggered by vim-plug when it's loaded. On the other hand, the suggested method is very straightforward if you know about autocmd
functionality which is a standard, built-in feature of vim itself you use with or without vim-plug.
Can you please give a real life example of this hack. I'm sorry, but i can't really follow along. I already looked doautocmd and User up, and it seems development-centric. I just ask for another syntactic entity like for instance plug-after, and simply place it anywhere outside of the begin and end block.
Can you please give a real life example of this hack
I don't know what exactly you mean by "this hack", but you can find autocmd
s in my vimrc all over the place. If you're not willing to learn how to use it, you're missing out.
Actually, most plugins are customized via g:*** variables, so autocmds are usually not even necessary.
@junegunn, I believe this is actually no longer the case if you are using neovim and a bunch of lua-based plugins that would require require("nvim-plugin").setup { ... }
to initialize. For these plugins, customization happens after the plugin is loaded. So I would say autocmd
seems the only way at this point to implement post-loading hook functionality (#702).
A more straightforward solution @z0xyz might have implied in their comment might be something like #702, Plug foo/bar, {'post': ':lua blahblah'}
, which I think is easier for beginners to use than autocmds.
As in @z0xyz's case, if one wants to execute such plugin config code, their execution needs to be deferred after the plugin has been loaded, otherwise lua modules cannot be imported. So you'll need autocmd
s to execute the plugin configs: autocmd VimEnter lua ...
-- I as well have a bunch of such autocmds in my config. @z0xyz may want to have a look at this yet another real-life example. Note that they are not required to be put inside the plug#begin..end
block.
In my use cases, I would want to lazy-load some heavy lua-based plugins (such as treesitters or nvim-cmp) to make the startup time even faster. So I agree that a consistent post-load hook mechanism would be a great feature to have.
I've looked through plug's code, and 2 things looked like they could be the solution
first, the
User pluginname
autocommand. That one would be perfect, but it's only fired for lazy loaded plugins. if the plugin is loaded right away, the command is not fired.another one is 'do' parameter of the
Plug
command, but this one only called on 'update'.I'm thinking about using
au VimEnter
but that might be too late for some plugins configuration I think.For me, the perfect solution would be for the
User pluginname
command to always be fired when a plugin loads, lazily or not
I propose the following event at the end of plug#end()
:
+++ plug.vim 2022-06-22 13:57:57.363352027 -0600
@@ -429,8 +429,9 @@
end
else
call s:reload_plugins()
endif
+ call s:doautocmd('User', 'VimPlugPluginsLoaded')
endfunction
function! s:loaded_names()
return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)')
The proposed event should work both when Vim starts and with commands like :PlugInstall!
.
VimEnter
won't work after :PlugInstall!
,User after_plug
example won't work after :PlugInstall!
.User pluginname
won't work after a :PlugInstall!
without a timer, due to the s:reload_plugins()
call. Hopefully the timer callback is after s:reload_plugins()
had finished, this is a race-condition.In my use-case, I have one plugin which depends on another plugin being loaded (i.e. s:reload_plugins()
finishing) prior to doing some things. The proposed User VimPlugPluginsLoaded
event works for my need.
Here is an minimal example vimrc of the User pluginname
, lazy-load, timer_start, messy workaround. PostBuild()
being called verifies that asyncrun.vim hadn't been reloaded by s:reload_plugins()
after AsyncRun had started (which breaks AsyncRun):
set nocompatible
function! PostBuild()
echom "do post build stuff"
endfunction
function! PrimeBuild(info)
echom 'Vim-Plug Post-Update... setup things for AsyncRun make'
autocmd User asyncrun.vim ++once execute('AsyncRun -mode=term -pos=tab -post=call\ PostBuild() @ echo "do stuff on terminal like make"')
call timer_start(2000, { -> plug#load('asyncrun.vim') })
endfunction
call plug#begin()
Plug 'skywind3000/asyncrun.vim', { 'on': [] }
Plug 'yaml/yaml-schema', { 'do': function('PrimeBuild') }
call plug#end()
Run the above example vimrc with :PlugInstall!
or :PlugInstall! yaml-schema
.
Note: yaml/yaml-schema
is just a placeholder repository in this minimal example, it isn't meaningful, you can replace with any other Vim plugin, I just picked a repo with one file to make things minimal and showcase the issue.
EDIT: To be crystal clear, the proposed vim-plug event makes it so the lazy-load and timer are not required and has no race-condition! Here is a patch making the change to the minimal example above:
@@ -6,11 +6,10 @@
function! PrimeBuild(info)
echom 'Vim-Plug Post-Update... setup things for AsyncRun make'
- autocmd User asyncrun.vim ++once execute('AsyncRun -mode=term -pos=tab -post=call\ PostBuild() @ echo "do stuff on terminal like make"')
- call timer_start(2000, { -> plug#load('asyncrun.vim') })
+ autocmd User VimPlugPluginsLoaded ++once execute('AsyncRun -mode=term -pos=tab -post=call\ PostBuild() @ echo "do stuff on terminal like make"')
endfunction
call plug#begin()
-Plug 'skywind3000/asyncrun.vim', { 'on': [] }
+Plug 'skywind3000/asyncrun.vim'
Plug 'yaml/yaml-schema', { 'do': function('PrimeBuild') }
call plug#end()
EDIT2: On thinking about this more, Shougo is right regarding the complexity need. I chose to migrate to using the dein.vim (and dein-ui.vim) package manager as it has hooks/complexity that meet my needs, which is different from the minimalist vim-plug philosophy.
Note that they are not required to be put inside the plug#begin..end block.
I mean the initial plugin inclusion still has be enclosed within the begin&end function calls, which doesn't really serve the purpose of having a totally separate interrelated chunks i.e generic settings, generic mapping, and plugin inclusion & its configuration.
The former solution of having virtually everything within the begin&end block, with the after-loading settings being deferred by prefixing them with autocmd User
, does work, but as i've already said, i was hoping for a new plugin-inclusion syntactic sugar, by which one can include any plugin anywhere, irrespective of the begin&end block.
One clarification.
Plugins are not actually loaded on plug#end()
when Vim is starting. plug#end()
only puts the plugin directories to &runtimepath
so Vim, not vim-plug, can load them after processing the whole vimrc. (See :help load-plugins
.)
1. Set the 'shell' and 'term' option
2. Process the arguments
3. Execute Ex commands, from environment variables and/or files
4. Load the plugin scripts.
5. Set 'shellpipe' and 'shellredir'
6. Set 'updatecount' to zero, if "-n" command argument used
7. Set binary options
8. Perform GUI initializations
9. Read the viminfo file
10. Read the quickfix file
11. Open all windows
12. Execute startup commands
You can only call autoload functions right after plug#end()
. Commands or non-autoload functions are not available at the point.
# Doesn't work
# E492: Not an editor command: FZF
vim -Nu <(cat << EOF
call plug#begin()
Plug 'junegunn/fzf'
call plug#end()
FZF
EOF
)
# Doesn't work either. fzf#run() is not an autoload function.
vim -Nu <(cat << EOF
call plug#begin()
Plug 'junegunn/fzf'
call plug#end()
call fzf#run(fzf#wrap())
EOF
)
# This works
vim -Nu <(cat << EOF
call plug#begin()
Plug 'junegunn/fzf'
call plug#end()
EOF
) -c FZF
I'm going to close this.
If you need to run some autoload functions to configure a plugin, but you want to specify that before plug#end()
for readability of the configuration file, use VimEnter
autocmd to defer the execution.
call plug#begin()
" autoload functions are available after plug#end(). You can defer the execution using VimEnter autocmd
Plug 'junegunn/vim-after-object'
autocmd VimEnter * silent! call after_object#enable('=', ':', '#', ' ', '|')
" Of course you can source an external file
Plug 'junegunn/fzf'
autocmd VimEnter * source fzf-configuation.vim
call plug#end()
In rare cases where you find VimEnter
is too late for your purpose (e.g. you want to start Vim with -c
commands), use a custom User autocmd as suggested above.
[!NOTE] vim-plug doesn't load non-lazy plugins by itself, it only updates the
&runtimepath
and the loading just happens afterward, after Vim has finished processing your Vim configuration file, not right afterplug#end()
. So there is no direct way to trigger some code after the plugins are loaded. If we want to do that, we would need to rely on anafter/plugin
script, but that is not possible because vim-plug is distributed as a single autoload script.
Is there a way to configure Plug in a modular way?
Right now the configuration for many plugins needs to be split into 2 pieces:
Plug
command. Those need to be betweenplug#begin
andplug#end
plug#end
.I'd like to be able to do something like that:
I've looked around in many popular vim configurations but I didn't find a good solution to this problem.
Some (like I do) split 'module' configuration in 2 files, one sources in between
plug
commands, and another is sourced after. This works, but it's not clean and harder to maintain.Others, like SpaceVim (I think), write the sourced files in a way that doesn't immediately define plugins or configuration, instead they define functions, that a centralized plugin manager can call later, e.g.
call foo_define_plugins()
and then afterplug#end
-call foo_configure()
. this also works, but, imho, it's too much boilerplate for a simple problem to solve.I've looked through plug's code, and 2 things looked like they could be the solution
first, the
User pluginname
autocommand. That one would be perfect, but it's only fired for lazy loaded plugins. if the plugin is loaded right away, the command is not fired.another one is 'do' parameter of the
Plug
command, but this one only called on 'update'.I'm thinking about using
au VimEnter
but that might be too late for some plugins configuration I think.For me, the perfect solution would be for the
User pluginname
command to always be fired when a plugin loads, lazily or not.I wander if I'm missing something? I'm not a vim expect, may be a perfectly simple solution already exists ;)