I have been using Vim as my primary (and only) text editor since 2009. Over the years, I have discovered many useful things about Vim that I wish I knew earlier because they dramatically improved my text-editing efficiency. In this post, I would like to share the most important ones with you.



HJKL

Usually, the first advice a new Vim user gets is “Do not use arrow keys, use h/j/k/l instead!” For a very long time, I ignored this advice because it seemed absurd to me. Why on earth would I want to do that? One day, however, I decided to give it a try. And since then, I have never looked back. It took me many days to get used to it, but when I did, I was amazed what I was missing. The h/j/k/l keys are directly on the home row, so you do not have to move your hands that much. This not only helped me to move faster, but it also caused my hands to be more relaxed. I believe this was one of the reasons my wrist pain went away. The other one was a wrist pad that I put under my hands.

If you want to learn to use h/j/k/l instead of arrow keys, I suggest to either disable the arrow keys or remap them to something more useful. Another benefit of not using them is that you will get used to better movement commands, like f/F/t/T , w/W/b/B , 0/^/$ , or searching. Use of such commands enables you to move faster than you would by simply holding arrow keys or h/j/k/l . Holding a key in Vim is an antipattern.

Relative Line Numbers

As a lot of users, I used absolute line numbers because, well, all editors use them. One day, however, I stumbled upon this article, which got me thinking. What if relative numbers are better? I decided to give them a shot. And, as Ben said in this video, I realized that my life with absolute line numbers was a lie. Relative numbers are the correct way of using Vim.

To start using relative numbers, I recommend to put the following combination of settings into your .vimrc :

set number set relativenumber

Together, they make Vim show the absolute number for the current line, and relative numbers for other lines.

Next, let me illustrate the usefulness of relative numbers. In Vim, many commands can be prefixed by a number. For example, to move 10 lines below the current line, you can use 10j . To move 4 lines above the current line, use 4k . To indent the current line and 2 lines below, use >2j . You get the idea. With relative numbers, you simply see how far the other lines are. If you were using absolute numbers, you would need to mentally subtract two (possible large) numbers to get the number of lines between them. The use of relative numbers alleviates the need to do math in your head.

You can still use absolute numbers, though. For example, when you compile a source file and the compiler tells you that there is a syntax error on line 943, you can get to this line by pressing either 943G or :943<CR> .

One very useful feature of Vim is that you can set it to visually wrap long lines. Many users, including me, remap j/k to gj/gk to make j/k move by virtual lines instead of physical lines. This remapping, however, breaks the counting functionality described above. To remedy this, use the following mapping instead, based on this stackoverflow.com post:

noremap <silent> <expr> j (v:count == 0 ? 'gj' : 'j') noremap <silent> <expr> k (v:count == 0 ? 'gk' : 'k')

This makes gj/gk move by virtual lines when used without a count, and by physical lines when used with a count. This is perfect in tandem with relative numbers.

Vim and Tmux

For a very long time, I used GVim instead of terminal Vim. It looks better, integrates better with window environments, etc. Then, however, I discovered Tmux, which drastically improved my workflow. In short, it allows you to have separate terminal sessions inside a single terminal window. Inside each session, you can have multiple windows, and each window can be separated into multiple panes. Take a look at this screenshot to get an idea.

The use of Tmux created a dilemma for me. How to use it with GVim? TMux is a terminal application while GVim is a stand-alone GUI application. Fortunately, I was able to set up Vim to look nearly identically to GVim. The most useful plugin was CSApprox. It made my GVim-only color scheme work transparently in terminal Vim. See my .vimrc for other settings that helped me in the transition to terminal Vim.

The greatest advantage the Tmux+Vim combo brings is that it enables you to perform nearly all the development in a terminal. This allows you, for example, to ssh into a remote server and do your development in there. You may then seamlessly resume working from other places, even from a different computer, because you do your work on a remote server through SSH. Another benefit is that development servers are usually much faster than notebooks or desktop PCs. Depending on your company’s budget, you may even be able to develop on a machine with a massive number of cores and memory. Such an experience will make you never want to go back to your work PC.

If you have never used TMux, I urge you to at least give it a try. It is an awesome tool. To help you get started, I have described my Tmux configuration here. Check it out, you may find some nice tweaks in there that will help you to speed up your workflow. For example, the article describes a way of making the navigation between Vim and Tmux seamless.

Operations and Motions

A unique feature of Vim is that it feels like you can speak with it through a language. For example, there are verbs like d (delete) or y (yank), nouns like b (brackets) or s (sentence), and adverbs like i (inside/inner) or a (a/all/around). You can freely combine them, so dib will delete all text inside brackets and yap will copy (yank) the current paragraph. After you learn this simple language, you will never have to remember what to do to delete a paragraph: you simply type dap , without thinking about. The reason why many people think Vim is difficult is that they are not used to think this way about their editor.

The even better part is that the Vim’s language is extensible. Indeed, you can create you own verbs and nouns (operations and motions/text objects in Vim parlance). There are some very useful plugins that I use on a daily base, which I describe next.

Operations

tcomment-vim – Adds a code commenting/uncommenting operation: gc . For example, to comment-out the current paragraph, you use gcap . Think of it as go comment a paragraph. To comment the current line and 5 lines below it, you use gc5j (thanks, relative numbers!).

. For example, to comment-out the current paragraph, you use . Think of it as go comment a paragraph. To comment the current line and 5 lines below it, you use (thanks, relative numbers!). vim-sort-motion – Adds a sorting operation: gs . For example, to sort Python imports under the cursor, you use gsip . Think of it as go sort inside paragraph.

. For example, to sort Python imports under the cursor, you use . Think of it as go sort inside paragraph. ReplaceWithRegister – Adds a replacement operation: gr . It allows you to replace text without overwriting other text stored in registers. For example, to replace the current word with the contents of the default register, you use griw . Think of it as go replace inner word. The gr operation also works with the dot command ( . , repeats the last action), which makes it even better. It is one of my favorite operations.

Motions/Text Objects

targets.vim – Adds a lot of useful text objects. For example, daa deletes an argument of a function call, and ci$ changes text between dollar signs (very useful in LaTeX). Another feature of this plugin is that it allows you to use text objects even when you are not directly inside them. For example, to delete everything inside the nearest double quotes, you use di" (delete inside quotes).

deletes an argument of a function call, and changes text between dollar signs (very useful in LaTeX). Another feature of this plugin is that it allows you to use text objects even when you are not directly inside them. For example, to delete everything inside the nearest double quotes, you use (delete inside quotes). vim-indent-object – Allows you apply an operation to the current indentation level. For example, to shift the current block to the left, you use <ii (left-shift inside indent). This is very useful in Python, which uses whitespace instead of curly braces to structure the code.

(left-shift inside indent). This is very useful in Python, which uses whitespace instead of curly braces to structure the code. vim-surround – Allows you to operate on surroundings. For example, cs"' changes surrounding double quotes with single quotes, and dsb deletes the surrounding brackets.

Of course, you can combine the operations and motions from the above-mentioned plugins. For example, to sort items of a Python list where each item is on a separate line, you use gsii (go sort inside indent).

Some simple text objects can be defined even without plugins. For example, to operate on an entire file, put the following line to your .vimrc :

onoremap af :<C-u>normal! ggVG<CR>

Then, to copy the contents of the entire file (more precisely, the entire buffer), use yaf (yank a file).

Fuzzy Finding

To open a file in Vim, you can use edit or tabnew to open it in the current buffer or a new tab, respectively. A disadvantage of this way is that it is very slow when you are inside of a large project with many nested directories and files. For example, to edit file frontend/scripts/js/view/viewer.js , you have to type the entire path. Hmm. There has to be a better way…

Fortunately, there is! You can use a fuzzy searcher, such as Command-T. It allows you edit the above file by simply starting the searcher (like pressing ,t ), typing fsviewer (f and s are parts of the path to the file), and opening it either in the current window, in a split, or in a new tab. Once you know the hierarchy or file names in your project, the use of a fuzzy searcher massively increases the speed of file openings.

Grepping

Often, you want to list all files that contain the given phrase or word, like the name of a function. When I started using Vim, I would switch to the terminal and type gvim `grep -r FUNC | cut -d: -f1` to open the found files in GVim. However, why leaving Vim to do such a simple task?

You can either use Vim’s built-in grep command, or use a higher-level plugin, such as vim-grepper. It allows you to select a search tool ( grep , git grep , or even ag) and choose how to present the results. For example, you can set up a mapping ,/ to search in all files in a project for a certain phrase, or ,* to perform a project-wide search for the word under the cursor. After the search is done, it opens a window with the found files, and you can open them directly in the Vim instance you work in.

Vim As an External Editor

When you use a text editor, it is important to try to use it as much as possible. After all, why learning another editor, like textarea forms on the web, when you already know Vim? Using Vim everywhere allows you to utilize its strengths and features even on places you previously would not imagine.

For example, for Firefox, there is a great add-on called It’s All Text!, which enables you to edit textarea elements in Vim. This facilitates editing wiki pages, writing blog posts, creating bug reports, etc. by using your favorite editor. For Vim, this means you can utilize syntax highlighting, spell checking, dictionary completion, snippets, or any other feature.

For Thunderbird, there is also the It’s All Text! add-on. It helps you to write emails faster and with more comfort than you would get by using the built-in “editor”.

Many terminal applications also support Vim as an external editor. For example, you may set up Midnight Commander to open files in Vim. Another useful use of Vim is when writing commit messages in version control systems, like in Git. Are you tired of typos? Enable spell checking in Vim. Would you like to be able to complete words from the commited diff by using Ctrl+n ? Commit with the –verbose parameter. It will copy the whole diff into Vim so you can use completion, like for function names. Writing commit messages has never been easier.

The last Firefox add-on I would like to mention is Vimperator. It makes the browser behave like Vim, which allows you to utilize Vim principles even when browsing the web. For example, you can quickly open links, copy text, or make marks on web pages and returning to them later, without a need to touch your mouse. Vimperator even lets you configure Firefox in a .vimrc -like file. Here is mine.

Running External Commands

Imagine you are writing Python code and you would like to run unit tests in a file that you are currently editing. Or imagine you are writing a LaTeX document and would like to compile it to see the results. One way is to move to a terminal and run the tests or compilation from there. This is, however, not very efficient because it causes a delay in your workflow.

A better way is to utilize the fact that you can run external commands directly from Vim. For example, the following autocommand allows you to simply press F9 to save and run the currently edited unit tests for your Python code:

au FileType python nnoremap <buffer> <F9> :wa<CR>:!clear; nosetests %<CR>

Another very useful feature when running Vim inside Tmux is the possibility to run external commands in a given Tmux pane or window. For example, you may divide your current Tmux window into two panes, edit files in one pane, and run tests in the second pane, without a need to switch between them. To give you a taste of my workflow, I like to do the following. I use a dual monitor setup. For a project, I open two terminals with two Tmux sessions. I put one of them to the first monitor and the other one on the second monitor. In the first Tmux session, I edit code, and when I want to run tests, generate documentation, or check the code via a lint-like tool, I send a command from Vim to the second Tmux session, so the tests run on the second monitor. This allows me to edit code and tests in a split window on the first monitor and run git commands, tests, etc. on the second monitor. To toggle focus between the monitors, I have configured Fluxbox to use Ctrl+Alt+h/l . See my configuration files. And the best part? This works even when I run Tmux over SSH on a remote server.

Configuration Options and Mappings

Vim is highly extensible. You can configure it anyway you like, and add mappings and commands for actions you use frequently. I have grown my .vimrc over the years to contain many useful settings and mappings. Below, you can find some of them. However, I encourage you to take a look at my .vimrc to see all of them.

" Quickly select the text that was just pasted. This allows you to, e.g., " indent it after pasting. noremap gV `[v`]

" Stay in visual mode when indenting. You will never have to run gv after " performing an indentation. vnoremap < <gv vnoremap > >gv

" Make Y yank everything from the cursor to the end of the line. This makes Y " act more like C or D because by default, Y yanks the current line (i.e. the " same as yy). noremap Y y$

" Make Ctrl-e jump to the end of the current line in the insert mode. This is " handy when you are in the middle of a line and would like to go to its end " without switching to the normal mode. inoremap <C-e> <C-o>$

" In command mode (i.e. after pressing ':'), expand %% to the path of the current " buffer. This allows you to easily open files from the same directory as the " currently opened file. cnoremap <expr> %% getcmdtype() == ':' ? expand('%:h').'/' : '%%'

" Allows you to easily replace the current word and all its occurrences. nnoremap <Leader>rc :%s/\<<C-r><C-w>\>/ vnoremap <Leader>rc y:%s/<C-r>"/

" Allows you to easily change the current word and all occurrences to something " else. The difference between this and the previous mapping is that the mapping " below pre-fills the current word for you to change. nnoremap <Leader>cc :%s/\<<C-r><C-w>\>/<C-r><C-w> vnoremap <Leader>cc y:%s/<C-r>"/<C-r>"

" Replace tabs with four spaces. Make sure that there is a tab character between " the first pair of slashes when you copy this mapping into your .vimrc! nnoremap <Leader>rts :%s/ / /g<CR>

" Remove ANSI color escape codes for the edited file. This is handy when " piping colored text into Vim. nnoremap <Leader>rac :%s/<C-v><Esc>\[\(\d\{1,2}\(;\d\{1,2}\)\{0,2\}\)\?[m\|K]//g<CR>

Argument Wrapping

Last, but certainly not least, I would like to mention the vim-argwrap plugin. It allows you to quickly wrap and unwrap function arguments, lists, and dictionaries. For example, it allows you to convert

decompiler = Decompiler(api_url=args.api_url, api_key=args.api_key)

to

decompiler = Decompiler( api_url=args.api_url, api_key=args.api_key )

and vice versa with a single mapping.

Discussion

Apart from comments below, you can also discuss this post at /r/programming, r/linux, /r/vim, and /r/sysadmin.