Ask HN: What is one Vim trick most people don't know?

45 points by wawhal ↗ HN

98 comments

[ 2.1 ms ] story [ 166 ms ] thread
You can use `Ctrl + C` instead of `ESC`

I figured this out today. And I submitted this Ask HN to find out more such things.

Also ctrl+[ , if that's any easier.
Fun fact is that `C-[` is the same keypress as `<ESC>` due to how ascii control codes work http://jkorpela.fi/chars/c0.html
Those are incredibly frustrating when you're trying to find new bindings, just about all the non-control ones are already used.
It's not recommended to use <C-C> in place of Esc because it doesn't trigger an InsertLeave event
Guy who uses <C-c> here. Is that bad?
It is if one of your plugins uses the InsertLeave event to do its work. If in doubt, `grep -R InsertLeave ~/.vim`.
(comment deleted)
> You can use `Ctrl + C` instead of `ESC`

Even better: Map "jk" to Escape. Enter normal mode without even leaving the home keys; so much easier.

.vimrc:

    inoremap jk <Esc>
A lot of people seem to be unaware of switching files within vim instead of exiting and reinvoking.
I think that's probably more to people not wanting to learn how to do it right. For the longest time, I only taught myself just enough vim to be able to use it for basic editing, because it's convenient and it's better than nano.
To note how:

- ctrl+p plugin to find files in project.

- :bn / :bp / :b<number> to switch between files (buffers)

- :bd to close file

I've mapped 11 to go to previous file, 22 to go to next file, 33 to close file.

How to quit is probably what most people don’t know, when it’s been invoked by something looking for $EDITOR
I have two favourites : alt+* (search for the word I currently standing on) and ciw (delete the word you standing on and enter insert mode).
> I have two favourites : alt+* (search for the word I currently standing on)

Just '*' does this, no need for alt.

Whops that's true. I use non us keyboard layout where you have to press alt to get the * char. I pulled out this shortcut from muscle memory.
I use ciw (= "change inner word") also a lot, very helpful!
* - search current word forward # - search for it backward
`Shift+v` to select a block of text and do a single operation to the same portion of text on several lines (regexp, aligning, etc.)

There's also `vt` + some character to select text from the cursor to the next occurrence of that character.

I've been looking for something like `Shift+v`! Thanks for that. +1 for `vt` as well.
Also ctrl-v allows you to manipulate a block of text, or insert text on multiple lines at once using I or A for before or after the block.
I use a lit this ed (http://man.openbsd.org/4.4BSD-Lite2/ed.1) commands from vi (not just vim).

For instance:

Delele first 20 lines:

<ESC>:0,20d

Delete lines from current location to end of file:

<ESC>:,$d

Search and replace from regrex:

<ESC>:0,$s/regex/replacement/g

any reason for not using :%s/a/b/g for the last one?
Easier way to delete (or cut):

(from cursor next 20 lines) <ESC> d20d

When deleted is on your copy buffer, just prest p tu paste it from cursor.

Or if you don't like counting lines: d15gg

Delete from the current line to a line with a particular line number you already see on the left if you have line numbering enabled.

Line number display can be relative or absolute.
Delete lines from current location to end of file:

dG

is a lot faster.

Along the same line, the move command.

Copy lines 0 through 20 to the current line:

<ESC>:0,20t.

I end up using variants of this and the above multiple times every work day.

`gv` for reselecting the last selection

Assigning different functions to the arrow keys helps when learning vim navigation

Yes! Took me (embarrassingly) long to discover since I could not figure out how to google it
A couple of nice ones: `gq` for re-wrapping a visually selected block of text (<shift>-v is simplest) to your text width.

`=` for re-indenting a selection to your current shift-width settings etc. (or `gg=G` to just do the whole file)

`gq` will work with a text object, so you don't need to go to the trouble of visually selecting a block. Say, for example, you have a mis-wrapped paragraph in a text file, providing your cursor is anywhere within that paragraph, `gqip` will rewrap the whole paragraph.
The nice thing about using `=` instead of `gq` is that you can “set equalprg” to something smarter than the internal Vim formatter, such as `fmt` or `par`:

    https://www.gnu.org/software/coreutils/manual/coreutils.html#fmt-invocation

    http://www.nicemice.net/par/
These formatters will do nice things like choose line breaks intelligently to reduce the raggedness of the right edge. I just tested `gqip` on a paragraph in a Markdown document here that was formatted with `fmt`: the `fmt` output put breaks in such that all but the last line was within one character of equal, whereas `gqip` had line lengths varying as much as 5 characters on a 72 character line length.

A quicker alternative to Shift-V, arrows, then `=` to reformat a paragraph with `fmt` is this:

    :map <F2> !}fmt -w72<CR>
That works anywhere inside the paragraph like with your `gqip`, but it uses the smarter `fmt` paragraph formatter.

Select your keystroke to taste. I chose F2 so long ago that I forget why that was a good idea at the time.

Not really a trick of Vim itself, but when using Vim from the terminal I find ctrl-z very useful to background Vim, type in a few shell commands for git or whatever and then use "fg" to hop back into Vim.
vim 8 and neovim have pretty functional in-built terminals (:term). You can try that if you're using one of these.
That's more keystrokes. ;)
Not if you bind it to ^Z. ;)
Well, you can't. The terminal translates Ctrl-Z into SIGTSTP before it even reaches vim. Alternative suggestion:

  nmap gz :term zsh<CR>
Same number of keystrokes, and does not override any existing normal-mode command from what I can see.

    :nnoremap <C-z> :term<Return>
works for me (tmux in urxvt).

Ctrl-Z only gets converted to SIGTSTP if the terminal has ISIG set. For example, try `stty -isig; sleep 5` and try to suspend or interrupt the sleep command.

Only a few more keystrokes is:

:sh ENTER

or for more control over which shell, or to run a shell with any arguments, or even to run any command w/ or w/o args:

:!bash

:!bash -o vi

:!bash some_script.sh

:!some_command some args

and after any of those, just press Ctrl-D or type exit ENTER to return to the vim session.

Very fast and easy to do. I use it all the time.

'Esc :q' to quit vim seems to be the one trick most people don't know.
Better/Other ways to exit VI/vim:

  * ctrl+z; kill %1
  * Open a new terminal and ignore the one with vim running.
  * ZZ
  * Pull the power cord, erasing any sign of it running.
  * ESC :q!
  * ESC :wq
  * ESC :exit
  * ESC :quit
Of course ESC and :q usually works too ;)
ZQ is another one. Like ZZ, but doesn't save. I mainly use ZZ and ZQ to quit.
Ctrl+V for making and operating on block selections.
`:compiler` for parsing lines in the quickfix window - great for jumping directly to unit test failures
'Shift+zz' to save and exit
Vim has at least three ways of doing this.

You can do :wq return, or the abbreviated form of :x return, or as you say, ZZ

If you forgot to sudo vi, you've already edited the file, saving the file as root without first saving it as your own and then having to move it:

<ESC>:w !sudo tee %

Pipes the content of the file to a tee process as root and lets tee save it under the current file name. Vim will tell you the file has changed on disk and ask if it should reload it afterwards.

> If you forgot to sudo vi

IMO, it's better not to do that in the first place (which, of course, only makes your tip all the more useful!)

Make sure you are 100% confident that you know the proper syntax for this when you use it. I once blanked by mistake an important file, lucky for me I had a backup.
Generally a good idea, before you sudo anything. That's one of the reasons to prefer this approach to `sudo vim`, actually - that's essentially "sudo of anything vim does", and that's a lot of very different things just a couple keystrokes away.
ZZ
I agree it's a good command to know, but you might explain what it does: save and exit.
A slightly longer trick but..

:tabe newfile to open a new file.

Then, add the following to your ~/.vimrc (on MacOS)

map <Esc>f <Esc>:tabn<cr> map <Esc>b <Esc>:tabp<cr>

Now you can switch between tabs using option + arrow keys

Also, there are standard gt and gT that are same amount of keystrokes and very mnemonic too.
Turning off the ability to enter recording mode. I still occasionally type :Q instead of :q and I’d like that to also quit...or even to just no-op.

Any tips on how to just rip recoding mode completely out of my vim?

nnoremap Q <nop>

removes the recording mode and throws a simple error when you use :Q instead of :q

command! Q q

will make :Q behave like :q

Macros, Macros, Macros. These are a game changer when editing large files. Use the `q` key and followed by any letter you like, I default to `a`. Perform some action, like deleting a line, appending to the start of a line, or searching for a word then deleting it. Press `esc`, then type in the number of times you want to repeat the action, followed by `@` and the letter you chose. I.E `10@a` and it will perform that action 10 times.
Vim can be great for quickly doing tedious text transformations. Far easier to get right than doing it the 'proper way' with a script in Python/Perl/whatever.

To do something like scan through a JSON or XML document and split a 'name' field/tag into 'firstName'/'lastName', Vim is the tool I'd reach for.

I think of it as 'cursor-oriented programming', but what I do with it isn't really programming, it's generally of the pattern of 1. Find start of pattern 2. Transform pattern 3. GOTO 1

Or at worst, the decorate/sort/undecorate pattern.

But it boils down to repeatedly applying a macro.

Also fun: macros can call themselves. So if you want to repeat something across a whole file, it's sometimes easiest to write an infinitely recursive macro and let it error when it bumps up against the bottom of the file.
A useful thing to know when using macros is that the letter you press after `q` is just the register in which Vim stores the macro. Registers are also used when copying and pasting. As such, if you want to edit a macro, you can just paste it into a new buffer (e.g., `"ap` for register `a`), edit it as you wish, then copy it back into that register (`:%y a`). You can even use this method to write macros from scratch, rather than recording them first.
`Ctrl + v` to visually select one character at a time (instead of say `Shift + v` that selects a whole line) and then use the movement keys to select a block of characters horizontally as well as vertically. Imagine several well indented HTML <li class="something"> elements, you could for instance delete/modify all the class attributes on all lines visually in one go (to insert text use `Shift + i`, type, then Esc).
I think I don’t quite get you. Doesn’t “v” do the same thing?
What robotvert means is rectangular selection across multiple lines. For example, suppose you have the following text:

  <li class="wrong">first</li>
  <li class="wrong">second</li>
  <li class="wrong">third</li>
You want to change all the instances of "wrong" to "right". So you put the cursor on the first "w", then `Ctrl-V` to enter blockwise visual mode, then `e2j` to select the "wrong" words, then `c` to remove all of them and enter insert mode to type a replacement. The replacement text is then applied to each line separately. Full series of keystrokes (starting with the cursor on the "w" in the first line) if you want to follow along:

  <Ctrl-V>e2jcright<ESC>
:norm(al) command Allows you to do some of the vim magic also on remote systems where you don't have all your plugins.

Example:

(1) Select block with `C-v`

(2) Hit colon `:`

(3) Write norm and enter any sequence as you would be in normal mode: `norm I# ` (prepend selection with a comment sign)

(4) Admire the result.

I know i am going to get downvoted for this but :q!
Writing some vimscript is actually not that bad and opens plenty of possibilities for advanced, context aware code editing.
copy a line using <Esc>1 yy and past simply <Esc> p
You don't need the 1; `yy` or `Y` in normal mode is enough to copy the whole current line.