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:
Alternatives:
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
Alternatives
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.
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.
Alternatives
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.
Alternatives
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.
Alternatives
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
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.
Alternatives
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()
Setting up Vim shouldn't be a struggle. With these cutting edge plugins you can supercharge your Vim workflow.