At least one Vim trick you didn't know about

Original author: Hillel Wayne
  • Transfer
  • Tutorial
I have been working at Vim for eight years and constantly discovering something new. It is considered to be a virtue of Vim. As for me, this is a lack of openness: a bunch of hidden functions are hidden too deeply.

They talk about the beauty of modal editing and text objects, but it seems to me that the essence of Vim is not that. Vim is a patchwork quilt of subsystems clogged with additional tools. Only in normal editing mode more than a hundred keyboard shortcuts! This density of toolkits largely explains why Vim is so useful. If “show all tags for a keyword” is simple g], then this command will be used much more often.

In systems with a lack of openness, one has to rely on leadership. But for Vim there are not so many of them. There are articles for beginners, such as ciw(not to be confused with the CIA, the CIA manual for Vim ) and the like. And there are articles of experts who are immersed in subsystems. But no one really talks about these special tricks that make you exclaim: damn it, as I needed it for the past six years!

This article is about some of the little tricks I use in Vim. None of them are disassembled in all details, so if something interested, I recommend digging additional information. They are also not related to each other. But it normal. In general, there are more than enough of them to really help almost everyone.

Article structure

Very rude, Vim users fall into two categories. Purists appreciate the small size and ubiquity. As a rule, they minimize the configuration in case you have to work on an unfamiliar computer (for example, via ssh). On the other hand, rasshiryalschiki fill Vim plugins, features and homegrown comparisons in a vain attempt to pretend that they are using Emacs. If you take vimrc from them, then the guys will remain completely helpless.

As you probably guess, I am much closer to the expanders than purists. I divided the tricks into two sections depending on whether changes are required in the base Vim.


For modal commands, standard representations from the help are used, i.e. means pressing the Enter key. When you need help :hfor a specific line, for example :h E676, the line will be in parentheses.

Various commands in normal mode

": and @:

":is a register holding the last command executed. You can type ":pto print it to the clipboard. @:repeats the last command.


Register for "expressions." Here you can enter any vimL expression and insert it, use with ctrl-R, etc. Thus, for example, a local timestamp is inserted by input ."=strftime("%c")p

mA, 'A

m{letter}sets the mark at the cursor position. Then '{letter}proceed to this line. For lowercase letters, it acts on the buffer, so it is suitable for navigation. For capital letters, it acts globally: even if you are in another file, it 'Awill go to the file with the label А. You can see all your tags with the command :marks:.

ctrl-A and ctrl-X

Increases and decreases the next number in the line at the cursor location or to the right of it. Since it immediately goes to the number, the combination can be used from anywhere. 10c-Amuch easier than wwwwwciw20.


Opens the history of previous teams. You can work with it as with any Vim text, but the changes are not saved. However, you can run the modified command with . This allows you to very quickly change and restart commands or look for old ones for reuse.

q /, q?

Same as q:search.

ctrl-I, ctrl-O

Moves to the next or previous location in the jumplist. Useful for quick checking and then backtracking. It is very nice to read help files.


See this post for a deeper insight into the use of macros.

Visual mode


Selects the previous visual item.


Goes to the other side of the visual block. Useful if you started one line too low or something like that. In block mode, it goes to the opposite angle diagonally, and use to move to the opposite angle horizontally v_O.

g ctrl-A / ctrl-X

In visual mode, ctrl-A simply increments the first number on each line. On the other hand, g ctrl-Awith each line it will increase the increase by one. This is much easier to explain in the table:

selectedctrl-Ag ctrl-A2 g ctrl-A
a 0
b 0
d 0 
a 1
b 1
d 1 
a 1
b 2
d 3 
a 2
b 4
d 6 

Operators: v, V, cv (: h o_v)

You probably know that in visual mode you can select characters (v), lines (V) and blocks (ctrl-V). But these three combinations can be used as motion operators for the corresponding fragment. For example, you have the following text: If you place the cursor on the top and press , it will delete all three lines, because it moves line by line. If you click instead , the movement becomes block-by-block and only the middle column with three letters is deleted . One use case is delete in search. Normal moves character by character. Therefore, I use for line-by-line movement with deletion. There is another way to do this:




/ regex / {n}

Movement n lines below the match, or as many lines up if the value is negative. As a side effect, movement occurs line by line. Thus, if you want to delete the first line that matches regex, you can enter d/regex//0.


You enter ex-commands in command mode, for example, a command :s. In addition to replacement, there are many other useful commands. All of these examples require a range such as %.

: g / regex / ex

Runs the command only on lines matching the regular expression. For example, you can enter g/regex/dto delete all lines matching regex. The command vis similar to g, but works on all lines that do not match the regular expression.

Tricks become more powerful with norm and some others.

: norm {Vim}

Acts as if you ran {Vim} on each line of the range. For example, it g/regex/norm f dwdeletes the first word after the first space in each line that matches the regex regular expression. This is often much simpler than a macro.

normobeys all your comparisons. For example, if you assigned keys jkto in insert mode, then norm I jk$diwadd a space to the beginning of the line, leave insert mode , and then delete the last word in the line. I really like this functionality, but if you prefer not to use your mappings, you can then apply norm!.

: co.

Copies a range to the current line. You can specify arbitrary values ​​instead of a point, for example, +3or 'a. mvto move.

: y {reg}

Copies a range to a register {reg}. If you {reg}are in upper case, then it is added to an existing case. i.e., such a command

let @a = '' | %g/regex/y A

will copy to aall lines corresponding regexto the entire file. This helps to extract the broken text from the file and copy it to the system clipboard (using let @+ = @a).

: windo {ex}

Runs a command in all windows. For example, :windo $scrolls all the windows down. There is bufdo, cdo, tabdoand others.

Works very well with gand s. To replace all the combinations AAon BBa preliminary view replacements, you can enter vimgrep AAby downloading the coincidences in all quickfix, and then cdo s/AA/BB/cgeto search / replace all matches.

Vim for Extenders

Listed here are tricks that require saving in settings or changing a Vim session. Hypothetically, they can be used in the "puritanical" mode, simply by entering commands, but some involve quite serious changes that contradict the spirit of purism.

Here is only the most unusual. Many people prescribe Hfor a cap ^, so such things are not worth mentioning. It also makes no sense to talk about vim-sensibleor vim-surround, but only about more exotic plugins.

If you are constantly configuring your vimrc, please yourself and add a separate command for this:

command! Vimrc :vs $MYVIMRC


I have all the settings, key bindings and functions stored in a single vimrc file. Splitting into multiple files makes searching difficult.

Most of the settings are not really any “tricks”. It's best to look at vim-sensible : almost all the settings from there will suit your vimrc.

set lazyredraw

Do not redraw the screen in the middle of a macro (to improve performance).

set smartcase / ignorecase

With these two settings, a search without capital letters becomes case insensitive, and a search with capital letters is case sensitive.

set undofile

Saving actions, even if you close and open Vim, so that undo actions are always available. Very handy in combination with the undotree plugin.

set foldcolumn = {n}

Side column with collapsed blocks. The more n, the more collapsed blocks are shown in the column, and for the rest the number is indicated.

set suffixesadd = {str}

gfusually means "go to the file under the cursor", but requires a file extension in the line. suffixesaddAdds the specified extension. If set, then the command gfon the line 'foo' will look for files fooand

set inccommand = nosplit

Only for Neovim. The setting incommandshows in real time what changes the team will make. Now only supported s, but even this is incredibly useful. If you enter :s/regex, all matches are highlighted. If you then add it /change, it will show all the replacements. Works with all regex properties, including backlinks and groups.

set statusline (: h statusline)

Determines what to display in the panel at the bottom of each window. Here formatting is much more complicated and finicky than in other settings, so you have to spend time explaining it. There are some simple tricks. First, look at the default Vim status bar:

:set statusline=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P

Here it is easiest to replace %P(percentage of file over cursor). The status bar format is the value after the percent sign in braces. Therefore, for Markdown files, you can write this:

:set statusline=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %{wordcount()[\"words\"]}

And replace the percentage of the file with the number of words in the document.

Or install tabline. If you do not use tabs, then this line can be made a “global status line”. For example,

set tabline=%{strftime('%c')}

it will always show a date on top.

Key Bindings

I have a lot of bindings.

A lot of convenient keys in Vim are stupidly assigned by default. For example, saving a keystroke sis a synonym cl(saving one keystroke), but it U is the same as saving the uundo as a new change, which is functionally useless. Qidentical gQand in any case is a colossal trap. Zused only for ZZand ZQ. Hell, even the manual recommends Vim reassign keys _and ,on any function, because "you will probably never do not use them." I would prefer not to save one click, but to add completely new functions to the keyboard. Here are some of my bindings:

nnoremap Q @@

Without slowing down the transition to ex-mode, repeats the last macro.

nnoremap s "_d

It makes the key s(with the appropriate assignments for ssand S) work like d, only without saving the deleted text in the register. Useful in order not to clog up the register.

nnoremap j

Go to the window below. Appropriate destination for h, k, l. Working with windows is much easier.

nnoremap e: exe getline (line ('.'))

Run the current line as if it is a command. Experiments are often more convenient than q:.

Special arguments (: h map-arguments)

The command activates the assignment of keys for this buffer only. It really works conveniently with auto-commands as a temporary key combination or when defining assignments through a function. Buffer assignments take precedence over global ones, that is, you can override the general command more useful in a specific situation. The command checks and uses the return value as the final remapping of the keys. One simple use case is binding based on conditions. I have these: What makes and move along the line until a number is found, and after that the key is canceled. Therefore, I can navigate long paragraphs of prose without violating combinations such asmap lhs rhs

map {lhs} {expr}{expr}

nnoremap k (v:count == 0 ? 'gk' : 'k')
nnoremap j (v:count == 0 ? 'gj' : 'j')


The argument helps if any bindings trigger ex-commands.


Thanks to inoremapbinding, they work in insert mode. There they begin to work, therefore they inoremap ;a aaaawill introduce 'aaaa' instead of '; a'. If you want to do something normally, use . For example, if we have it , it will set a label at this point . I like to specify to use semicolons as a key for reassignments, because in normal texts there is almost always a space or a new line after the semicolon.

inoremap ;1 ma



Auto commands are great for configuration. Usually you configure them like this:

augroup {name}
  autocmd! " Prevents duplicate autocommands
  au {events} {file regex} {command}
augroup END

Then, if any of the {events} events occurs in the {file regex} file, the {command} command will fire. Events are listed :h event. For example, if you write

augroup every
  au InsertEnter * set norelativenumber
  au InsertLeave * set relativenumber
augroup END

then vim will disable relativenumber for insert mode only.

The command applies the auto command only to the current buffer. Sometimes I use this to add short-term event handlers to a specific {event} {ex}

BufNewFile, BufRead

BufnewFileit starts when a new file is created, BufRead - when the buffer is first opened. They are usually used to add parameters and remaps to specific file types. I have one such:

augroup md
  au BufNewFile,BufRead *.md syntax keyword todo TODO
  au BufNewFile,BufRead *.md inoremap  ;` ``````
augroup END

Only in Markdown files is the TODO line highlighted, and code ;`notation adds characters in insert mode.

Auto-teams allow you to do much more complex things. For example, auto BufWriteCmdoverride the default retention, allowing to implement custom logic. This goes beyond “tricks” and goes into the realm of “dark magic”.


Most people know about popular plugins such as vim-surroundand NERDtree. Here is a list of some little known ones that I find very useful.


In most text editors, undo actions occur linearly. If you make a change to A, undo it, and then make a change to B, then A is lost forever. However, Vim stores the entire tree of undone actions. The command urolls back the action in the current tree branch, and ggoes to the previous chronological version. You can view the list of canceled actions by the team :undolist.

But this format is not very clear. It is much better to see the actual tree. This is exactly what it does Undotree: it lays out a good ASCII representation of the tree of canceled actions with convenient navigation.


The plugin provides commands for exchanging arguments, so you can replace it (a, f(b, c))with a couple of keystrokes (f(b, c), a). I regularly have to make such edits, so this is a major improvement in the quality of life.


Connects a higher-level API to the neo / vim embedded terminal. For example, :T {text}sends {text} to the console. Good for creating an interactive environment.

"TODO {{{

Many topics are not covered in this article because they are too technical or need to be explained in detail, like function writing or the syntax system. And I don’t know much. I would like to study the following topics in more detail:

Preview, Quickfix, and List windows

I sometimes use tools with these windows, but I don’t know how to manipulate them. I would like to add quickfix errors to my TLA + plugin . I also like the idea of ​​putting supporting information and callback commands in the preview window. This opens up some possibilities that are difficult to reproduce in the IDE.

Neovim API

Neovim offers an advanced API for integrating Vim with external programs. Your Python script can send commands to the Neovim instance, and you can control the editor through the server, for example. I saw some cool conceptual demos where autocomplete happens based on information in a browser. It seems to be very cool!

Text objects

Never created such.

So, this was a brief overview of some of the implicit functions of Vim. Hope you found out something useful!

Also popular now: