Dive into my .vimrc
Date: 2024/08/17 (Sat)
I recently got my first job, but only Windows environment at my working place. I know it's normal, but as a Linux user, it's painful to deal with Windows stuff. My current solution is vim in WSL (Arch btw!), and i've also been thinking about server side workflow without WM for a long time, so i've been updating some vim config these days.
My main concept is minimalism. We don't need to install bunch of plugins and use whatever they feed us, since for some plugins we only need a small subset of its functions. Instead, we can spend some time diving into their source code, learn how they work, and then try to make our own version with more flexibility, more customizable.
Old Workflow with bspwm

- vim on the left, terminal simulator and file manager on the right side
- do compile, or some shell shit in the terminal
- but in most of the time, we are not editing in vim at the same time actually.
- if we need to, like running a server or a slow-executing task, we can simply use tmux.
- use
vim --servername VIM
andvim --remote-tab FILE
to communicate between vim and ranger - but vim need to be compiled with
clientserver
flag on, or we can use gvim instead
- do compile, or some shell shit in the terminal
- we may achieve similar workflow with tmux, but i'm too lazy to look into it, and somehow i think the window navigation key bindings in tmux will messup with mine in bspwm. For now i only use the attach/detach feature of tmux, so maybe someday when i have time (?).
New Workflow with vim only

- To open files:
- if in a project, use self-defined command
CdHere
to set an anchor in the project root directory, and then we can start fuzzy finding !!- i was using
CdHere
until i found outautochdir
. but i realized that it's acutally a stumbling stone to stop me from using fuzzy file finder. - since usually we have our
.git/
in the root of a project, so we can further use fzf to search around changed git files, like when usinggit add
. - (btw, another useful command
SudoSave
when editing some readonly files)
- i was using
command CdHere :cd %:h command SudoSave :w ! sudo tee %
- normal file navigation with file manager, which is ranger in my case.
- opener:
tabe
, i know most people use buffers, but i personally use tabs.
- if in a project, use self-defined command
- terminal
- compile, shell stuff
- use tmux when we need to run something in the background while we can further edit our text.
Why not Neovim ?
- i've tried it several times, but i found nothing so critial that worth a migration for me.
- i know i can simply move my
.vimrc
into~/.config/nvim/init.vim
, but i think it's just fine with vanilla vim right now. if i started from neovim back then, i would totally go for it. - another concern is that comparing to the single-person maintained vanilla vim, the community driven neovim may be more unstable (?) when updated, just like the problem the cutting-edge distro, Arch, has.
- i know i can simply move my
- too fancy, even saw some use render engine, like gtk, to achieve cool animations, but it's a little too much for me. i just need a stable, old-fashioned (or say, retro, lol), server usable text editor, with all functions in a pure
.vim/
,.vimrc
setup, even better not to have extra support flags needed to be compiled with. - a good looking is also a top priority for me. but vim8 added the fancy popup window feature right after neovim did, so im currently fine with it.
- i'm too lazy to learn lua, but neither do i like the new vim9 script language since it looks totally different from the old one.
Plugins
Plugin Manager
- vim8's native plugin manager
- simply git clone the plugins into
~/.vim/pack/default/start/
- but need to pull the git repo of plugins manually when update
- this is sort of related to my arch installation flow. i may need to maintain the git directories of plugins or i have to write what plugins are installed down somewhere (like in arch's installation script). But unlike zsh, vim plugins often change, so it makes me harder to maintain my setup.
- simply git clone the plugins into
- vim-plug
- install/remove with one command
PlugInstall
/PlugClean
- as i mentioned above, it can be easily listed and managed in
.vimrc
.
- install/remove with one command
- an overview of my plugins:
" 1. vim 8 native plugin manager (git clone at ~/.vim/pack/default/start/)
" 2. junegunn/vim-plug:
call plug#begin()
" Plug 'vimwiki/vimwiki'
Plug 'lilydjwg/colorizer'
Plug 'kovetskiy/sxhkd-vim'
Plug 'airblade/vim-gitgutter'
Plug 'itchyny/vim-highlighturl'
Plug 'voldikss/vim-floaterm'
" ===== fuzzy finder ======
" not needed if installed from pkg manager
" Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
" ===== auto-complete ======
Plug 'girishji/vimcomplete'
Plug 'girishji/autosuggest.vim'
" ===== airline ===== (current using powerline)
" Plug 'vim-airline/vim-airline'
" Plug 'vim-airline/vim-airline-themes'
call plug#end()
- only three plugins, which are covered in this article, needs some little tweaks. Others are some useful little plugins that can be easily used after installed.
- fzf / fzf.vim
- vim-floaterm
- vimcomplete / autosuggest.vim
Auto Completion
- completor.vim
- need vim to be compiled with
python
orpython3
support flag on - to get rid of this, i just find an alternative without the need of extra flags. there are tons of auto-completion plugins out there.
- need vim to be compiled with
- vimcomplete / autosuggest.vim
autocmd VimEnter * call g:AutoSuggestSetup({ 'search': { 'fuzzy': 1 }, 'cmd': { 'fuzzy': 1 } })
autocmd VimEnter * call g:VimCompleteOptionsSet({ 'buffer': { 'completionMatcher': 'fuzzy' } })
inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
inoremap <expr> <Tab> pumvisible() ? "\<C-n>" : "\<Tab>"
Fuzzy File Finder
- i've tried several plugins so far:
- scope.vim
- slightly slower than fzf, and no fancy file previews
- but with built-in live file grep search and no other dependencies needed
- fzf and its wrapper fzf.vim
- fzf is prettier, and really well-documented. With command piping, fzf can do a lot of tricks. apart from fuzzy finder, it can also just be a simple selector like
dmenu
. - fzf has its onw vim port,
fzf#run
andfzf#wrapper
, while fzf.vim is a further wrapper around it. somehow if you find it hard to write your own custom script with fzf.vim, you may consider doing it directly base on fzf. - but the downside of fzf.vim is that the preview script is hardcoded. i have to custom it in the git directory of the plugin. there was a pull request about passing a custom preview in the wrapper in 2019, but i don't know why it's still not accepted.
- fzf is prettier, and really well-documented. With command piping, fzf can do a lot of tricks. apart from fuzzy finder, it can also just be a simple selector like
- scope.vim
- at first, i didn't find out the
:RG
function of fzf.vim, so i wrote a live file grep with the tutorial from fzf. here's it works:- use
rg
command to search given token in files (unfortunately no fuzzy search so far) as source - pipe result of
rg
intofzf
to be selected - with
--bind
option offzf
, reload on every keystroke to update new token queries torg
- ofc then i went for fzf.vim, so i am not putting my dumbass script here, lol
- use
- tabs v.s. buffers
- sometimes switching betwen tabs when viewing tens of thousands lines of code is quite slow (also, at my working place, PC is constantly scanned by MIS), and there doesn't seem to be a command to directly jump to specific tabs in vim, but
:b
can easily do the work with buffers. - one buffer can be opened in multiple tabs, which is not what i want: sometimes fzf grep tokens in the already opened files, and there would be duplicate tabs holding the same file.
:pwd
afterCdHere
are not the same among tabs (tabs before callingCdHere
won't change)- so i am a buffer fan boy right now, haha.
- sometimes switching betwen tabs when viewing tens of thousands lines of code is quite slow (also, at my working place, PC is constantly scanned by MIS), and there doesn't seem to be a command to directly jump to specific tabs in vim, but
- after using fzf.vim's
:Buffers
command, i want it also to be able to delete buffers with another key binding (ctrl+d
here) while selecting buffers, so i customed it a little bit. Here's how it works:- with a custom
sink*
functionsink_callback()
, i can do:buffer
or:bdelete
on selected buffers. but how do i know if i want to open them or delete them ? - so i use two bindings
--bind "ctrl-d:accept+execute(echo bd > tmpfile)"
to save different actions to a temp file, and then read it with the callback function afterward - the
--bind
options takeevent:action
syntax: here pressingctrl-d
as an event triggers two actionsaccept
and (+
)execute
at the same time. obviously, we do the output bd stuff inexecute
, andaccept
makes fzf output the selected items to its own communication channel (also a temp file).
- with a custom
nnoremap <C-f> :call FzfCmd('File', '')<CR>
nnoremap <C-b> :call FzfCmd('Buffer', '')<CR>
nnoremap <C-g> :call FzfCmd('Grep', '')<CR>
vnoremap <C-g> y/<C-r>"<CR>N:call FzfCmd('Grep', getreg('"'))<CR>
function! FzfCmd(cmd, init_query) " {{{
let preview_opt = '~3:+{2}+5/2'
let fd_cmd = 'fd -HL -E ".git" -t f 2> /dev/null'
let rg_cmd = "rg -L --hidden --column --line-number --no-heading --color=always --smart-case "
" for Buffer: save fzf action as tmp file and read by sink callback afterward
let s:tmp_action = '/tmp/fzf_action'
function! s:sink_callback(lines)
let action = readfile(s:tmp_action)[0]
for item in a:lines[1:]
let bufn = matchstr(split(item, ':')[1], '\[\zs[0-9]*\ze\]')
execute action bufn
endfor
return delete(s:tmp_action)
endfunction
" dict good, if/else bad (?)
let funcs = {
\ 'File': function('fzf#vim#files', ['', fzf#vim#with_preview({ 'source': l:fd_cmd, 'options': '--prompt "' . a:cmd . ' > " --preview-window ' . l:preview_opt }), 0]),
\ 'Grep': function('fzf#vim#grep2', [l:rg_cmd, a:init_query, fzf#vim#with_preview({ 'options': '--prompt "' . a:cmd . ' > " --preview-window ' . l:preview_opt }), 0]),
\ 'Buffer': function('fzf#vim#buffers', ['', fzf#vim#with_preview({
\ 'sink*': function('s:sink_callback'),
\ 'options': '--prompt " ' . a:cmd . ' > " --preview-window ' . l:preview_opt . ' --multi' .
\ ' --bind "ctrl-d:accept+execute(echo bd > '.s:tmp_action.')"' .
\ ' --bind "enter:accept+execute(echo b > '.s:tmp_action.')"' }), 0])
\}
call funcs[a:cmd]()
endfunction " }}}
- Btw, the
--highlight-line
and--line-range
options ofbat
work as a file grep preview out of the box !! - in fzf.vim, for the purpose of scrolling preview window with mouse (i've never tried it though), they use fzf's
--preview-window
option to scroll to the center highlighted line ofbat
, which prints out the full file. it's easier to use imo, but may take a little more memory (?).

Terminal & File Manager
- Terminal:
- i'm not a fan of window splitting in vim so i go for the fancy popup window terminal vim-floaterm instead of
:terminal
. - vim-floaterm also has wrappers with some good tools such as fzf, ranger, etc.
- i'm not a fan of window splitting in vim so i go for the fancy popup window terminal vim-floaterm instead of
- File navigation:
- i used to use ranger.vim and the built-in netrw as alternatives just in case.
- but the full-sized ranger looks so laaaaame. i really want a popup one
- So i was trying to combine the below two flows and make a floating ranger myself:
- How ranger in vim works
- use ranger option
--choosefile
to not directly open the file but save the chosen file name in a temporary location. - then cat the file and open with vim afterward
- use ranger option
- How popup window (since vim8 IIRC) works
- according to vim documentation:
popup_create(bufn, options)
- (note: this is different from Pmenu or pum in vim)
- call
:terminal
to open a terminal in window, record the buffer number, and then hide the buffer. - feed the buffer number and your popup window options to the
popup_create()
function - you may need a callback to tell what to do after the terminal closed, which is well done by vim-floaterm's wrappers
- according to vim documentation:
- How ranger in vim works
- i know the configs below seem too simple to worth any mention, cuz i removed my stupid self-written scripts right after i found out vim-floaterm's ranger wrapper lol.
let g:floaterm_title = ''
let g:floaterm_opener = 'tabe'
let g:floaterm_borderchars = '─│─│╭╮╯╰'
nnoremap <C-n> :FloatermNew<CR>
nnoremap <C-b> :FloatermNew ranger<CR>
if !executable('ranger')
nnoremap <C-b> :Texplore<CR>
endif
" netrw configs
let g:netrw_hide = 1
let g:netrw_list_hide='\(^\|\s\s\)\zs\.\S\+'
autocmd FileType netrw nmap <buffer> h -
autocmd FileType netrw nmap <buffer> l <CR>
autocmd FileType netrw nmap <buffer> <BS> gh
- looking nice :)


Some other useful configs
Syntax Highlighting
- custom syntax for C: a little regex can do the work
" file location: ~/.vim/syntax/c.vim
syn match cType '\<[a-zA-Z_][a-zA-Z0-9_]*_[ft]\>' " data_type_t
syn match cType '\<[A-Z_][A-Z0-9_]*\>' " DATA_TYPE or MACRO
syn match cFunction "\<\h\w*\ze\_s*(" " functions
- before v.s. after: much more readable


- no need of fancy tree-sitter. i know tree-sitter can do some powerful parser stuff, but if i need syntax highlighting only, it's just an overly decorated Christmas tree for me.
Folding
- a good looking folding script stolen from stack overflow or somewhere.
- sorry that i cant even remember where it's from lol.
set foldenable
set foldmethod=marker " indent / syntax / marker / manual
set foldtext=NeatFoldText()
function! NeatFoldText()
let line = ' ' . substitute(getline(v:foldstart), '\s*{{' . '{\s*', ' ', 'g') . ' '
let lines_count = v:foldend - v:foldstart + 1
let lines_count_text = '| ' . printf("%10s", lines_count . ' lines') . ' |'
let foldchar = matchstr(&fillchars, 'fold:\zs.')
let foldtextstart = strpart('+' . repeat(foldchar, v:foldlevel*2) . line, 0, (winwidth(0)*2)/3)
let foldtextend = lines_count_text . repeat(foldchar, 8)
let foldtextlength = strlen(substitute(foldtextstart . foldtextend, '.', 'x', 'g')) + &foldcolumn
return foldtextstart . repeat(foldchar, winwidth(0)-foldtextlength) . foldtextend
endfunction
Huh ? no LSP ?!
- yeah, i haven't done too much research on it, and i'm currently fine with auto-completion and fuzzy finder. i'll definitely look into it later.
OMAKE: My Linux Hopping History
- 2021
- 11/12: Start with Manjaro i3 Edition
- 2022
- 04/07: musikcube -> cmus
- 06/12:
- Manjaro -> Arch
- terminator -> termite
- 07/01: Try Artix
- 08/15: Sublime Text -> vim
- 10/03: i3 -> bspwm
- See more of my dotfiles here.