Ask HN: What is one Vim trick most people don't know? - wawhal
======
aequitas
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.

~~~
dllthomas
> 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!)

~~~
mugurel_chirica
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.

~~~
dllthomas
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.

------
thedjinn
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.

~~~
hiyer
vim 8 and neovim have pretty functional in-built terminals (:term). You can
try that if you're using one of these.

~~~
thedjinn
That's more keystrokes. ;)

~~~
sshine
Not if you bind it to ^Z. ;)

~~~
majewsky
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.

~~~
Pete_D

        :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.

------
Xophmeister
Many of the things here, as of writing, are quite elementary Vim tips. A
lesser known trick that I learnt quite recently and have found very useful is
`gn`, which visually selects the next search hit (similarly `gN` for the
previous hit). That's not so useful in itself, but it can be combined with an
operation, such as `c` or `y`, etc., which can then be repeated using the `.`.

------
k4ch0w
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.

~~~
Pete_D
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.

------
robotvert
`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).

~~~
wawhal
I think I don’t quite get you. Doesn’t “v” do the same thing?

~~~
majewsky
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>

------
vikin9
: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.

~~~
Brometheus
yes, awesome!!!

------
valbaca
Quick renaming of variables: what to type"explanation

    
    
        gd" go to definition of variable
        :%s/" beginning of a replace...
        Ctrl-r /" inserts the last word searched into the command, so what "gd" found
        /newname/gc" finish the replace command, g=global replace, c=confirm each replace
    

Save a character going to a line: instead of using :42<enter> to go to line
42, can use 42G

Auto-indent: =

Go to last file: Ctrl-^

Abbreviations: put this in your ~/.vimrc

    
    
        iab cmain int main() {
        \<CR>    return 0;
        \<CR>}
    

Insert the contents of a file: :r <filename>

I like to have a ~/gitmessage.txt which has a template I like, then when I do
git commit all I have to do is:

    
    
        :r ~/gitmessage.txt
    

Vim + Ctags:

Ctags link usages and definitions so you can navigate through code like in an
IDE without the bloat of an IDE. Works best with C, but works pretty well with
any language with C-like syntax (and more).

Goto tag (definition) of what's under cursor: Ctrl-]

Go back: Ctrl-t

Open tag in a preview: Ctrl-w

:tag <tag> " go to tag, like:

    
    
        :tag someFunction
        :tag SOME_CONSTANT

~~~
wyoung2
> Insert the contents of a file: :r <filename>

The file name can be a pipe instead.

Let’s say you have a Makefile based project and the dependencies aren’t as
complete as they ought to be. With your cursor on this line in the Makefile:

    
    
        SOURCES = \
    

You can say

    
    
        :r !ls src/*.c
    

That will put the complete list of extant C source files into the file at that
position, complete with the “src/“ path prefix. Then to format the list
properly for “make” syntax, use Shift-V to select the list, hit the right
angle bracket (“>”) once to indent it a level, then say:

    
    
         :s/$/ \/
    

This trick of replacing the start (“^”) or end (“$”) of a line is very often
helpful. Here I’ve used it to ask Vim to put a space and backslash after every
line to allow the SOURCES variable definition to continue from one line to the
next.

(This will look like “:’<,’>s...” in your editor, with the bit between the
colon and s being inserted by Vim; it means “front the start of the selection
to the end.”)

Remove the final backslash and it’s done.

The advantage of working this way is that you aren’t manually transcribing
things the computer already knows and can report on command.

The possibilities here are vast. For instance, if your C source files are
buried under subdirectories of `src`, say this instead:

    
    
        :r !find src -name \*.c

------
lgeorget
`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.

~~~
_31
I've been looking for something like `Shift+v`! Thanks for that. +1 for `vt`
as well.

~~~
amaterasu
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.

------
amaterasu
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)

~~~
Xophmeister
`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.

~~~
wyoung2
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.

------
wawhal
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.

~~~
tpict
It's not recommended to use <C-C> in place of Esc because it doesn't trigger
an InsertLeave event

~~~
cytzol
Guy who uses <C-c> here. Is that bad?

~~~
majewsky
It is if one of your plugins uses the InsertLeave event to do its work. If in
doubt, `grep -R InsertLeave ~/.vim`.

------
eb0la
I use a lit this ed ([http://man.openbsd.org/4.4BSD-
Lite2/ed.1](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

~~~
professorTuring
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.

~~~
megous
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.

~~~
pritambaral
Line number display can be relative or absolute.

~~~
megous
Ha! Good to know.

------
croo
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).

~~~
flukus
> I have two favourites : alt+* (search for the word I currently standing on)

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

~~~
croo
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.

------
smilesnd
'Esc :q' to quit vim seems to be the one trick most people don't know.

~~~
zie
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 ;)

~~~
opan
ZQ is another one. Like ZZ, but doesn't save. I mainly use ZZ and ZQ to quit.

------
flukus
Mine is playing with errorformat (personal blogspam:
[http://flukus.github.io/vim-errorformat-
demystified.html](http://flukus.github.io/vim-errorformat-demystified.html))
and combining this with :cf (read errors from file) or :cb (read errors from
buffer) to parse a file/buffer into the quicklist. Great for dealing with log
files.

------
vram22
Not sure if most people don't know it, but this is useful (in Windows vim):

In Unix vi(m), you use Ctrl-V to quote a special character to actually insert
it into the text (or into a last line mode command; see example below).

So in Unix if you want to insert a carriage return (Ctrl-M) into a file or a
command, you do Ctrl-V Ctrl-M. That does not work in Windows with gVim because
Ctrl-V means paste from clipboard. So you use Ctrl-Q instead of Ctrl-V, like
in this example, where you want to use vim to remove all the carriage returns
(CRs) from the file (say if you were going to use the file on Unix later [1]):

    
    
        :%s/Ctrl-QEnter//g
    

where instead of typing the letters Enter, you hit the Enter key.

The %s means do the command for all lines in the file (% for all lines, s for
substitute), the command is search-and-replace (old pattern with new pattern,
here Ctrl-M with nothing), and the g(lobal) at the end means do it for all
occurrences in the line (otherwise it does it only for the first occurrence on
the line).

This will show on your screen as:

    
    
        :%s/^M//g (the Ctrl-Q does not show on screen)
    

where the ^M represents the CR or Enter.

The same command on Unix would be:

    
    
        :%s/Ctrl-VEnter//g
    

This will show on your screen as:

    
    
        :%s/^M//g (the Ctrl-V does not show on screen)
    

[1] Of course there are other ways to remove the CRs from the file, like a)
using a dos2unix utility, a) many modern editors will do it for you (via a
setting or a menu option), c) push it to Git from Windows and then pull it
from Unix (with appropriate Git settings for line-ending handling), etc.

~~~
dwyer
There's a command for that.

    
    
        " Use Unix line feeds.
        :set fileformat=unix
    
        " Use Windows line feeds.
        :set fileformat=dos
    
        " Shortcut
        :set ff=unix
    
        " See the current format
        :set ff

~~~
vram22
Yes, I was aware of that (but thanks), and that's why I had written above:

>a) many modern editors will do it for you

although I tend not to use those particular vim options much.

And for anyone else who does not know, many other vim set commands also have
shortcuts, like:

:se ai (for :set autoindent)

and ts for tabstop, sw for shiftwidth, ic for ignorecase, wm for wrapmargin
and many others, probably.

I tend to do this in my .vimrc or .exrc as soon as I start using any new
instance (on a new machine) of vi/vim:

:se ai ts=4 sw=4 showmode showmatch ignorecase expandtab report=0

Also, like:

>" See the current format

> :set ff

you can do this for any boolean setting, like readonly, ignorecase, etc.:

:se readonly?

:se ic?

to query their values.

------
aprao
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

~~~
morokhovets
Also, there are standard gt and gT that are same amount of keystrokes and very
mnemonic too.

------
mohitmun
you can find most on this thread
[https://stackoverflow.com/questions/726894/what-are-the-
dark...](https://stackoverflow.com/questions/726894/what-are-the-dark-corners-
of-vim-your-mom-never-told-you-about)

------
vbsteven
`gv` for reselecting the last selection

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

~~~
ahurmazda
Yes! Took me (embarrassingly) long to discover since I could not figure out
how to google it

------
ifoundthetao
If you're in Insert Mode, and you want to paste the thing you last yanked,
without leaving insert mode, you can do the following:<C-r>0

That pastes the contents of the 0 register into the buffer. Very useful.
That'll work for all registers too.

~~~
mehrundmehr
Can also do <C-r>" (double quote instead of 0) to paste from the default yank
register while in Insert Mode.

------
mihaifm
Better keyboard scrolling with this simple mapping:

nmap <C-j> 3j3<C-e>

nmap <C-k> 3k3<C-y>

This maps the <C-j> and <C-k> keys to a scroll action similar to mouse
scrolling: the cursors stays in a fixed position while the whole screen moves
up or down 3 rows.

~~~
taternuts
I similarly map <C-j> 5j and <C-k> 5k and find it to be one of the most useful
bindings I use, can't VIM without it these days

------
ssayols
Diff mode, delicious! Just edit the 2 files with vim -O file1 file2, and in
vim do <ESC>:diffthis<enter>C-w<right>:diffthis<enter>, and voila!

Vimgrep and the quickfix window are also pretty cool.

~~~
dllthomas
:diffoff is another great thing to know, particularly when using vimdiff to
merge things (e.g. in git). I find that turning diffing off and on for various
windows can more quickly give a clear picture of what changed where.

------
afarrell
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?

~~~
IlGrigiore
nnoremap Q <nop>

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

------
Pete_D
If you like these, it's worth skimming `:help index` and `:help option-
summary` occasionally. You're likely to find at least one interesting new
keybinding or setting.

------
teilo
'ct' followed by a character later in the line. Erases all text from the
cursor up to that character, and enters insert mode.

------
megous
Writing some vimscript is actually not that bad and opens plenty of
possibilities for advanced, context aware code editing.

------
stephenr
How to quit is probably what most people don’t know, when it’s been invoked by
something looking for $EDITOR

------
tpict
`:compiler` for parsing lines in the quickfix window - great for jumping
directly to unit test failures

------
voltooid
:vsplit filename

to open file called "filename" in a vertical split of the console window. Also

:split filename

will open it in a horizontal split

------
aabbate
'Shift+zz' to save and exit

~~~
MaxBarraclough
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_

------
67_45
A lot of people seem to be unaware of switching files within vim instead of
exiting and reinvoking.

~~~
harrygeez
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.

------
eddyg
zz - scroll the line with the cursor to the center of the screen

zt - scroll the line with the cursor to the top

zb - scroll the line with the cursor to the bottom

also:

Ctrl-O - jump to last (think "o"lder) cursor positions

Ctrl-I - jump to next cursor positions (after using Ctrl-O)

------
arc_of_descent
Ctrl-e and Ctrl-y to scroll with the cursor on the same line.

------
dllthomas

        git grep -n foo | vim - -c 'cbuf!'

------
hesselink
Ctrl+V for making and operating on block selections.

------
peter_retief
I know i am going to get downvoted for this but :q!

------
diehunde
Ctrl-a increases a number in visual model

------
arunmp
copy a line using <Esc>1 yy and past simply <Esc> p

~~~
Xophmeister
You don't need the 1; `yy` or `Y` in normal mode is enough to copy the whole
current line.

------
alexandernst
How to quit it

~~~
majewsky

      killall vim
    

There you go. :)

------
vram22
One of my favorite Vim tricks (which also works in vi) is the general
technique of piping a specified range of text through a command (a Unix-style
filter that reads from standard input and writes to standard output), with the
output of that command then replacing that range of text.

The text can be anything from a single line, some arbitrary range of lines
(defined via vim marks like a and b or other letters, some paragraphs (see
example below), to the entire file - and the filter command can be anything at
all, too. The Cartesian product of those two things makes it a very powerful
technique.

An example is this key mapping of the character v to a command that format
paragraphs of text using the fmt command [1]:

map v !}fmt -w 64<CR>

This says: map the letter v to the command following it (after the space),
which is:

    
    
        !}fmt -w 64<CR>
    

which runs/pipes (!) the current paragraph (when at top of a para, the cursor
movement } defines a para) through the fmt -w 64 command, which formats its
input text into lines of not more than 64 characters each.

(I just used v because it was one of the characters that Vim does not already
assign a command to - any other available character will work.)

I have the mapping in my _vimrc on Windows and .vimrc on Unix.

With that mapping, I can reformat any paragraph (where paragraphs in vim are
defined by a blank line either above and below them or both), just by going to
the top of the paragraph (with { ) and typing v (no Enter needed).

For example, if I have this (single) line in a file in vim:

    
    
      the quick brown fox jumped the quick brown fox jumped the quick brown fox jumped the quick brown fox jumped the quick brown fox jumped
    

and I press v when at the start of that line, it gets reformatted into this
para:

    
    
      the quick brown fox jumped the quick
      brown fox jumped the quick brown fox
      jumped the quick brown fox jumped the
      quick brown fox jumped
    

I typically use this technique when writing text content (non-programming
content, such as documentation, tech articles, blog posts, etc.) or sometimes
even for block comments of text in programs.

You can also create a different version of that formatting command to filter
the entire text file through fmt in one shot (that would be "!Gfmt -w 64" when
at top of file, where G moves to the last line), but I tend not to use that
approach much, because it sometimes messes up some paragraphs which should not
be reformatted. So I do it a para at a time.

If you use the sort command instead of fmt, that will sort the range of lines
you select, and the sorted lines replace the original lines. This is of course
useful in text files and (text format) data files, but is also sometimes
useful in source code, e.g. to sort lines of import statements (say in Python
or Go - although Go has commands for that), ranges of variable declarations
into alphabetical order, array literals, etc.).

[1] (Fmt is a Unix command, but you can probably get it in many of the Unix
subsystems that run on Windows too, like Cygwin, UWin, Windows Subsystem for
Linux too). c The command that you run the selected text through, can also be
a Unix or Windows pipeline, which makes the technique even more powerful.

------
dvfjsdhgfv
ZZ

~~~
MaxBarraclough
I agree it's a good command to know, but you might explain what it does: save
and exit.

