My VIM setup

If you don’t use VIM, learn VIM!

It’s quite daunting learning this text editor. When I was starting up with Linux, a colleague launched vim on my terminal and asked me to quit out of it. I was pressing Ctrl+C, escape, Ctrl+C AND escape and all kinds of key combinations but I simply could not figure it out without cheating (yes, the Internet)!

I then discovered that typing vimtutor will launch the best tutorial you will ever have, I highly encourage you to do so before proceeding with this post.

VIM is extremely powerful on its own, but more magic comes in the form of plugins that attach to it. Below you can find my configuration but first, let’s add a plugin manager.

I started with vim-plug and it was so simple to use that I stuck with it. To install, simply copy the following in your terminal:

curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

After installing vim-plug, you need to edit your ~/.vimrc file. Let’s add the airline plugin, which adds a lightweight status bar with nice information at the bottom of the window:

# Plugins will be downloaded under the specified directory.
call plug#begin('~/.vim/plugged')

" Declare the list of plugins
Plug 'vim-airline/vim-airline'

" List ends here. Plugins become visible to Vim after this call.
call plug#end()

Note that lines starting with " are comments, and therefore “ignored” by the configuration

Relaunch vim and voila! If you don’t see the status bar, type the following inside vim:

:PlugInstall and hit Enter (don’t forget the : at the beginning of the command.) This will load the plugins included in the .vimrc file.

This is what vim looked liked before:

vim_before

And this is what it looks like now:

vim_after

Huge difference, right?

Here’s my full .vimrc configuration:


" Make Pretty
set number
set ai
set tabstop=4
highlight LineNr term=bold cterm=NONE ctermfg=DarkGrey ctermbg=NONE gui=NONE guifg=DarkGrey guibg=NONE
let mapleader=","
set encoding=UTF-8
 

" Move between tabs with F8 and Shift-F8.
set switchbuf=usetab
nnoremap <C-t> :tabnew<CR>
inoremap <C-t> <Esc>:tabnew<CR>
nnoremap <F8> :sbnext<CR>
nnoremap <S-F8> :sbprevious<CR>
 

" Press F4 to toggle highlighting on/off, and show current value.
:noremap <F4> :set hlsearch! hlsearch?<CR>
 

" NERDTree stuff
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif
map <C-n> :NERDTreeToggle<CR>
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif
 

" Plugins will be downloaded under the specified directory.
call plug#begin('~/.vim/plugged')
 

" Declare the list of plugins.
Plug 'tpope/vim-sensible'
Plug 'junegunn/seoul256.vim'
Plug 'vim-airline/vim-airline'
Plug 'vim-airline/vim-airline-themes'
Plug 'jreybert/vimagit'
Plug 'tpope/vim-fugitive'
Plug 'preservim/nerdtree'
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
Plug 'junegunn/fzf.vim'
Plug 'ryanoasis/vim-devicons'
 

" List ends here. Plugins become visible to Vim after this call.
call plug#end()
 

" Files + devicons + floating fzf
function! FzfFilePreview()
  let l:fzf_files_options = '--preview "bat --theme="OneHalfDark" --style=numbers,changes --color always {3..-1} | head -200" --expect=ctrl-v,ctrl-x'
  let s:files_status = {}
 

  function! s:cacheGitStatus()
    let l:gitcmd = 'git -c color.status=false -C ' . $PWD . ' status -s'
    let l:statusesStr = system(l:gitcmd)
    let l:statusesSplit = split(l:statusesStr, '\n')
    for l:statusLine in l:statusesSplit
      let l:fileStatus = split(l:statusLine, ' ')[0]
      let l:fileName = split(l:statusLine, ' ')[1]
      let s:files_status[l:fileName] = l:fileStatus
    endfor
  endfunction
 

  function! s:files()
    call s:cacheGitStatus()
    let l:files = split(system($FZF_DEFAULT_COMMAND), '\n')
    return s:prepend_indicators(l:files)
  endfunction
 

  function! s:prepend_indicators(candidates)
    return s:prepend_git_status(s:prepend_icon(a:candidates))
  endfunction
 

  function! s:prepend_git_status(candidates)
    let l:result = []
    for l:candidate in a:candidates
      let l:status = ''
      let l:icon = split(l:candidate, ' ')[0]
      let l:filePathWithIcon = split(l:candidate, ' ')[1]


      let l:pos = strridx(l:filePathWithIcon, ' ')
      let l:file_path = l:filePathWithIcon[pos+1:-1]
      if has_key(s:files_status, l:file_path)
        let l:status = s:files_status[l:file_path]
        call add(l:result, printf('%s %s %s', l:status, l:icon, l:file_path))
      else
        " printf statement contains a load-bearing unicode space
        " the file path is extracted from the list item using {3..-1},
        " this breaks if there is a different number of spaces, which
        " means if we add a space in the following printf it breaks.
        " using a unicode space preserves the spacing in the fzf list
        " without breaking the {3..-1} index
        call add(l:result, printf('%s %s %s', ' ', l:icon, l:file_path))
      endif
    endfor


     return l:result
   endfunction 

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


    return l:result
  endfunction 

  function! s:edit_file(lines)
    if len(a:lines) < 2 | return | endif
 

    let l:cmd = get({'ctrl-x': 'split',
                 \ 'ctrl-v': 'vertical split',
                 \ 'ctrl-t': 'tabe'}, a:lines[0], 'e')
 

    for l:item in a:lines[1:]
      let l:pos = strridx(l:item, ' ')
      let l:file_path = l:item[pos+1:-1]
      execute 'silent '. l:cmd . ' ' . l:file_path
    endfor
  endfunction
 

  call fzf#run({
        \ 'source': <sid>files(),
        \ 'sink*':   function('s:edit_file'),
        \ 'options': '-m --preview-window=right:70%:noborder --prompt Files\> ' . l:fzf_files_options,
        \ 'down':    '40%',
        \ 'window': 'call FloatingFZF()'})


 endfunction 

I will not go through all the plugins in this post but I encourage you to look them up and experiment.

However, some basic information regarding what the above configuration applies:

  • set number will set line numbers
  • Ctrl-T will launch a new tab, and F8 will switch between tabs. Shift-F8 to go backwards.
  • If you search for a keyword (usually by typing / followed by the keyword and then Enter), you can toggle highlighting all other similar keywords with F4
  • NERDTree is also amazing. If you simply launch vim without specifying a file, NERDTree will display a tree explorer that you can use to select whatever you need to edit.
    You can also call it by typing :NERDTree in Normal mode or toggle it with Ctrl+N
  • FZF (or fuzzy finder) is a whole different beast and deserves a post on its own but, as a starting point, you can use :FZF to find files in your working directory. Esc will close that search. Note that for this functionality you may need to install FZF from the link.

I hope this will help you kickstart your vim experience! Again, I highly encourage you to google everything and read as much as you can, add/remove lines and functions from your .vimrc config and see where things break.

Because hey, you gotta break some eggs!

To reset everything, simply empty out your .vimrc file and reload vim.

Finally, the only way to truly learn vim and harness its power is by using it for whatever editing purpose you can think of.

Enjoy!

Leave a Comment