⬆️ ⬇️

At least one trick of Vim, about which you did not know

I have been working at Vim for eight years and constantly discovering something new. It is considered to be the virtue of Vim. As for me, this is a lack of openness: a bunch of hidden features are hidden too deep.



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



In systems with a lack of openness, you have 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 on 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 exclaiming: damn it, how I needed it in the last six years!



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

')

Article structure



Very roughly, Vim users fall into two categories. Purists value small sizes and omnipresence. As a rule, they reduce the configuration to a minimum in case you have to work on an unfamiliar computer (for example, via ssh). On the other hand, extenders populate Vim with plugins, functions, and home-grown juxtapositions in a vain attempt to pretend they are using Emacs. If you take vimrc from them, then the guys will remain completely helpless.



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



Purists



For modal commands, the standard representations from the help are used, i.e. <cr> means pressing the Enter key. When you need to get help :h for a specific line, for example :h E676 , then the line will be in brackets.



Different teams in normal mode



": and @:



": is the register that stores the last command executed. You can type ":p to print it to the buffer. @: repeats the last command.



"=



Register for "expressions". Here you can enter any vimL expression and insert it, use it with ctrl-R, etc. Thus, for example, the local time stamp is inserted by entering "=strftime("%c")<cr>p .



mA, 'A



m{letter} sets the mark at the cursor location. Then '{letter} will go to this line. For lower case letters, it acts within the limits of the buffer, therefore it is suitable for navigation. For capital letters, it acts globally: even if you are in another file, 'A will go to the file with the label You can view all your tags with the command :marks:



ctrl-A and ctrl-X



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



q:



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



q / q?



Same as q: except search.



ctrl-i, ctrl-o



Moves to the next or previous location in the jumplist. Useful for quick check and then back. Very nice to read the help files.



Macros



See this post for deep immersion in the use of macros.



Visual mode



gv



Selects the previous visual element.



v_o



Moves 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 to go to the opposite angle horizontally, use 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-A will increase the increment by one with each line. This is much easier to explain in the table:



selectedctrl-Ag ctrl-A2 g ctrl-A
  a 0
 b 0
 c
 d 0 
  a 1
 b 1
 c
 d 1 
  a 1
 b 2
 c
 d 3 
  a 2
 b 4
 c
 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 this text:



abc

abc

abc




If you place the cursor on the top b and press d2j , it will delete all three lines, because j moves line by line. If you press d<cV>2j instead, the movement becomes block by block and only the middle column with three letters b is deleted.



One use case is delete in search. Normal d/ moves character by character. Therefore, I use dV/ for line-by-line movement with deletion. There is another way to do this:



/ regex / {n}



Moves 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 corresponding to regex , you can enter d/regex//0 .



Ex teams



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



: g / regex / ex



Executes the command only in lines matching the regular expression. For example, you can type g/regex/d to remove all lines that match regex. The v command is similar to g , but works on all strings that do not match the regular expression.



Tricks become more powerful with the use of norm and some others.



: norm {Vim}



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



norm is subject to all your comparisons. For example, if you assigned the jk keys to <esc> in insert mode, then norm I jk$diw adds a space to the beginning of the line, leaves insert mode , and then deletes the last word in the line. I really like this functionality, but if you prefer not to use your own mappings, you can then apply norm! .



: co.



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



: y {reg}



Copies range to register {reg} . If {reg} capitalized, it is added to the existing register. i.e. such a command



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



will copy into a all the lines corresponding to the regex in the whole file. It helps to extract broken text from a file and copy it to the system clipboard (using let @+ = @a ).



: windo {ex}



Runs the command in all windows. For example :windo $ all windows down. There are bufdo , cdo , tabdo and others.



Works very well with g and s . To replace all AA combinations with BB with replacement preview, you can enter vimgrep AA by loading all matches in quickfix, and then cdo s/AA/BB/cge to search / replace all matches.



Vim for extenders



Here are tricks that require saving in the settings or changing the Vim session. Hypothetically, they can be used in the "puritan" mode, just by typing commands, but some entail quite serious changes that are contrary to the spirit of purism.



Here, only the most unusual. Many people assign H to the cap ^ , so these things are not worth mentioning. Also, it makes no sense to talk about vim-sensible or vim-surround , but only about more exotic plugins.



If you are constantly setting up your vimrc, make yourself nice and add a separate command for this:



command! Vimrc :vs $MYVIMRC



Settings



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



Most of the settings are not really some "tricks". It is 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 the macro (for better performance).



set smartcase / ignorecase



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



set undofile



Saving actions, even if you close and open Vim, so undoing actions is always available. Very convenient in combination with the plugin undotree.



set foldcolumn = {n}



Side column with folded blocks. The greater the n , the more convolved blocks are shown in the column, and for the others the number is indicated.



set suffixesadd = {str}



gf usually means “go to the file under the cursor,” but it requires the file extension in the string. suffixesadd adds the specified extension. If you set suffixesadd=.md , then the gf command on the 'foo' line will look for the files foo and foo.md



set inccommand = nosplit



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



set statusline (: h statusline)



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



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



Here the easiest way is to replace %P (the percentage of the file above the cursor). The format of the status bar is the value after the percent sign in curly brackets. 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 by the number of words in the document.



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



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



will always show the date on top.



Key bindings



I have a lot of bindings.



A lot of convenient keys in Vim are assigned by default stupidly. For example, saving pressing s is synonymous with cl (saving one pressing), and U is the same as u , except for recording undo as a new change, which is functionally useless. Q identical to gQ and in any case is a huge trap. Z used only for ZZ and ZQ . Heck, even the Vim manual recommends reassigning the _ keys and , for some functions, since “you probably never 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



Causes the s key (with the appropriate settings for ss and S ) to work as d, only without saving the deleted text in the register. Useful in order not to litter the register.



nnoremap <cj> <cw> j



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



nnoremap <leader> e: exe getline (line ('.')) <cr>



Run the current line as if it were a command. In experiments, it is often more convenient than q: .



Special arguments (: h map-arguments)



The map <buffer> lhs rhs command map <buffer> lhs rhs activates key assignment only for this buffer. It really works conveniently with autocommands as a temporary keyboard shortcut or when defining assignments through a function. Buffer assignments take precedence over global ones, that is, you can redefine a common command more useful in a particular situation.



The map <expr> {lhs} {expr} command map <expr> {lhs} {expr} checks {expr} and uses the return value as the final key remap. One simple use case is binding depending on conditions. I have these:



nnoremap <expr> k (v:count == 0 ? 'gk' : 'k')

nnoremap <expr> j (v:count == 0 ? 'gj' : 'j')




What causes j and k to move along the line until a number is encountered, and after that the key assignment is canceled. Therefore, I can move through long paragraphs of prose without disturbing combinations like 10j .



The <silent> argument helps if some bindings run ex commands.



inoremaps



Thanks to inoremap bindings work in insert mode. There they start working, so inoremap ;a aaaa will enter 'aaaa' instead of '; a'. If you want to do something normally, use <cO> . For example, if we have



inoremap ;1 <co>ma



then ;1 set at this point the label 'a .



I like to use the semicolon as a key for reassignments, because in normal texts there is almost always a space or a new line after the semicolon.



autocmd



Autocommands are great for configuration. Usually you set them up like this:



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


Then, if any of the {events} events occur in the {file regex} file, then the {command} command is triggered. Events are listed in the list :h event . For example, if you write



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


then vim will disable relative number only for insert mode.



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



BufNewFile, BufRead



BufnewFile launched when creating a new file, BufRead - when you first open the buffer. They are usually used to add parameters and reassignments to specific file types. I have one such:



 augroup md autocmd! au BufNewFile,BufRead *.md syntax keyword todo TODO au BufNewFile,BufRead *.md inoremap <buffer> ;` ```<cr><cr>```<Up><Up> augroup END 


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



Autocommands allow you to do much more complicated things. For example, au for BufWriteCmd overrides the standard save, allowing you to implement non-standard logic. It goes beyond the "tricks" and goes into the area of ​​"dark magic".



Plugins



Most are aware of popular plugins such as vim-surround and NERDtree . Here is a list of some lesser known ones that I find very useful.



Undotree



In most text editors, undoing occurs linearly. If you make change A, cancel it, and then make change B, then A is lost forever. However, Vim stores the entire tree of undone actions. The u command rolls back the action in the current tree branch, and g moves to the previous chronological version. You can view the list of canceled actions with the command :undolist .



But this format is not very visual. Much better to see the actual tree. This is exactly what Undotree does: lays out a good ASCII representation of the tree of undone actions with easy navigation.



vim.swap



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



Neoterm



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



"TODO {{{



This article does not cover many topics, because they are too technical or need a detailed explanation of how to write functions or the syntax system. And I do not 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 a Neovim instance, and you can control the editor through a server, for example. I have seen some cool conceptual demonstrations where autofilling happens based on the information in the browser. It seems to be very cool!



Text objects



Never created such.






So this was a quick overview of some of the implicit Vim functions. I hope you learned something useful!

Source: https://habr.com/ru/post/454742/



All Articles