How can I test for plugins and only include them if they exist in .vimrc?

14

5

In my .vimrc I am trying to use ftplugin and obviously use some commands relating to that under the assumption that it was loaded successfully. However, I have now encountered a few old machines that don't have the plugin installed. Can I somehow make loading of this plugin conditional and add filetype on and similar directives into the same conditional block?

I have seen there are conditions for color schemes and the Vim version, but I haven't seen an example that would check for the plugin (or didn't recognize it).

NB: Be gentle, I am a VimScript beginner.

0xC0000022L

Posted 2013-02-14T23:55:11.867

Reputation: 5 091

1Note that plugins are loaded after your ~/.vimrc, so you won't be able to test for the effects of a plugin within your ~/.vimrc unless you test for the existence of the plugin file or defer the test until after plugins have been loaded with an autocommand such as VimEnter. – garyjohn – 2013-02-15T01:16:32.787

@garyjohn: aha, that's interesting. Because this kind of contradicts the existing answer. Could you write it up as an answer? – 0xC0000022L – 2013-02-15T01:51:59.887

I've edited my answer to somewhat address that issue. – qqx – 2013-02-15T02:10:30.140

My comment didn't contradict qqx's answer; it was meant to draw attention to a point that could have been missed if one didn't read qqx's answer carefully or made incorrect inferences from it. The answer was good to start with and is even clearer now. – garyjohn – 2013-02-15T03:08:29.177

Answers

20

You can wrap that block in a conditional which uses the exists() function to check if a variable, command or function defined by the plugin is known to vim.

Here are a couple bits that I have in files under ~/.vim:

" after/plugin/speeddating.vim
if exists(':SpeedDatingFormat')
    SpeedDatingFormat %-d %B %Y
endif

" ftplugin/ruby.vim
if exists('g:loaded_surround') && !exists('b:surround_'.char2nr(':'))
  let b:surround_{char2nr(':')} = ":\r"
endif

Note that the above bits are in files that get evaluated after normal plugins, here an ftplugin, and a file in the after/plugin directory.

Another option would be to use try/catch blocks, although this requires at least vim 7.0:

if v:version >= 700
    try
        runtime bundle/pathogen/autoload/pathogen.vim
        call pathogen#infect()
    catch
    endtry
endif

Once something in the try section of that block fails it will skip to the catch section. Since the catch section is empty, it will just continue on with the remainder of the initialization file after the endtry statement.

Since this is manually loading code rather than relying on a plugin being already loaded, this can be done in the .vimrc file itself.

qqx

Posted 2013-02-14T23:55:11.867

Reputation: 2 603

8

My preferred method is just to check for the existence of the plugin file. I find this simpler.

if !empty(glob("path/to/plugin.vim"))
   echo "File exists."
endif

user3751385

Posted 2013-02-14T23:55:11.867

Reputation: 191

Sounds reasonable, but what is the base path? Is it automatically the Vim home (i.e. usually ~/.vim)? – 0xC0000022L – 2020-01-31T08:04:28.360

Depends on your .vimrc configuration and your package management preferences. I do this: `if filereadable($HOME."/.vim/plugins.vim")

source ${HOME}/.vim/plugins.vim

endif` – user3751385 – 2020-02-01T06:09:05.450

thanks, awesome. I was more worried that there was some base path implied by what you gave. – 0xC0000022L – 2020-02-02T12:46:30.670

4

I wanted to achieve this while keeping my Vim configuration together within .vimrc, rather than in a bunch of after/ directories. This is the solution I came up with:

  1. Check each plugin's existence by checking for any single command that it provides with exists(), and set its options if it does exist. (This is just like in the accepted answer.)

  2. Put all the options set in the above manner within a function (called SetPluginOptionsNow() in my code).

  3. Call this function on the VimEnter event, which is triggered while entering a new Vim session - but crucially, after the plugins have all been loaded. Because of this fact, our exists() checks can check for the plugin functions without a problem.

Here's a sample from that part of my .vimrc.

""" PLUGIN-SPECIFIC OPTIONS
" These are "supposed to be" set in after/plugin directory, but then
" cross-platform synchronization would get even messier. So, au VimEnter it is. 

function! SetPluginOptionsNow()


    " NERDTree Options
    if exists(":NERDTree")
        map <F10> :NERDTreeToggle<CR>
    endif

    " Syntastic Options
    if exists(":SyntasticCheck")
        let g:syntastic_stl_format = '[Syntax: line:%F (%e+%w)]'
        set statusline+=%#warningmsg#
        set statusline+=%{SyntasticStatuslineFlag()}
        set statusline+=%*
        " and so on...

endfunction

au VimEnter * call SetPluginOptionsNow()
""" END OF PLUGIN-SPECIFIC OPTIONS

sundar - Reinstate Monica

Posted 2013-02-14T23:55:11.867

Reputation: 1 289

this answer doesn't place nice with vim-airline. In particular, waiting for the VimEnter event to specify things like airline_theme seems to induce a bunch of errors... I'm not really sure why. – StevieP – 2016-03-09T21:15:12.660

3

Yet another alternative is using :silent! {cmd}, which suppresses the error when {cmd} does not exist. The main benefit is that it's a short single command. This even works in Vim 6, and is great for optional stuff.

For example, it is used by plugins that use Tim Pope's repeat.vim to make mappings repeatable.

Ingo Karkat

Posted 2013-02-14T23:55:11.867

Reputation: 19 513

It's :silent!, not !silent, and it applies to all contained commands, except for when :unsilent is used somewhere inside. (But that's rare.) – Ingo Karkat – 2013-02-15T14:08:03.163

2

Initially posted in another question: https://stackoverflow.com/a/48178537/2843583

Just as an alternative you may also use a regexp to decide if the plugin at hand is in your runtimepath:

if &rtp =~ 'plugin-name'
    ...
endif

This has the advantage that it works with plugins that only have vimscript code in the autoload directory, which in turn can't be detected when .vimrc is initially parsed since the autoload snippets are loaded at the time of a function call.

bergercookie

Posted 2013-02-14T23:55:11.867

Reputation: 480