A Veterans Tutorial of Vim
Many posts aimed at new Vim users tend to just paste a large .vimrc file and then explain a few plugins to try. Very little (if any) time is devoted to explaining what all those settings in .vimrc are actually doing.
I’d like to walk through my personal .vimrc file section by section and break down what and why I have the configuration settings I do. Given that my .vimrc has over 15 years’ worth of built-up cruft, this will also be a good exercise for me to clean it up a bit and update where needed as well.
To be completely transparent, we won’t be really talking about the contents of my
~/.vimrc file, because that file on my computer really only contains the following:
set runtimepath+=~/Dropbox/vim source ~/Dropbox/vim/vimrc.vim
I like to have my whole Vim setup, plugins and all, available to me no matter what system I’m on, and using Dropbox allows me to keep all my computers in sync. Yes, setting the
runtimepath and then sourcing the file will increase your startup time, but for me the slight time bump is worth it. So, the file we will be really looking at is my
~/Dropbox/vim/vimrc.vim file which acts like a normal
" Don't include vi compatibility set nocompatible
Right off the bat, the first thing I do is turn off Vi compatibility. If you were never an ardent Vi user (not Vim, Vi) then just turn off Vi compatibility. Then I make the backspace key play a bit nicer on OS X too allow me to backspace over auto-indents, line breaks, and the start of inserts.
" os x backspace fix set backspace=indent,eol,start set modelines=0 " dont need modelines and the potential security hazard
Next I turn off modeline support, mostly because I don’t use modelines personally and I don’t want to open a file from someone else that could potentially harm my system by the usage of modelines. It’s just a risk not worth taking if you aren’t in the habit of using modelines for what they were intended for.
"set t_kb fixdel
Last up in this section I just fix the terminal code support so both my backspace and delete keys work as expected on OS X.
" Setup term color support if $TERM == "xterm-256color" || $TERM == "screen-256color" || $COLORTERM == "gnome-terminal" set t_Co=256 endif
Next I turn on good color support for Vim terminal usage, and as a developer I turn on trailing whitespace support so I can see any trailing whitespace as I type it. We will revisit this setting again when I describe some settings that automatically strip trailing whitespace when a buffer is saved.
" show trailing whitespace chars set list set listchars=tab:>-,trail:.,extends:#,nbsp:.
set list turns on the display of unprintable characters, and then
set listchars enumerates which characters to display and which character to display them with.
" Better buffer management - hide buffers instead of closing them set hidden set history=100 " Default history is only 20 set undolevels=100 " Use more levels of undo
This next grouping relates to how Vim manages its buffers and history. I like Vim to hide my buffers instead of closing them completely. This allows me to keep modified buffers without being forced to save or abandon them. Next I have Vim remember 100 commands in history and set my undo level to 100 as well.
" tab -> spaces set expandtab set tabstop=2 " a tab is 2 spaces set softtabstop=2 " tab size when insterting/pasting set shiftwidth=2 " number of spaces to use for autoindenting set shiftround " use multiple of shiftwidth when indenting with '<' and '>' set smarttab " insert tabs on the start of a line according to shiftwidth, not tabstop
The prolific spaces vs. tags section is next up, and I’m firmly in the converting spaces to tabs camp, so my Vim configuration reflects that. The first line expands tabs to spaces, with tab spacing of 2.
Shiftwidth sets the number of spaces used when autoindenting.
set autoindent " always set autoindenting on set copyindent " copy the previous indentation on autoindenting
Finally we turn on auto-indentation and tell Vim to use the most recent indentation level when auto-indenting. These auto-indentation rules are just the defaults and will most-likely will be overridden by plugins you use for common programming languages.
" set foldenable " fold by default set nofoldenable " dont fold by default set foldmethod=indent " fold based on indentation set foldnestmax=10 " deepest fold is 10 levels set foldlevel=1
I prefer to not have my files open with folding turned on, but if you prefer, you can just uncomment
set foldenable and remove
set nofoldenable. I set my foldmethod to indent as this works well for just about all languages I code in, but other options include manual or custom syntax markers for fold deliniation. I tell Vim to only nest 10 folds deep (honestly probably 5 levels is too far in my opinion, but 10 is better than the default of 20).
" Ruler on set ruler " Line numbers on set nu
I like to have line numbers turned on when editing, and also see which line and column I’m currently editing which is turned on by the ruler option.
" use ack for grepping set grepprg=ack set grepformat=%f:%l:%m
Also, I’m a user of Ack instead of grep so I tell Vim to use it instead of grep.
" dont use backup files set nobackup set noswapfile set directory=~/.vim-tmp,~/.tmp,~/tmp,/var/tmp,/tmp " store swap files here
The next few lines are minor preferences, but pretty self-explanatory. I don’t have Vim make backup for swapfiles by default, but when it does, I set the directory hierarchy to use for creating those files.
syntax on " Enable syntax highlighting filetype on " Enable filetype detection filetype indent on " Enable filetype-specific indenting filetype plugin on " Enable filetype-specific plugins
As a developer, I prefer to have syntax highlighting and I turn it on. I also turn on file type detection and file type specific indentation rules and plugin loading.
" Search Settings set incsearch " show search matches as you type set ignorecase " case insensitive search set smartcase " If a capital letter is included in search, make it case-sensitive set nohlsearch " dont highlight search results
Next I configure how I want Vim to behave when searching. I have Vim show me the search results incrementally, as I type my search query and perform case-insensitive searches by default unless I include a capital letter in my query. Finally, I prefer not to highlight search results by default.
colorscheme vividchalk set background=dark
My color scheme settings come next and I use a dark background based on my primary usage of Vim from the terminal.
scrolloff setting is the number of lines of context to keep above and below the cursor when scrolling to the very top and bottom of the screen. I prefer to have a few lines of context visible always instead of having my cursor be at the very top or bottom of the screen.
shortmess variable is probably too much to cover here, but is worth a read if you have the time (use
:help shortmess), but know that it is just configuring what and how I want alert and system messages to be displayed.
set visualbell " don't beep set noerrorbells " don't beep
I don’t like Vim beeping at me so I turn on the
visualbell and I don’t want any error bells triggered at all.
" Auto read when a file is changed on disk set autoread
autoread tells Vim to automatically read a file in memory again if it has been detected to have changed from outside of Vim.
" status line set laststatus=2
Lastly, I set
laststatus=2 to tell Vim to always show the status line (a value of 0 means never and 1 means only if there are at least 2 windows).
" Use pathogen to easily modify the runtime path to include all " plugins under the ~/.vim/bundle directory execute pathogen#infect()
I use Pathogen as my Vim plugin manager. It seems most of the cool kids are now using Vundle which provides some nice, useful additions, but I’ve been on Pathogen for a long time and haven’t had the need to migrate yet. This command just initializes pathogen which loads all my plugins.
To begin the discussion of keymapping, let’s take our first sidebar and remember that Vim is a modal editor and what this means for keymapping. While you will mostly only be concerned with mapping keys in the default, normal, and visual modes, here is the full list of modes and their corresponding mode symbol for mapping commands:
* n: normal only * v: visual and select * o: operator-pending * x: visual only * s: select only * i: insert * c: command-line * l: insert, command-line, regexp-search (and others. Collectively called "Lang-Arg" pseudo-mode)
These mode symbols can be used as prefixes on the two mapping commands of
map will map keys recursively while
noremap is a non-recursive mapping.
Now, back to my
" space = pagedown, - = pageup noremap <Space> <PageDown> noremap - <PageUp>
The next major grouping of my
vimrc is my custom key mappings. I begin by mapping the
Space spacebar to send a page down command, and the
- minus key to send a page up command. I sometimes find this easier than the default of
" make j and k act normally for wrapped lines nnoremap j gj nnoremap k gk " remap ; to : so you can just do `;w` instead of <Shift-; w> nnoremap ; :
Next I make the normal up/down movement keys of j and k perform the same for wrapped lines as unwrapped lines, and I remap the semicolon key to send the colon key command. Since colon is used for entering Vim commands, and only 3 people on earth seem to know what the default semicolon key does in Vim, we shorten this up to a single keystroke and just use
(As an aside, to impress your friends, the default command for semicolon is to repeat the most recent f, t, F, or T command).
" make regexp search not suck by default - nnoremap / /v vnoremap / /v
Also, I make Vim’s regular expression pattern matching work a bit more sanely by default. This maps the search command of
/ to use
/v by default in both normal and visual modes, which allows you to use a more familiar regular expression syntax instead of the craziness that is Vims regexp syntax.
" remap'd keys map <c-j> <c-w>j map <c-k> <c-w>k map <c-l> <c-w>l map <c-h> <c-w>h map <Tab><Tab> <C-W>w
Here I begin to remap some movement keys just to save keystrokes. I map
Ctrl-J directly to the standard window movement commands so I can save a keystroke and not have to type
Ctrl-w j. Same for k, l and h. I also map window hopping to a double press of the
Tab key so I can quickly cycle through windows with a single key.
nnoremap <F2><F2> :vsplit<CR> nnoremap <F3><F3> <C-W>w nnoremap <F4><F4> :set invwrap wrap?<CR> " use f4f4 to toggle wordwrap nnoremap <F5><F5> :set invhls hls?<CR> " use f5f5 to toggle search hilight map <F7> :b#<CR>
For creating new windows I map a double press of
F2 to vertically split my current window and then also map a double press of
F3 to cycle again, just like my double
Tab command does. Hey, there is no law against having two ways to do the same thing :). I remap double
F4 to toggle word-wrapping on and off, and double
F5 to toggle search result highlighting on and off.
" allow saving a sudo file if forgot to open as sudo cmap w!! w !sudo tee % >/dev/null
Next come mappings for a command mode only way for me to save files that require root access, but which I forgot to open with the proper permissions.
" toggle paste mode nmap <leader>o :set paste!<CR> " toggle NERDTree drawer map <leader>d <plug>NERDTreeTabsToggle<CR>
After that is way to quickly toggle paste mode on and off, which is very useful for pasting code snippets from GUI editors or found on the web, followed by a way for me to quickly toggle open the project drawer from the NERDTree plugin.
" remove trailing whitespace nnoremap <leader>W :%s/\s\+$//<cr>:let @/=''<CR>
Lastly I map a quick command I can run to remove trailing whitespace on demand by typing
leader key is set to backslash).
Vim allows for the usage of custom-defined functions through Vimscript and I have one defined for the scratch.vim plugin I use.
" toggle scratch buffer (scratch.vim plugin) function! ToggleScratch() if expand('%') == g:ScratchBufferName quit else Sscratch endif endfunction map <leader>s :call ToggleScratch()<CR>
I define a function called
ToggleScratch() and then map that to
\s for easy usage. This opens my Scratch buffer if not open in a current window.
Auto commands in Vim allow you to have certain commands automatically execute based on events. Events can be anything from file type detection to reading a buffer.
" auto remove whitespace on buffer save autocmd! BufWrite * mark ' | silent! %s/\s\+$// | norm ''
My first few auto commands are simple enough. I have a command set on all filetypes when the buffer is saved to remove any trailing whitespace.
" Turn on spell check for certain filetypes automatically autocmd BufRead,BufNewFile *.md setlocal spell spelllang=en_us autocmd BufRead,BufNewFile *.txt setlocal spell spelllang=en_us autocmd FileType gitcommit setlocal spell spelllang=en_us
Next I turn on spell check support for markdown and text files as well as my gitcommit messages to hopefully save myself any potential typo embarrassment.
" Autowrap text to 80 chars for certain filetypes autocmd BufRead,BufNewFile *.md setlocal textwidth=80 autocmd BufRead,BufNewFile *.txt setlocal textwidth=80 autocmd FileType gitcommit setlocal textwidth=80
Also for markdown, text and gitcommit files I set the max text width to 80 characters on buffer read and new buffers.
Plugin Specific Options
The last section of my
vimrc contains customizations to the various plugins I use. Reading the help documentation for any plugin you use should provide documentation on the various settings you can configure to customize the plugin.
" gist-vim config let g:gist_clip_command = 'pbcopy' let g:gist_detect_filetype = 1 let g:gist_open_browser_after_post = 1 let g:gist_post_private = 1 " make gists private by default
In my case, I set some basic customizations to the gist.vim plugin to make my gists private by default and open the gist in my browser after creation.
" CtrlP Config let g:ctrlp_map = '<leader>t' let g:ctrlp_working_path_mode = 'ra' let g:ctrlp_match_window_bottom = 0 let g:ctrlp_match_window_reversed = 0 let g:ctrlp_custom_ignore = '\v\~$|\.(o|swp|pyc|wav|mp3|ogg|blend)$|(^|[/\\])\.(hg|git|bzr)($|[/\\])|__init__\.py' let g:ctrlp_working_path_mode = 0 let g:ctrlp_dotfiles = 0 let g:ctrlp_switch_buffer = 0
I use ctrlp.vim as my fuzzy file launcher and configure it mostly to tell it which files and directories to ignore and to map launching it to my
" Vimux config let g:vroom_use_vimux = 1
— Craig (@cpjolicoeur)