Donnie West

Enhance Your Workflow with these Vim Plugins

1/20/2019

Setting up Vim can be a struggle: configuration is in the eclectic Vimscript language and there are a huge amount of plugins. It can be akin to setting up an IDE from scratch. In this guide, we will break down the best-in-class plugins for various aspects of Vim development so you can get started easily.

Prerequisites:

  1. A recent version of Neovim (this can be used within regular Vim with some effort but for best results use Neovim)
  2. Mac OSX or Linux (This could be applied to a Windows computer, but I do not have one to test)

Plugin Manager

vim-plug

Alternatives:

dein.vim

vim-pathogen

VAM

voom

While Vim has its own built-in plugin manager, it can be a bit of a hassle to manage yourself. Thankfully, vim-plug simplifies this process so that all your configuration happens in one place: your Vim config. While there are others that can do the same, vim-plug seems to have the greatest community support and supports parallel plugin download. vim-plug accomplishes this by using Neovim (or Vim 8) jobs support and can fall back to legacy support via python, ruby or other languages supported by your version of Vim. It has many advanced features that I can't cover here, but you can find in their documentation. To begin using vim-plug, we will first create a basic init.vim in ~/.config/nvim/init.vim that has the following contents:

" Install vim-plug if not installed
if empty(glob('~/.config/nvim/autoload/plug.vim'))
  silent !curl -fLo ~/.config/nvim/autoload/plug.vim --create-dirs
    \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  autocmd VimEnter * PlugInstall
endif

call plug#begin()


call plug#end()

This automatically downloads and installs vim-plug when Vim launches. Plugins are added between the calls to plug#begin() and plug#end() and are generally specified with a reference to their Git repository. For instance, to install Vim Github Dashboard you would add Plug 'https://github.com/junegunn/vim-github-dashboard.git' to your config like so:

" Install vim-plug if not installed
if empty(glob('~/.config/nvim/autoload/plug.vim'))
  silent !curl -fLo ~/.config/nvim/autoload/plug.vim --create-dirs
    \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  autocmd VimEnter * PlugInstall
endif

call plug#begin()

Plug 'https://github.com/junegunn/vim-github-dashboard.git'

call plug#end()

And for Github repositories, you can shorten that entry to:

Plug 'juneguun/vim-github-dashboard'

To see more of what vim-plug can do, check out their documentation

Intellisense / Autocomplete / OmniCompletions

ncm2

Alternatives

deoplete

YouCompleteMe

asyncomplete.vim

Autocompletion or Omnicompletions on Vim are difficult and unintuitive to setup manually. Vim provides omnifuncs that are called with Ctrl + O Ctrl + X that activates a menu providing all possible completions generated by the single active omnifunc. Mixing and matching omnifunc results is not possible out of the box. Automatically launching this completion menu on language specific triggers is difficult. Finally, even if you go through all of this pain, the omnifuncs are synchronous by default and will freeze Vim while generating completions.

To solve this, we turn to ncm2. Ncm2 (formerly known as "nvim-completion-manager") provides intuitive and asyncronous autocomplete by default. Ncm2 has a set of plugins that provide language-specific triggers and completions that won't freeze your editor. For instance, JavaScript code will automatically provide the completion menu when you type . to call a method on an object.

To get started, add the following to your configuration:

call plug#begin()

Plug 'ncm2/ncm2'
Plug 'roxma/nvim-yarp'

" enables completion of file paths
Plug 'ncm2/ncm2-path'

call plug#end()

" enable ncm2 for all buffers
autocmd BufEnter * call ncm2#enable_for_buffer()

" set completeopt to be what ncm2 expects
set completeopt=noinsert,menuone,noselect

For more information, visit the ncm2 wiki page for a list of their other sources or features that you can use. My personal favorite is the ability to determine whether you are editting JavaScript or HTML while in an HTML file.

A Note: ncm2 is a young project with a responsive maintainer. It works very well for my purposes but the larger Neovim/Vim communities tend to use Deoplete or YouCompleteMe. They may better suit your needs. I prefer ncm2 mainly because the experience requires less configuration and Deoplete freezes my editor when it initializes. However, there are work-arounds that may work for you.

Bonus

To get consistent tooling across all languages and all editors, take a look at the language server protocol, or LSP for short, developed by Microsoft for their VSCode editor. Instead of each editor recreating the same functionality as all other editors, each programming language can develop an LSP-compliant set of tools which each editor will automatically use.

For ncm2, I recommend vim-lsp. Vim-lsp has a little more configuration than the community favorite, LanguageClient-neovim, but it seems to work more consistently with ncm2 with more flexibility. On the contrary, LangugageClient-neovim is faster than the all-Vimscript vim-lsp and is the only choice for Deoplete.

Neovim will soon have its own built-in LSP in version 0.4. Both ncm2 and Deoplete will support it. Once Neovim merges the built-in LSP support, we will see more autocomplete solutions in this space, with broader support for all languages.

Linters

ALE

Alternatives

neomake

syntastic

Accio

call plug#begin()

Plug 'w0rp/ale'

call plug#end()

ALE leverages a strong community to provide the most pragmatic linting framework with the broadest language support currently available for Vim. ALE's docs provide some insight into their design philosophy, which includes providing default settings that are akin to the linter of other popular editors. For those that don't like the defaults, they can selectively disable any part of ALE they want. Most people will find the defaults a fantastic experience that require little customization.

Additionally, ALE has the largest selection of linters available out-of-the-box compared to any other linting solution (except, perhaps, syntastic which lacks asynchronous Vim support). It will automatically pick up tools that are installed on your computer for the file type you are editting and even handles hard-to-configure projects like JavaScript (which can have both global and locally installed versions of linters) like a champ.

Perhaps the only thing that can be said against ALE is that it DOES do all of this automatically. If you don't like the default values picked up by ALE and that it's set up by default to lint files when saved, you might prefer something more like Neomake which doesn't do all of this for you.

Formatters

Neoformat

Alternatives

Autoformat

ALE

call plug#begin()

Plug 'sbdchd/neoformat'

call plug#end()

" Format on save, if desired
augroup fmt
  autocmd!
  autocmd BufWritePre * undojoin | Neoformat
augroup END

" To Run Manually
nnoremap <leader>fm :Neoformat<CR>

Neoformat is a flexible tool for running formatters on your code and it supports the most tooling for the most programming languages. A formatting tool differs from the linting tools we mentioned previously by being primarily concerned with the appearance of your code as opposed to coding errors. This is why ALE is on this list: while the tool runs linters, it can also run some formatters by using :ALEFix since those lines are often blurred.

Status Lines

lightline

Alternatives

airline

powerline

call plug#begin()

Plug 'itchyny/lightline.vim'
Plug 'mgee/lightline-bufferline' " For tabs on top

" Be sure to install fugitive for the below config to work and provide git status information
" Plug 'tpope/vim-fugitive'

call plug#end()

let g:lightline = {
      \ 'separator': { 'left': '', 'right': '' },
      \ 'subseparator': { 'left': '', 'right': '' },
      \ 'tabline': {
      \   'left': [['buffers']],
      \   'right': [[ 'exit' ]],
      \ },
      \ 'active': {
      \   'left': [ [ 'mode', 'paste' ],
      \             [ 'gitbranch', 'readonly', 'filename', 'modified'] ]
      \ },
      \ 'component_function': {
      \   'gitbranch': 'fugitive#head'
      \ },
      \ 'component_expand': {
      \   'buffers': 'lightline#bufferline#buffers',
      \ },
      \ 'component_type': {
      \   'buffers': 'tabsel'
      \ },
      \ }
let g:lightline#bufferline#shorten_path = 1

While most people in the community prefer airline, lightline is an excellent alternative. Lightline eschews preconfiguring everything for you in favor of a lightweight experience that can be configured with any number of external plugins or user supplied functions

Bonus

vim-devicons

call plug#begin()

Plug 'ryanoasis/vim-devicons'

call plug#end()

let g:lightline#bufferline#enable_devicons = 1

By adding vim-devicons, you can get filetype icons in your lightline or other supported tooling.

Code Search

FZF

Alternatives

Ctrl+P

Vim Grepper

call plug#begin()

Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
Plug 'junegunn/fzf.vim'

call plug#end()

nnoremap <C-p> :Files<ENTER>
if has('nvim')
  aug fzf_setup
    au!
    au TermOpen term://*FZF tnoremap <silent> <buffer><nowait> <esc> <c-c>
  aug END
end

While I recommend tools like File Beagle or just plain :e ./path/to/file to explore project filesystems, tools like FZF are a superior choice for general fuzzy file searching throughout your project. By following the directions on their README you can also get FZF up and running in your terminal to do full system-wide fuzzy finding. Long time VIM users might also be familiar with Ctrl-P and the provided config above provides the same keybindings.

Some other cool tricks with FZF:

By adding the following config to your .zshrc or .bashrc you can configure FZF to use rg for faster file searching

export FZF_DEFAULT_COMMAND='rg --files --hidden --follow --glob "!.git/*"'

By adding the following snippet of code to your vimrc with the aforementioned vim-devicons you can get the filetype icon before the filename in FZF's fuzzy search

function! Fzf_dev()
  function! s:files()
    let files = split(system($FZF_DEFAULT_COMMAND), '\n')
    return s:prepend_icon(files)
  endfunction

  function! s:prepend_icon(candidates)
    let result = []
    for candidate in a:candidates
      let filename = fnamemodify(candidate, ':p:t')
      let icon = WebDevIconsGetFileTypeSymbol(filename, isdirectory(filename))
      call add(result, printf("%s %s", icon, candidate))
    endfor

    return result
  endfunction

  function! s:edit_file(item)
    let parts = split(a:item, ' ')
    let file_path = get(parts, 1, '')
    execute 'silent e' file_path
  endfunction

  call fzf#run({
        \ 'source': <sid>files(),
        \ 'sink':   function('s:edit_file'),
        \ 'options': '-m -x +s',
        \ 'down':    '40%' })
endfunction


command! FilesWithIcon :call Fzf_dev()

Conclusion

Setting up Vim shouldn't be a struggle. With these cutting edge plugins you can supercharge your Vim workflow.

Github@_DonnieWestSay Hello