Vim Minimalist


hammer

Vim, the god of editor, is popular in developers and hackers. I use vim over two decade (when I am in the college, I already use vim to write VHDL code to programming the chip).

A lot of people install many plugins into vim, and even turn vim into IDE, which is cumbersome and unnecessary in my eye. In my daily life, vim is only suitable for terminal usage (on Windows, I would rather use vscode and pycharm), so why not just keep it simple and be a minimalist? Just reuse anything from vanilla vim, and add plugins only if you have to. Currently, I only install two plugins: ctrlp and vim-fugitive.

Keep the screen clean (even turning off syntax highlight), for me, it could keep me focus on the code only.

Vim has many many topics, and I only talk about my own experience.

Plugin manager

Since version 8, vim has builtin plugin manager, so just ignore all sorts of wild ones.

For example, to install ctrlp, download it into specific directory is enough.

git clone https://github.com/ctrlpvim/ctrlp.vim ~/.vim/pack/plugins/start/ctrlp

Basic settings

set nocompatible

" import default settings
source $VIMRUNTIME/vimrc_example.vim

" use 4 spaces instead of tab
set expandtab
set shiftwidth=4
set softtabstop=4
set tabstop=4

" While searching though a file incrementally highlight matching characters as you type.
set incsearch

" Override the ignorecase option if searching for capital letters.
" This will allow you to search specifically for capital letters.
set smartcase

" Use highlighting when doing a search.
set hlsearch

" when you press *, just highlight and stay still
nnoremap * :keepjumps normal! mi*`i<CR>

" wrap lines
autocmd OptionSet * set wrap

" highlight spaces at the end of line
highlight WhiteSpaceEOL ctermbg=darkgreen guibg=lightgreen
match WhiteSpaceEOL /\s$/
autocmd WinEnter * match WhiteSpaceEOL /\s$/

" vim default leader key is \
" press \p when you paste text from outside to keep indents,
" and press it again to disable paste mode
nnoremap <Leader>p :set paste!<Cr>

" press \r to avoid misoperation
" and press again if you really need to do modification
nnoremap <Leader>r :set readonly!<Cr>

" press ctrl-l to clean search highlight
nnoremap <silent> <C-l> :<C-u>nohlsearch<CR><C-l>

" after you paste something, press gb to select it in visual mode
" so that you could format it or do something else
nnoremap <expr> gb '`[' . strpart(getregtype(), 0, 1) . '`]'

File management

netrw is vim’s builtin file explorer. It’s good enough. No need to install nerdtree or other plugins.

It’s boring when you need to traverse deep directory tree and do a lot of create/move/rename/delete file operations in the shell. Then netrw is your best friend.

Just press :E to enter netrw window. Like normal window, you could press /pattern to locate the desired file.

Check this gist for detailed shortcuts:

https://gist.github.com/danidiaz/37a69305e2ed3319bfff9631175c5d0f

But netrw does not support deleteing non-empty directory.

Here is the workaround, so that you could press FF to do so.

function! NetrwRemoveRecursive()
  if &filetype ==# 'netrw'
    cnoremap <buffer> <CR> rm -r<CR>
    normal mu
    normal mf
    try
      normal mx
    catch
      echo "Canceled"
    endtry

    cunmap <buffer> <CR>
  endif
endfunction

function! NetrwMapping()
    nmap <buffer> FF :call NetrwRemoveRecursive()<CR>
endfunction

augroup netrw_mapping
    autocmd!
    autocmd filetype netrw call NetrwMapping()
augroup END

ctrlp

https://github.com/ctrlpvim/ctrlp.vim

Press ctrl-p to open file in fuzzy way.

let g:ctrlp_map = '<c-p>'
let g:ctrlp_cmd = 'CtrlPMixed'
let g:ctrlp_user_command = ['.git', 'cd %s && git ls-files -co --exclude-standard']
let g:ctrlp_open_multiple_files = 'i'

There is a ctrlp plugin I have to mention, which is very useful to locate function in source code. That is ctrlp-funky. No ctag files needed and regex based search is good enough. Just press \fu to open the function window.

nnoremap <Leader>fu :CtrlPFunky<Cr>
" narrow the list down with a word under cursor
nnoremap <Leader>fU :execute 'CtrlPFunky ' . expand('<cword>')<Cr>

Buffer management

The builtin buffer mangement is good enough, you only need some shortcuts:

" open buffer list
" then press `:b<N>` to jump to the desired buffer
nnoremap <silent> bl :ls<CR>

" jump to next buffer
nnoremap <silent> bn :bn<CR>

" jump to previous buffer
nnoremap <silent> bp :bp<CR>

" jump to the alternative buffer
" this is brilliant useful!
" press it again and again to switch between last two buffers you use,
" just like what tmux `ctrl-l` does
nnoremap <silent> bo :b#<CR>

Search and Replace

quickfix window shortcuts

nnoremap <silent> co :copen<CR>
nnoremap <silent> cn :cn<CR>
nnoremap <silent> cp :cp<CR>
nnoremap <silent> ccl :ccl<CR>

Search current buffer

:vim /pattern/ % | cw

Search in all open buffers

Press :Vim <pattern>, show results in quickfix window.

function! Vimgrepall(pattern)
  call ClearQuickfixList()
  exe 'bufdo vimgrepadd ' . a:pattern . ' %'
  copen
endfunction

command! -nargs=1 Vim call Vimgrepall(<f-args>)

Clear the quickfix window when finished:

:call setqflist([])

Replace in all buffers

:bufdo %s/search/replace/g

Replace in arbitrary file tree

Take a little example I did. I need to modify tons of **/*.t files (directory depth is random):

  • remove pattern only at the end of the file
--- no_error_log
[error]
  • remove pattern (if there is an empty line before the pattern, it should be removed too)
    if ... {
        $block->set_value("no_error_log", "[error]");
    }

Multi-lines pattern matching is very tricky for trandition tools like sed, even when you write perl script, it’s complex and error-prone. In fact, use vim, you could handle it easily. What you see is what you get, you could improve the pattern step by step, and you could even do selective replacement interactively. The vim regular expression is powerful.

Here I use quickfix list to do search and replace:

:vimgrep /--- no_error_log\n\[error\]\%$/ t/**/*.t
:silent cfdo %s/--- no_error_log\n\[error\]\%$//g | update
:call setqflist([])
:vimgrep /\n\?\s*if\s\+.*\n.*\$block->set_value("no_error_log", "\[error\]");.*\n\s*}\s*\n/ t/**/*.t
:silent cfdo %s/\n\?\s*if\s\+.*\n.*\$block->set_value("no_error_log", "\[error\]");.*\n\s*}\s*\n//g | update
:call setqflist([])

Misc

" show matched count
:%s/pattern//ng

" list all matches to have a whole view
:g/pattern/#

vim-fugitive

When you have many files modified, when you need to:

  • revert some of them
  • stage/unstage some of them
  • diff some of them to confirm changes before commit

It’s boring to copy/paste file name and execute git command one by one. vim-fugitive would help.

Press :G to enter git window.

Check shortcuts here:

https://github.com/tpope/vim-fugitive/blob/master/doc/fugitive.txt

Most useful shorcuts:

s                       Stage (add) the file or hunk under the cursor.
u                       Unstage (reset) the file or hunk under the cursor.
X                       Discard the change under the cursor.
dd                      Perform a |:Gdiffsplit| on the file under the cursor.
cc                      Create a commit.

Conclusion

Vim is powerful editor, insist vanilla vim if possible, add plugins gradually if you have to. Don’t use it as IDE, which is not original intention of vim, in my opinion. Keep focus on your source code, but not the fancy looks and addons.