How to load Vim plugins in Neovim

Can anyone provide some guidance on how to load Vim (Vim Script) plugins in Neovim?

Up till now, I’ve only ever used plugins written in Lua in Nvim and installed them using Packer, but now I’m trying to install a few Vim plugins like vim-expand-region and vindent which are written in Vim Script.

My current config is organized like this:

~/.config/nvim/
├── init.lua
├── lua
│   └── user
│       ├── alpha.lua
│       ├── autocommands.lua
│       ├── autopairs.lua
│       ├── bufferline.lua
│       ├── cmp.lua
│       ├── colorscheme.lua
│       ├── comment.lua
│       ├── dap
│       │   ├── dap.lua
│       │   ├── dap-python.lua
│       │   ├── init.lua
│       │   └── osv.lua
│       ├── gitsigns.lua
│       ├── hop.lua
│       ├── icons.lua
│       ├── illuminate.lua
│       ├── impatient.lua
│       ├── indentline.lua
│       ├── keymaps.lua
│       ├── lsp
│       │   ├── handlers.lua
│       │   ├── init.lua
│       │   ├── mason.lua
│       │   ├── null-ls.lua
│       │   ├── package-lock.json
│       │   └── settings
│       │       ├── pyright.lua
│       │       └── sumneko_lua.lua
│       ├── lualine.lua
│       ├── navic.lua
│       ├── neoclip.lua
│       ├── nvim-surround.lua
│       ├── nvim-tree.lua
│       ├── options.lua
│       ├── plugins.lua
│       ├── symbols-outline.lua
│       ├── tabnine.lua
│       ├── telescope.lua
│       ├── toggleterm.lua
│       ├── treesitter.lua
│       ├── vim-expand-region.lua
│       └── whichkey.lua
└── plugin
    └── packer_compiled.lua

As described in the nanotee guide, to load a .lua plugin, I run require "user.plugin" in my init.lua file. Then, in the plugin.lua file, I require the plugin itself with code like:

local status_ok, plugin = pcall(require, "plugin")
if not status_ok then
    vim.notify("WARNING: plugin.lua failed to load.")
    return
end

As I understand it, the require function searches the runtime path looking for a file called “plugin.lua” to load. In my case, my runtime path includes ~/.local/share/nvim/site/pack/*/start/* and each of the lua plugins installed with Packer contains a lua directory with a plugin.lua file (e.g. ~/.local/share/nvim/site/pack/*/start/plugin/lua/plugin.lua) which I assume gets sourced when the require function is called.

I tried installing vim-expand-region with Packer, which resulted in this structure:

~/.local/share/nvim/site/pack/packer/start/vim-expand-region/
├── autoload
│   └── expand_region.vim
├── doc
│   ├── expand_region.txt
│   └── tags
├── expand-region.gif
├── MIT-LICENSE.txt
├── plugin
│   └── expand_region.vim
└── README.md

From some of the instructions listed here it seems like the expand_region.vim file needs to be sourced. For Vim, it seems like the plugin should be added to ~/.vim/pack/bundle/start but that’s not where it gets installed with Packer.

In Vim, it seems like many people use the Plug package manager, but I’m not sure if it’s a good idea to mix multiple package managers (Packer + Plug) in one config.

Anyway, I’m clearly a little confused and would be grateful for any tips.

I do not know how you can get the status of vim plugins but you can add them using packer in the same way you add nvim plugins, can’t you ?

use("terryma/vim-expand-region")

in my config adds the vim plugin.

What have you tried so far ?

Hi @koalp, thanks for the help!

I had previously done what you suggested and added use { "terryma/vim-expand-region" } to my plugins.lua file. Packer successfully installed vim-expand-region at the path in the following screenshot.

What I’m stuck on is how to properly source a .vim file in a lua-centric config. As I mentioned above, for a .lua file, I’d use require as in the following snippet.

local status_ok, ver = pcall(require, "vim-expand-region")
if not status_ok then
    vim.notify("WARNING: vim-expand-region.lua failed to load.")
    return
end

Somehow, to this point I’ve never learned the vim equivalent of require that would source .vim files in the runtimepath.

What I don’t understand is why you want to source a .vim file.
Isn’t the plugin already installed and usable in your nvim ? I think it should.

You could maybe source the vim file you want using vim.cmd("source vim_script_path.vim")

Ok, yes, you’re right.

In the help (:h load-plugins) it states “all directories in ‘runtimepath’ will be searched for the “plugin” sub-directory and all files ending in “.vim” or “.lua” will be sourced (in alphabetical order per directory), also in subdirectories. First “*.vim” are sourced, then “*.lua” files.”

I thought that the plugin wasn’t working because repeated typing of “+” isn’t expanding the highlighted section.

I now have require "user.vim-expand-region" in my init.lua file.
In my vim-expand-region.lua file I am no longer trying to source anything.

Per the vim-expand-region documentation, I should expand the “text objects the plugin knows about with g:expand_region_text_objects”, e.g.:

" Default settings. (NOTE: Remove comments in dictionary before sourcing)
let g:expand_region_text_objects = {
      \ 'iw'  :0,
      \ 'iW'  :0,
      \ 'i"'  :0,
      \ 'i''' :0,
      \ 'i]'  :1, " Support nesting of square brackets
      \ 'ib'  :1, " Support nesting of parentheses
      \ 'iB'  :1, " Support nesting of braces
      \ 'il'  :0, " 'inside line'. Available through https://github.com/kana/vim-textobj-line
      \ 'ip'  :0,
      \ 'ie'  :0, " 'entire file'. Available through https://github.com/kana/vim-textobj-entire
      \ }

Since this is Vim Script code, I wrapped it with the vim.cmd() function to get the following:

vim.cmd([[
let g:expand_region_text_objects = {
      \ 'iw'  :1,
      \ 'iW'  :1,
      \ 'i"'  :1,
      \ 'i''' :1,
      \ 'i]'  :1,
      \ 'ib'  :1,
      \ 'iB'  :1,
      \ 'il'  :1,
      \ 'ip'  :1,
      \ 'ie'  :1,
      \ }
]])

However, in spite of this the plugin doesn’t appear to work.

Annnnnnd after looking at the issues for vim-expand-region, it looks like other people are having issues getting it to work in Neovim, so I guess it’s the plugin itself that is at fault. That’s a first for me.

Thanks again for the help @koalp

The let g:expand_region_text_objects = ... expression just creates a global Vim variable. In Lua you can assign to the vim.g table, no need to wrap Vim script code in Lua. See :h internal-variables, :h :g and :h vim.g for details.

vim.g.expand_region_text_objects = {
   iw = 1,
   -- ...
}

As for your general question, normally you do not need to source or activate a plugin manually. This is something that started occurring once Lua got introduced in Neovim because the Lua integration still had some holes in the start. It has become customary since then to have a setup function, but there is nothing in Neovim that actually necessitates such a function.

Vimscript plugins are already added to your rtp and need no extra requireing. They are usually configured via global varables vim.g.mypluginvar = ...