3

I recently learned the very hard way that vim-plug will only load plugins AFTER the vimrc is completely sourced: https://stackoverflow.com/questions/21322520/why-wont-vim-recognise-a-plugin-command-in-the-vimrc-but-it-will-recognise-it

The issue is that I have a plugin where I define functions that I would like to use inside my vimrc. Specifically my plugin is here: https://github.com/Erotemic/vimtk

and I would like to call the lines:

" Make default vimtk remaps.
:call VimTK_default_remap()

" Swap colon and semicolon
:call vimtk#swap_keys(':', ';')

" Register files you use all the time with quickopen
" (use <leader>i<char> as a shortcut to specific files
:call vimtk#quickopen(',', '~/.vimrc')
:call vimtk#quickopen('5', '~/.bashrc')

in my vimrc. These lines define special remappings, so I think it makes sense that they are called on startup time and not via an autocmd. My current workaround is just to explicitly source the plugin file: source $HOME/.vim/bundle/vimtk/plugin/vimtk.vim before calling these commands, but that's not very satisfying.

Is there a way to force plugins to load such that you can call their functions inside your vimrc?

7
  • Looking at the stackoverflow link...autocmd w. VimEnter event seems like a clean, straightforward solution....not hacky, IMO. "Forcing plugins to load" so they can use vimrc functions sounds more complicated, involved. Anyways, just some food for thought...your vim your rules.
    – B Layer
    Mar 21, 2020 at 23:36
  • 1
    Why do you need call VimTK_default_remap() in your vimrc? As it turns out, you have a "hook" in your plugin, so you can do let g:vimtk_default_mappings = 1 and postpone that call until the plugin is sourced normally. Also these swapkeys and quickopen look like an attempt to do easy things in a hard way. Just a couple of usual maps (or maybe special parameters to process in default_remap(), sort of let g:vimtk_extra_mappings = {':': ';'}, if you really like it this way), and you're done.
    – Matt
    Mar 22, 2020 at 5:08
  • Of course, the problem in general is nasty, but, I have to say, I don't like the design too, as xxx#swapkeys() and such seem pretty much useless everywhere except vimrc. So why then to have them in a plugin?
    – Matt
    Mar 22, 2020 at 5:10
  • @Matt, vim has no easy way to simply swap the functionality of two keys. A plugin seems like it is the best way to distribute that sort of "add-on" technology. There are a lot of tasks that are difficult to accomplish in the vimrc due to the nature of vimscript. I think a plugin is a natural way to expose a utility library to make those tasks easier (although it seems the design of vimscript might make that paradigm a non-starter).
    – Erotemic
    Mar 22, 2020 at 18:02
  • And what is so hard about it? So I look into your code and see you do 10(!) remaps per each keycode. What is it for?! noremap is equivalent of nnoremap and vnoremap and onoremap; vnoremap already stands for snoremap and xnoremap. Why inoremap and cnoremap at all? Etc. etc. It looks like a total mess for me. At the very most, it's four commands (two noremap and two noremap!) instead of twenty.
    – Matt
    Mar 22, 2020 at 18:54

1 Answer 1

4

These lines define special remappings, so I think it makes sense that they are called on startup time and not via an autocmd.

Note that there's a specific autocmd event which is essentially for "startup time", but after plugins were loaded and executed, which is the VimEnter event.

From :help VimEnter:

VimEnter: After doing all the startup stuff, including loading .vimrc files, executing the -c cmd arguments, creating all windows and loading the buffers in them.

Defining a function and having that executed in VimEnter would be an appropriate solution.

My current workaround is just to explicitly source the plugin file: source $HOME/.vim/bundle/vimtk/plugin/vimtk.vim before calling these commands

Slightly better would be:

runtime! plugin/vimtk.vim

Since that doesn't depend on the specific directory used by your plugin manager to store the vimtk plugin, it only depends on the specific name of the *.vim file inside it. It matches what Vim does when it loads plugins after the vimrc file is processed.

But it's still not very satisfying.

One issue with this approach is that the plugin file will be executed again when Vim loads all plugins. So it works better if the plugin file detects whether it was already sourced (for example, by setting a global variable) and skips execution if it was previously loaded.

and I would like to call the lines:

" Make default vimtk remaps.
:call VimTK_default_remap()

" Swap colon and semicolon
:call vimtk#swap_keys(':', ';')

Note that it should be possible to call the latter type of functions vimtk#... from your vimrc. These are autoloaded functions and as long as rhe plugins have been registered into 'runtimepath' (which happens early on, when you configure your plugin manager), Vim should be able to load them just fine.

Only issue is when those functions depend on some initialization that happens or is triggered from one of the plugin/*.vim files, as that's the step that will happen after vimrc is processed.

In this particular case, it's clear that global function VimTK_default_remap() is not autoloaded, so it must be registered by the plugin/vimtk.vim script and will only be accessible after its execution. (That's also often the case when plugins register new Vim user commands, that you might want to use during initialization, but using them from the vimrc file is problematic.)

One more option to consider is to write your late initialization commands into a separate file under ~/.vim/after/plugin/*.vim. This file will be executed at the same stage when the Vim plugins are loaded, but being on an after/ directory ensures it will be at the end of 'runtimepath', which means it will be executed after all plugins have been loaded and initialized.

For the specific case of your vimtk initialization, it turns out you don't really need to configure it by calling these functions.

Instead, as @Matt pointed out, you can do let g:vimtk_default_mappings = 1 and postpone that call until the plugin is sourced normally. And the swapkeys and quickopen can use a g:vimtk_extra_mappings dict specifying your custom mappings.

Since the initialization ordering of Vim plugins is very well known to plugin authors, they will usually (or often) export enough knobs through global variables that can be easily set from the vimrc file before plugin initialization happens.

So look for those first, as they'll often be able to solve what you're trying to configure without having to resort to using a VimEnter autocmd, or a vim script under ~/.vim/after, or a hack sourcing the plugin script from inside the vimrc file...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.