Home

Awesome

Vim packager

preview-gif

This is Yet Another plugin manager for Vim/Neovim. It's written in pure vimscript and utilizes jobs and pack features.

Tested with:

Why?

There's a lot of plugin managers for vim out there.

Most popular one is definitely vim-plug. It's a great fully featured plugin manager. One thing that it does different is managing runtimepath manually. In latest Vim (and Neovim), packages can be added to runtimepath automatically by vim, just by placing the plugins in the right folder. This also has one more advantage: You can use (load) plugin manager only when you need it.

One plugin manager that utilizes the same features as this one is minpac, which I used for some time, and which inspired me to write this one (Many thanks to @k-takata). In minpac, I missed having the window which shows the process and information about all the plugins while they are being installed/updated/previewed. I contributed and added a status window, but it still has a bit bad looking install/update process (echoing information to command line). You can easily loose track what's happening in the process, and echoing causes a lot "Press enter to continue." messages, which blocks the process.

Packager utilizes jobs feature to the maximum, and runs everything that it can in a job, and shows whole process in the separate window, in a very similar way that vim-plug does.

Requirement

Installation

Mac/Linux

Vim

git clone https://github.com/kristijanhusak/vim-packager ~/.vim/pack/packager/opt/vim-packager

Neovim

git clone https://github.com/kristijanhusak/vim-packager ~/.config/nvim/pack/packager/opt/vim-packager

Windows

Vim

git clone https://github.com/kristijanhusak/vim-packager ~/vimfiles/pack/packager/opt/vim-packager

Neovim

git clone https://github.com/kristijanhusak/vim-packager ~/AppData/Local/nvim/pack/packager/opt/vim-packager

Example .vimrc content

Using setup function.

if &compatible
  set nocompatible
endif

function! s:packager_init(packager) abort
  call a:packager.add('kristijanhusak/vim-packager', { 'type': 'opt' })
  call a:packager.add('junegunn/fzf', { 'do': './install --all && ln -s $(pwd) ~/.fzf'})
  call a:packager.add('junegunn/fzf.vim')
  call a:packager.add('vimwiki/vimwiki', { 'type': 'opt' })
  call a:packager.add('Shougo/deoplete.nvim')
  call a:packager.add('autozimu/LanguageClient-neovim', { 'do': 'bash install.sh' })
  call a:packager.add('morhetz/gruvbox')
  call a:packager.add('lewis6991/gitsigns.nvim', {'requires': 'nvim-lua/plenary.nvim'})
  call a:packager.add('haorenW1025/completion-nvim', {'requires': [
  \ ['nvim-treesitter/completion-treesitter', {'requires': 'nvim-treesitter/nvim-treesitter'}],
  \ {'name': 'steelsojka/completion-buffers', 'opts': {'type': 'opt'}},
  \ 'kristijanhusak/completion-tags',
  \ ]})
  call a:packager.add('hrsh7th/vim-vsnip-integ', {'requires': ['hrsh7th/vim-vsnip'] })
  call a:packager.local('~/my_vim_plugins/my_awesome_plugin')

  "Provide full URL; useful if you want to clone from somewhere else than Github.
  call a:packager.add('https://my.other.public.git/tpope/vim-fugitive.git')

  "Provide SSH-based URL; useful if you have write access to a repository and wish to push to it
  call a:packager.add('git@github.com:mygithubid/myrepo.git')

  "Loaded only for specific filetypes on demand. Requires autocommands below.
  call a:packager.add('kristijanhusak/vim-js-file-import', { 'do': 'npm install', 'type': 'opt' })
  call a:packager.add('fatih/vim-go', { 'do': ':GoInstallBinaries', 'type': 'opt' })
  call a:packager.add('neoclide/coc.nvim', { 'do': function('InstallCoc') })
  call a:packager.add('sonph/onehalf', {'rtp': 'vim/'})
endfunction

packadd vim-packager
call packager#setup(function('s:packager_init'))

and run PackagerInstall or PackagerUpdate. See all available commands here

Or doing the old way that allows more control.

if &compatible
  set nocompatible
endif

" Load packager only when you need it
function! PackagerInit() abort
  packadd vim-packager
  call packager#init()
  call packager#add('kristijanhusak/vim-packager', { 'type': 'opt' })
  call packager#add('junegunn/fzf', { 'do': './install --all && ln -s $(pwd) ~/.fzf'})
  call packager#add('junegunn/fzf.vim')
  call packager#add('vimwiki/vimwiki', { 'type': 'opt' })
  call packager#add('Shougo/deoplete.nvim')
  call packager#add('autozimu/LanguageClient-neovim', { 'do': 'bash install.sh' })
  call packager#add('morhetz/gruvbox')
  call packager#add('lewis6991/gitsigns.nvim', {'requires': 'nvim-lua/plenary.nvim'})
  call packager#add('haorenW1025/completion-nvim', {'requires': [
  \ ['nvim-treesitter/completion-treesitter', {'requires': 'nvim-treesitter/nvim-treesitter'}],
  \ {'name': 'steelsojka/completion-buffers', 'opts': {'type': 'opt'}},
  \ 'kristijanhusak/completion-tags',
  \ ]})
  call packager#add('hrsh7th/vim-vsnip-integ', {'requires': ['hrsh7th/vim-vsnip'] })
  call packager#local('~/my_vim_plugins/my_awesome_plugin')

  "Provide full URL; useful if you want to clone from somewhere else than Github.
  call packager#add('https://my.other.public.git/tpope/vim-fugitive.git')

  "Provide SSH-based URL; useful if you have write access to a repository and wish to push to it
  call packager#add('git@github.com:mygithubid/myrepo.git')

  "Loaded only for specific filetypes on demand. Requires autocommands below.
  call packager#add('kristijanhusak/vim-js-file-import', { 'do': 'npm install', 'type': 'opt' })
  call packager#add('fatih/vim-go', { 'do': ':GoInstallBinaries', 'type': 'opt' })
  call packager#add('neoclide/coc.nvim', { 'do': function('InstallCoc') })
  call packager#add('sonph/onehalf', {'rtp': 'vim/'})
endfunction

function! InstallCoc(plugin) abort
  exe '!cd '.a:plugin.dir.' && yarn install'
  call coc#add_extension('coc-eslint', 'coc-tsserver', 'coc-pyls')
endfunction

" These commands are automatically added when using `packager#setup()`
command! -nargs=* -bar PackagerInstall call PackagerInit() | call packager#install(<args>)
command! -nargs=* -bar PackagerUpdate call PackagerInit() | call packager#update(<args>)
command! -bar PackagerClean call PackagerInit() | call packager#clean()
command! -bar PackagerStatus call PackagerInit() | call packager#status()

"Load plugins only for specific filetype
"Note that this should not be done for plugins that handle their loading using ftplugin file.
"More info in :help pack-add
augroup packager_filetype
  autocmd!
  autocmd FileType javascript packadd vim-js-file-import
  autocmd FileType go packadd vim-go
augroup END

"Lazy load plugins with a mapping
nnoremap <silent><Leader>ww :unmap <Leader>ww<BAR>packadd vimwiki<BAR>VimwikiIndex<CR>

After that, reload vimrc, and run :PackagerInstall. It will install all the plugins and run it's hooks.

If some plugin installation (or it's hook) fail, you will get (as much as possible) descriptive error on the plugin line. To view more, press E on the plugin line to view whole stdout.

Neovim Lua support

There is some basic Lua support for latest Neovim (0.5.0). Here's short example:

vim.cmd [[packadd vim-packager]]
require('packager').setup(function(packager)
  packager.add('kristijanhusak/vim-packager', { type = 'opt' })
  packager.add('junegunn/fzf', { ['do'] = './install --all && ln -s $(pwd) ~/.fzf'})
  packager.add('junegunn/fzf.vim')
  packager.add('vimwiki/vimwiki', { type = 'opt' })
  packager.add('Shougo/deoplete.nvim')
  packager.add('autozimu/LanguageClient-neovim', { ['do'] = 'bash install.sh' })
  packager.add('morhetz/gruvbox')
  packager.add('lewis6991/gitsigns.nvim', {requires = 'nvim-lua/plenary.nvim'})
  packager.add('haorenW1025/completion-nvim', {requires = {
    {'nvim-treesitter/completion-treesitter', {requires = 'nvim-treesitter/nvim-treesitter'}},
    {name = 'steelsojka/completion-buffers', opts = {type = 'opt'}},
    'kristijanhusak/completion-tags',
  }})
  packager.add('hrsh7th/vim-vsnip-integ', {requires = {'hrsh7th/vim-vsnip'} })
  packager['local']('~/my_vim_plugins/my_awesome_plugin')

  --Provide full URL; useful if you want to clone from somewhere else than Github.
  packager.add('https://my.other.public.git/tpope/vim-fugitive.git')

  --Provide SSH-based URL; useful if you have write access to a repository and wish to push to it
  packager.add('git@github.com:mygithubid/myrepo.git')

  packager.add('kristijanhusak/vim-js-file-import', { ['do'] = 'npm install', type = 'opt' })
  packager.add('fatih/vim-go', { ['do'] = ':GoInstallBinaries', type = 'opt' })
  packager.add('neoclide/coc.nvim', {branch = 'master', ['do'] = function(plugin)
    vim.loop.spawn('yarn', {
        args = {'install'},
        cwd = plugin.dir,
      })
  end})
  packager.add('sonph/onehalf', {rtp = 'vim/'})
end)

and run PackagerInstall or PackagerUpdate. See all available commands here

Functions

packager#setup(callback_function, opts)

This is a small wrapper around functions explained below. It does this:

  1. Adds all necessary commands. PackagerInstall, PackagerUpdate, PackagerClean and PackagerStatus
  2. Running any of the command does this:

packager#init(options)

Available options:

packager#add(name, options)

name - Url to the git directory, or only last part of it to use github.

Example: for github repositories, kristijanhusak/vim-packager is enough, for something else, like bitbucket, use full path https://bitbucket.org/owner/package

Options:

branch, tag and commit options go in certain priority:

Hooks can be defined in 3 ways:

  1. As a string that doesn't start with :. This runs the command as it is a shell command, in the plugin directory. Example:
call packager#add('junegunn/fzf', { 'do': './install --all'})
call packager#add('kristijanhusak/vim-js-file-import', { 'do': 'npm install' })
  1. As a string that starts with :. This executes the hook as a vim command. Example:
  call packager#add('fatih/vim-go', { 'do': ':GoInstallBinaries' })
  call packager#add('iamcco/markdown-preview.nvim' , { 'do': ':call mkdp#util#install()' })
  1. As a funcref that gets the plugin info as an argument. Example:
  call packager#add('iamcco/markdown-preview.nvim' , { 'do': { -> mkdp#util#install() } })
  call packager#add('junegunn/fzf', { 'do': function('InstallFzf') })

  function! InstallFzf(plugin) abort
    exe a:plugin.dir.'/install.sh --all'
  endfunction

packager#local(name, options)

Note: This function only creates a symbolic link from provided path to the packager folder

name - Full path to the local folder Example: ~/my_plugins/my_awesome_plugin

Options:

packager#install(opts)

This only installs plugins that are not installed

Available options:

When installation finishes, there are two mappings that can be used:

packager#update(opts)

This installs plugins that are not installed, and updates existing one to the latest (If it's not marked as frozen)

Available options:

When update finishes, there are two mappings that can be used:

packager#status()

This shows the status for each plugin added from vimrc.

You can come to this view from Install/Update screens by pressing D.

Each plugin can have several states:

packager#clean()

This removes unused plugins. It will ask for confirmation before proceeding. Confirmation allows selecting option to delete all folders from the list (default action), or ask for each folder if you want to delete it.

Commands

Commands are added only when using packager#setup or Lua require('packager').setup()

Configuration

Several buffer mappings are added for packager buffer by default:

To use different mapping for any of these, create filetype autocmd with different mapping.

For example, to use <c-h> instead of <c-j> for jumping to next plugin, add this to vimrc:

autocmd FileType packager nmap <buffer> <C-h> <Plug>(PackagerGotoNextPlugin)

Thanks to: