There is a plethora of questions where people talk about common tricks, notably "Vim+ctags tips and tricks".

However, I don't refer to commonly used shortcuts that someone new to Vim would find cool. I am talking about a seasoned Unix user (be she/he a developer, administrator, both, etc.), who thinks (s)he knows something 99% of us never heard or dreamed about. Something that not only makes his/her work easier, but also is COOL and hackish. After all, Vim resides in the most dark-corner-rich OS in the world, thus it should have intricacies that only a few privileged know about and want to share with us.

+20  A: 

Let's see some pretty little IDE editor do column transposition.



\( and \) is how to remember stuff in regex-land. And \1, \2 etc is how to retrieve the remembered stuff.

>>> \(.*\)^I\(.*\)

Remember everything followed by ^I (tab) followed by everything.

>>> \2^I\1

Replace the above stuff with "2nd stuff you remembered" followed by "1st stuff you remembered" - eseentially doing a transpose.

What does it do exactly?
Switches a pair of tab-separated columns (separator arbitrary, it's all regex) with each other.
The ^I is meant to be a tab, incidentally.
This is just a regex; plenty of IDEs have regex search-and-replace.
@rlbond - It comes down to how good is the regex engine in the IDE. Vim's regexes are pretty powerful; others.. not so much sometimes.
That's a great trick!
James Thompson
The * will be greedy, so this regex assumes you have just two columns. If you want it to be nongreedy use {-} instead of * (see :help non-greedy for more information on the {} multiplier)
Kimball Robinson
@romandas: If all you want to do is column transposition, then you don't need a powerful regex engine. Just sayin.
@intuited - Of course. But I've never found that to be all I wanted. :)
+210  A: 

Might not be one that 99% of Vim users don't know about, but it's something I use daily and that any Linux+Vim poweruser must know.

Basic command, yet extremely useful.

:w !sudo tee %

I often forget to sudo before editing a file I don't have write permissions on. When I come to save that file and get a permission error, I just issue that vim command in order to save the file without the need to save it to a temp file and then copy it back again.

You obviously have to be on a system with sudo installed and have sudo rights.

sweet... never tried that before
This is my favorite bit of vi voodo, hands down.
That's just awesome.
Great command, I have lost count of the number of times this has happened to me ever since I moved to Ubuntu from Slackware.
Does not work in VIM for me. After about 2 seconds the password prompt times out and returns an error.<pre>[sudo] password for user:shell returned 1</pre>
@Casey, this can only help you if you already have a sudo, i.e. did something with it in the current session.
Arguably, that's even *better* than running vim as root! Upvoted!
Even better is using sudoedit in the first place. Otherwise, I'd use ":w !sudo dd of=%" since that doesn't bombard you with the file you're saving being cat to stdout.
great! thanks, it save some of my time:)
For a noob, what exactly does tee do? Would someone mind parseing out this command for me?
tee creates a tee junction in your output. You can output to the screen and a file, for example. Best to search SO or google for a more detailed answer. Or ask a question!
+177  A: 

Something I just discovered recently that I thought was very cool:

:earlier 15m

Reverts the document back to how it was 15 minutes ago. Can take various arguments for the amount of time you want to roll back, and is dependent on undolevels. Can be reversed with the opposite command :later

Chad Birch
Thanks, didn't know about this one. I don't know if i'd use it over multiple undos though.
If only life came with that!
Martin Beckett
How to force it works after :edit file again?
Mykola Golubyev
@skinp: If you undo and then make further changes from the undone state, you lose that redo history. This lets you go back to a state which is no longer in the undo stack.
So if you open the editor, issue :later 8h you are already done for today. Amazing how smart software is these days.
Gamecat: the 8h later version looks nearly exactly like the version now (with some trivial cleanup) , but your editor read 8h worth of SO threads...
Also very usefull is g+ and g- to go backward and forward in time. This is so much more powerfull than an undo/redo stack since you don't loose the history when you do something after an undo.
Etienne PIERRE
+27  A: 

This is a nice trick to reopen the current file with a different encoding:

:e ++enc=cp1250 %:p

Useful when you have to work with legacy encodings. The supported encodings are listed in a table under encoding-values (see help encoding-values). Similar thing also works for ++ff, so that you can reopen file with Windows/Unix line ends if you get it wrong for the first time (see help ff).

Never had to use this sort of a thing, but we'll certainly add to my arsenal of tricks...
great tip, thanks. For bonus points, add a list of common valid encodings.
Adriano Varoli Piazza
I have used this today, but I think I didn't need to specify "%:p"; just opening the file and :e ++enc=cp1250 was enough. I
Ivan Vučica
would :set encoding=cp1250have the same effect?
@laz: no, 'encoding' option defines the encoding that Vim uses to store all of its internal data like text in the buffers, registers, etc. 'fileencoding' defines the encoding of the current buffer. But if you set 'fenc' after opening a file, Vim will convert file from current encoding to the new one. So, the only way to open file using the specific encoding is to use ++enc option.
`:e +b %' is similarly useful for reopening in binary mode (no munging of newlines)
+18  A: 

Often, I like changing current directories while editing - so I have to specify paths less.

cd %:h
What does this do? And does it work with autchdir?
I suppose it would override autochdir temporarily (until you switched buffers again). Basically, it changes directory to the root directory of the current file. It gives me a bit more manual control than autochdir does.
:set autochdir //this also serves the same functionality and it changes the current directory to that of file in buffer
Naga Kiran
+76  A: 

Not exactly obscure, but there are several "delete in" commands which are extremely useful, like..

  • diw to delete the current word
  • di( to delete within the current parens
  • di" to delete the text between the quotes

Others can be found on :help text-objects

I knew the first one :)
:help text-objects
Joe Holloway
@dbr: di( deletes the content inside the brackets. How can you delete only the brackets? I remember that it is possible too.
jholloway7: Thanks, mentioned that help page and linked to the text-objects vim docs. Masi: Not sure, daw will delete the brackets+contents, the closest command I can think of is `xf)x` (delete bracket, jump to next ) and delete again)
dab "delete arounb brackets", daB for around curly brackets, t for xml type tags, combinations with normal commands are as expected cib/yaB/dit/vat etc
@Masi: yi(va(p deletes only the brackets
Don Reba
This is possibly the biggest reason for me staying with Vim. That and its equivalent "change" commands: ciw , ci( , ci" , as well as dt<space> and ct<space>
@thomasrutter: Why not dW/cW instead of dt<space>?
Roger Pate
@Masi: With the surround plugin: ds(.
Roger Pate
@Roger Pate thanks for the tip, though there's probably a limit to how many commands my brain can hold :)
@thomas: That's what I love about vim: commands build on each other so you can remember d<motion> and combine it. :)
Roger Pate

Since I put this in my .exrc I never use Ctrl+F or Ctrl+B anymore:

map # ^M

map ' ^B
Please explain what do those mapping to?
Hardly anything. It makes the # key execute and Ctrl+F and the ' key and Ctrl+B.Which seems very very pointless and dumb. But if you try that on a UK keyboard you'll end up with less risk of RSI.
With this you lose the the # key, which searches backwards for the word under the cursor. It does the same as *, only * searches forwards.
Nathan Fellman
How is ^M == Ctrl-F? Was that a typo?
+9  A: 

I often use many windows when I work on a project and sometimes I need to resize them. Here's what I use:

map + <C-W>+
map - <C-W>-

These mappings allow to increase and decrease the size of the current window. It's quite simple but it's fast.

Taurus Olson
There's also Ctrl-W =, which makes the windows equal width.
+68  A: 

Make vim into a hex editor.

And how do you revert it back?
:!xxd -r //To revert back from HEX
Naga Kiran
Warning: If you don't edit with `binary` (-b), you might damage the file.
I actually think it's `:%!xxd -r` to revert it back
Andreas Grech
+6  A: 

Here's something not obvious. If you have a lot of custom plugins / extensions in your $HOME and you need to work from su / sudo / ... sometimes, then this might be useful.

In your ~/.bashrc:

export VIMINIT=":so $HOME/.vimrc"

In your ~/.vimrc:

if $HOME=='/root'
        if $USER=='root'
                if isdirectory('/home/your_typical_username')
                        let rtuser = 'your_typical_username'
                elseif isdirectory('/home/your_other_username')
                        let rtuser = 'your_other_username'
                let rtuser = $USER
        let &runtimepath = substitute(&runtimepath, $HOME, '/home/'.rtuser, 'g')

It will allow your local plugins to load - whatever way you use to change the user.

You might also like to take the *.swp files out of your current path and into ~/vimtmp (this goes into .vimrc):

if ! isdirectory(expand('~/vimtmp'))
   call mkdir(expand('~/vimtmp'))
if isdirectory(expand('~/vimtmp'))
   set directory=~/vimtmp
   set directory=.,/var/tmp,/tmp

Also, some mappings I use to make editing easier - makes ctrl+s work like escape and ctrl+h/l switch the tabs:

inoremap <C-s> <ESC>
vnoremap <C-s> <ESC>
noremap <C-l> gt
noremap <C-h> gT

+2  A: 

HOWTO: Auto-complete Ctags when using Vim in Bash. For anyone else who uses Vim and Ctags, I've written a small auto-completer function for Bash. Add the following into your ~/.bash_completion file (create it if it does not exist):

Thanks go to stylishpants for his many fixes and improvements.

_vim_ctags() {
    local cur prev


    case "${prev}" in
            # Avoid the complaint message when no tags file exists
            if [ ! -r ./tags ]

            # Escape slashes to avoid confusing awk

            COMPREPLY=( $(compgen -W "`awk -vORS=" "  "/^${cur}/ { print \\$1 }" tags`" ) )

# Files matching this pattern are excluded

complete -F _vim_ctags -f -X "${excludelist}" vi vim gvim rvim view rview rgvim rgview gview

Once you restart your Bash session (or create a new one) you can type:


~$ vim -t MyC<tab key>

and it will auto-complete the tag the same way it does for files and directories:


MyClass MyClassFactory
~$ vim -t MyC

I find it really useful when I'm jumping into a quick bug fix.

Amazing....I really needed it
can you summarize? If that external page goes away, this answer is useless. :(
Summary - it allows ctags autocomplete from the bash prompt for opening files with vim.
Hamish Downer
+25  A: 

Assuming you have Perl and/or Ruby support compiled in, :rubydo and :perldo will run a Ruby or Perl one-liner on every line in a range (defaults to entire buffer), with $_ bound to the text of the current line (minus the newline). Manipulating $_ will change the text of that line.

You can use this to do certain things that are easy to do in a scripting language but not so obvious using Vim builtins. For example to reverse the order of the words in a line:

:perldo $_ = join ' ', reverse split

To insert a random string of 8 characters (A-Z) at the end of every line:

:rubydo $_ += ' ' + (1..8).collect{('A'..'Z').to_a[rand 26]}.join

You are limited to acting on one line at a time and you can't add newlines.

Brian Carper
what if i only want perldo to run on a specified line? or a selected few lines?
You can give it a range like any other command. For example :1,5perldo will only operate on lines 1-5.
Brian Carper
Could you do $_ += '\nNEWLINE!!!' to get a newline after the current one?
Sadly not, it just adds a funky control character to the end of the line. You could then use a Vim search/replace to change all those control characters to real newlines though.
Brian Carper
o my god this is the coolest thing
+30  A: 

Not sure if this counts as dark-corner-ish at all, but I've only just learnt it...

:g/rgba/y A

will yank all lines containing "rgba" into the a buffer. I used it a lot recently when making Internet Explorer stylesheets.

counts, counts as i haven't seen this one :)
Nice one. Never heard of it... Might be useful :P
Thanks! What does the A at the end mean?
@binOrIt is the name of the register to use, it being capital means append to rather than replace the register.
you use the A to append to the register, if it was a then you would just get the last match
Greg Bowyer
+5  A: 

% is also good when you want to diff files across two different copies of a project without wearing out the pinkies (from root of project1):

:vert diffs /project2/root/%
+4  A: 

Input a character from its hexadecimal value (insert mode):

<C-Q>x[type the hexadecimal byte]
Luper Rouch
<C-V> is the more generic command that works in both the text-mode and gui
It's only <C-q> if you're using the awful mswin.vim (or you mapped it yourself).
+15  A: 

Not exactly a dark secret, but I like to put the following mapping into my .vimrc file, so I can hit "-" (minus) anytime to open the file explorer to show files adjacent to the one I just edit. In the file explorer, I can hit another "-" to move up one directory, providing seamless browsing of a complex directory structures (like the ones used by the MVC frameworks nowadays):

map - :Explore<cr>

These may be also useful for somebody. I like to scroll the screen and advance the cursor at the same time:

map <c-j> j<c-e>
map <c-k> k<c-y>

Tab navigation - I love tabs and I need to move easily between them:

map <c-l> :tabnext<enter>
map <c-h> :tabprevious<enter>

Only on Mac OS X: Safari-like tab navigation:

map <S-D-Right> :tabnext<cr>
map <S-D-Left> :tabprevious<cr>
You can also browse files within Vim itself, using :Explore
Roman Plášil
Hi Roman,this is exactly what this mapping does, but assigns it to a "hot key". :)
+4  A: 

I often want to highlight a particular word/function name, but don't want to search to the next instance of it yet:

map m* *#

Scotty Allen
I don't understand this one.
René Nyffenegger
Try it:) It basically highlights a given word, without moving the cursor to the next occurrance (like * would).
Scotty Allen
You can do the same with "nnoremap m* :let @/ = '\<' . expand('<cword>') . '\>'<cr>"
+8  A: 
imap jj <esc>
what does this do?
It will exit edit mode when you press "jj"
how will you type jj then? :P
hasen j
How often to you type jj? In English at least?
You can type it slowly too and it works. Outstanding tip.
I can't live without the jj mapping. I type my jjs with j<C-v>j
Roberto Bonvallet
I remapped capslock to esc instead, as it's an otherwise useless key. My mapping was OS wide though, so it has the added benefit of never having to worry about accidentally hitting it. The only drawback IS ITS HARDER TO YELL AT PEOPLE. :)
@Alex: definitely, capslock is death. "wait, wtf? oh, that was ZZ?....crap."
+3  A: 

Put this in your .vimrc to have a command to pretty-print xml:

function FormatXml()
    set filetype=xml
    normal gg=G

command FormatXml :call FormatXml()
On linuxes (where xmllint is pretty commonly installed) I usually just do :%! xmllint - for this.
David Winslow
+19  A: 

Want to look at your :command history?


Then browse, edit and finally to execute the command.

Ever make similar changes to two files and switch back and forth between them? (Say, source and header files?)

:set hidden

:map :e#<CR>

Then tab back and forth between those files.

I hit `q:` by accident all the time...
Alternatively, from the ex editor (:), you can do CTRL-f to pop up the command history window.
Jason Down
@jleedev me too. I almost hate this command, just because I use it accidentally way too much.
+3  A: 

Use the right mouse key to toggle insert mode in gVim with the following settings in ~/.gvimrc :

" toggle insert mode <--> 'normal mode with the <RightMouse>-key
nnoremap  <RightMouse> <Insert>
inoremap  <RightMouse> <ESC>
This is stupid. Defeats the productivity gains from not using the mouse.
Andreas Grech
+1  A: 

I love :ls command.

Well what does it do?
gives the current file name opened ?
+66  A: 

:! [command] executes an external command while you're in vim.

But add a dot after the colon -- :.! [command] -- and it'll dump the output of the command into your current window. That's : . !

For example:

:.! ls

I use this a lot for things like adding the current date into a document I'm typing:

:.! date
Jeffrey Knight
Whoa... this is a great trick...
One other command -- I don't want to open a separate reply: If you have a split window (:sp [filename] or :vert split [filename) you can swap window panes with ^w r
Jeffrey Knight
This is quite similar to :r!The only difference as far as I can tell is that :r! opens a new line, :.! overwrites the current line.
This one is so cool. Thanks!
Simon Hartcher
@Jeffrey: Thanks...@saffsd: That single difference is a great thing: Now I can pass lines to sed or awk and have it replaced with the processed output...
An alternative to `:.!date` is to write "date" on a line and then run `!$sh` (alternatively having the command followed by a blank line and run `!jsh`). This will pipe the line to the "sh" shell and substitute with the output from the command.
`:.!` is actually a special case of `:{range}!`, which filters a range of lines (the current line when the range is `.`) through a command and replaces those lines with the output. I find `:%!` useful for filtering whole buffers.
@sundar: Why pass a line to `sed`, when you can use the similar built-in `ed`/`ex` commands? Try running `:.s/old/new/g` ;-)
Jabir Ali Ouassou
+1  A: 

Replace all


Give a to replace all :)

+56  A: 

de Duyuuuelete everything till the end of the word by pressing . at your heart's desire.

ci(xyz[Esc] -- This is a weird one. Here, I do not mean insert mode. Instead it means inside the parenthesis. So this sequence cuts the text inside parenthesis you're standing in and replaces it with "xyz". It also works inside square and figure brackets -- just do ci[ or ci{ correspondingly. Naturally, you can do di (if you just want to delete all text without typing anything. You can also do a instead of i if you want to delete the parentheses as well and not just text inside them.

ci" - cuts the text in current quotes

ciw - cuts the current word. This works just like the previous one except that (is replaced with w).

C - cut the rest of the line and switch to insert mode.

ZZ -- save and close current file (WAY faster than Ctrl-F4 to close the current tab!)

ddp - move current line one row down

xp -- move current character one position to the right

U - uppercase, so viwU upercases the word

~ - switches case, so viw~ will reverse casing of entire word

Ctrl+u / Ctrl+d scroll the page half-a-screen up or down. This seems to be more useful than the usual full-screen paging as it makes it easier to see how the two screens relate. For those who still want to scroll entire screen at a time there's Ctrl+f for Forward and Ctrl+b for Backward. Ctrl+Y and Ctrl+E scroll down or up one line at a time.

Crazy but very useful command is zz -- it scrolls the screen to make this line appear in the middle. This is excellent for putting the piece of code you're working on in the center of your attention. Sibling commands -- zt and zb -- make this line the top or the bottom one on the sreen which is not quite as useful.

% finds and jumps to the matching parenthesis.

de -- delete from cursor to the end of the word (you can also do dE to delete until the next space)

bde -- delete the current word, from left to right delimiter

df[space] -- delete up until and including the next space

dt. -- delete until next dot

dd -- delete this entire line

ye (or yE) -- yanks text from here to the end of the word

ce - cuts through the end of the word

bye -- copies current word (makes me wonder what "hi" does!)

yy -- copies the current line

cc -- cuts the current line, you can also do S instead. There's also lower cap s which cuts current character and switches to insert mode.

viwy or viwc. Yank or change current word. Hit w multiple times to keep selecting each subsequent word, use b to move backwards

vi{ - select all text in figure brackets. va{ - select all text including {}s

vi(p - highlight everything inside the ()s and replace with the pasted text

b and e move the cursor word-by-word, similarly to how Ctrl+Arrows normally do. The definition of word is a little different though, as several consecutive delmiters are treated as one word. If you start at the middle of a word, pressing b will always get you to the beginning of the current word, and each consecutive b will jump to the beginning of the next word. Similarly, and easy to remember, e gets the cursor to the end of the current, and each subsequent, word.

similar to b/e, capital B and E move the cursor word-by-word using only whitespaces as delimiters.

capital D (take a deep breath) Deletes the rest of the line to the right of the cursor, same as Ctrl+Shift+End/Del in normal editors (notice 2 keypresses -- Shift+D -- instead of 4)

**zt** is quite useful if you use it at the start of a function or class definition.
Nick Lewis
`vity` and `vitc` can be shortened to `yit` and `cit` respectively.
Nathan Fellman
viwy could also be yiw. viwc could also be ciw. But the vi... is probably easier to remember since you use it in a lot of cases.
Kimball Robinson
There's also "H" to take the cursor to the top line in the display, "M" to take it to the middle one, and "L" to put it on the bottom one. Not to be confused with "gg" and "G", which take you to the top or bottom of the buffer.
+4  A: 

I use vim for just about any text editing I do, so I often times use copy and paste. The problem is that vim by default will often times distort imported text via paste. The way to stop this is to use

:set paste

before pasting in your data. This will keep it from messing up. It is also sometimes helpful to turn on a high contrast color scheme. This can be done with

:color blue

I've noticed that it does not work on all the versions of vim I use but it does on most.

The "distortion" is happening because you have some form of automatic indentation enabled. Using `set paste` or specifying a key for the `pastetoggle` option is a common way to work around this, but the same effect can be achieved with `set mouse=a` as then Vim knows that the flood of text it sees is a paste triggered by the mouse.
+18  A: 

Sometimes a setting in your .vimrc will get overridden by a plugin or autocommand. To debug this a useful trick is to use the :verbose command in conjunction with :set. For example, to figure out where cindent got set/unset:

:verbose set cindent?

This will output something like:

cindent Last set from /usr/share/vim/vim71/indent/c.vim

Laurence Gonsalves
Excellent tip - exactly what I was looking for today.
Artem Russakovskii
+14  A: 
:r! <command>

pastes the output of an external command into the buffer.

Do some math and get the result directly in the text:

:r! echo $((3 + 5 + 8))

Get the list of files to compile when writing a Makefile:

:r! ls *.c

Don't look up that fact you read on wikipedia, have it directly pasted into the document you are writing:

:r! lynx -dump http://en.wikipedia.org/wiki/Whatever
Roberto Bonvallet
^R=3+5+8 in insert mode will let you insert the value of the expression (3+5+8) in text with fewer keystrokes.
@Sudhanshu: nice!
Roberto Bonvallet
+1  A: 

Some of my must-haves are:

cscope + ctags + vim, which can be found on the web.

Some abreviations for quickly starting new code files such as:

ab cpph #include <iostream><CR>#include <string><CR>#include <cstdlib><CR>#include <cassert><CR>#include <vector><CR>#include <
stdexcept><CR>using namespace std;<CR>int main(int argc, char *argv[]) {
ab perlh #!/usr/bin/perl<CR>use strict;<CR>use warnings;<CR>
ab chdr #include <stdio.h><CR>#include <sys/types.h><CR>#include <unistd.h><CR>#include <stdlib.h><CR>#include <sys/stat.h><CR>
#include <sys/wait.h><CR>#include <string.h><CR>int main(int argc, char *argv[]) {
ab xhtmlhdr <?xml version="1.0" encoding="UTF-8"?><CR><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.o
rg/TR/xhtml1/DTD/xhtml1-strict.dtd"><CR><html xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;CR&gt;  <head><CR>  <title></title><CR><link h
ref="style.css" rel="STYLESHEET" type="text/css"><CR></head>

For example cpph will insert a basic skeleton of a main.cc file

There is also my mapping of the function keys:

map <F1> <Esc>:w<CR>:perl $e = `./error.pl`; my ($f,$l,@w) = split(":",$e); my $w=join(":",@w); $curwin->Cursor($l,0); VIM::Msg($w);<CR>
map <F2> :wincmd w<CR>
map <F3> :wincmd s<CR>
map <F4> :wincmd v<CR>
map <F5> :wincmd o<CR>
map <F6> :sball<CR>
map <F7> :wq<CR>
map <F8> :wincmd q<CR>
map <F9> :wincmd -<CR>
map <F10> :wincmd +<CR>
map <F11> :wincmd <<CR>
map <F12> :wincmd ><CR>

In this case my F1 is mapped to put the cursor over the next error that needs to be corrected for a source code migration.

map _ ebi"^[ea"^[

This map would make _ quote a string

+1  A: 

I use Vim for everything. When I'm editing an e-mail message, I use:

gqap (or gwap)

extensively to easily and correctly reformat on a paragraph-by-paragraph basis, even with quote leadin characters. In order to achieve this funtionality, I also add:

-c 'set fo=tcrq' -c 'set tw=76'

to the command to invoke the editor externally. One noteworthy addition would be to add 'a' to the fo (formatoptions) parameter. This will automatically reformat the paragraph as you type and navigate the content, but may interfere or cause problems with errant or odd formatting contained in the message.

Gary Chambers
+4  A: 

I was sure someone would have posted this already, but here goes.

Take any build system you please; make, mvn, ant, whatever. In the root of the project directory, create a file of the commands you use all the time, like this:

mvn install
mvn clean install
... and so forth

To do a build, put the cursor on the line and type !!sh. I.e. filter that line; write it to a shell and replace with the results.

The build log replaces the line, ready to scroll, search, whatever.

When you're done viewing the log, type u to undo and you're back to your file of commands.

Brad Cox
This doesn't seem to fly on my system. Can you show an example only using the ls command?
!!ls replaces current line with ls output (adding more lines as needed).
Brad Cox
Why wouldn't you just set `makeprg` to the proper tool you use for your build (if it isn't set already) and then use `:make`? `:copen` will show you the output of the build as well as allowing you to jump to any warnings/errors.
+3  A: 

For making vim a little more like an IDE editor:

  • set nu - for line numbers in the left margin.
  • set cul - highlights the line containing the cursor.
How does that make Vim more like an IDE ??
I did say "a little" :) But it is something many IDEs do, and some people like it, eg: http://www.eclipse.org/screenshots/images/JavaPerspective-WinXP.png
After all, an IDE = editor + compiler + debugger + building tools + ...
Also, just FYI, vim has an option to set invnumber. That way you don't have to "set nu" and "set nonu", i.e. remember two functions - you can just toggle.
Same goes for cursorline ... and a lot others.
this cursor line feature makes VIM ugly slow, actually unusable
+3  A: 

I just found this one today via NSFAQ:

Comment blocks of code.

Enter Blockwise Visual mode by hitting CTRL-V.

Mark the block you wish to comment.

Hit I (capital I) and enter your comment string at the beginning of the line. (// for C++)

Hit ESC and all lines selected will have // prepended to the front of the line.

Grant Limberg
I added # to comment out a block of code in ruby. How do I undo it.
Neeraj Singh
well, if you haven't done anything else to the file, you can simply type u for undo. Otherwise, I haven't figured that out yet.
Grant Limberg
You can just hit ctrl+v again, mark the //'s and hit x to "uncomment"
I use NERDCommenter for this.
+25  A: 

One that I rarely find in most Vim tutorials, but it's INCREDIBLY useful (at least to me), is the

g; and g,

to move (forward, backward) through the changelist.

Let me show how I use it. Sometimes I need to copy and paste a piece of code or string, say a hex color code in a CSS file, so I search, jump (not caring where the match is), copy it and then jump back (g;) to where I was editing the code to finally paste it. No need to create marks. Simpler.

Just my 2cents.

Xavier Guardiola
similarly, ``'.`` will go to the last edited line
`'.` that is. And ```.` will go to the last edited position
```.` that is...
Ctrl-O and Ctrl-I (tab) will work similarly, but not the same. They move backward and forward in the "jump list", which you can view by doing :jumps or :ju For more information do a :help jumplist
Kimball Robinson
You can list the change list by doing :changes
Kimball Robinson
+3  A: 

Ctrl-n while in insert mode will auto complete whatever word you're typing based on all the words that are in open buffers. If there is more than one match it will give you a list of possible words that you can cycle through using ctrl-n and ctrl-p.

Niki Yoshiuchi
+4  A: 

Want an IDE?

:make will run the makefile in the current directory, parse the compiler output, you can then use :cn and :cp to step through the compiler errors opening each file and seeking to the line number in question.

':syntax on' turns on vim's syntax highlighting.

+5  A: 

I like to use 'sudo bash', and my sysadmin hates this. He locked down 'sudo' so it could only be used with a handful of commands (ls, chmod, chown, vi, etc), but I was able to use vim to get a root shell anyway:

bash$ sudo vi +'silent !bash' +q
Password: ******
too much php
FWIW, sudoedit (or sudo -e) edits privileged files but runs your editor as your normal user.
@OP: That was cunning. :)


Macros are useful to repeat a complicated series of steps (and avoid regular expressions).


Using this (horribly contrived) text file with a consistently repeated pattern, change the title and the artist, in all cases, to <title>'Tain't What You Do</title> and <artist><first>Ella</first><last>Fitzgerald</last></artist>, respectively. And imagine over 1,000 entries must be normalised in this fashion.

<?xml version="1.0"?>
<playlist creator="Yahoo AudioSearchService">
    <title>'Tain't What You Do</title>
    <album>Ella Fitzgerald</album>
    <artist>Ella Fitzgerald</artist>
    <title>Tain't What You Do</title>
    <album>Perfect Jazz</album>
    <artist>Ella Fitzgerald</artist>
    <title>Tain't What You Do</title>
    <album>Jazz Cities</album>
    <artist>Ella Fitzgerald</artist>
    <title>Tain't What You Do '</title>
    <album>Ella Fitzgerald</album>
    <artist>Ella Fitzgerald</artist>
    <title>Tain't What You Do '</title>
    <album>Ella Fitzgerald</album>
    <artist>Ella Fitzgerald</artist>

Record Macro

Here are the vim commands to execute the would-be monotonous task.

  1. Go to the first line where the repeated pattern begins (third line from the top):


  2. Start recording the macro.


  3. Execute the sequence of commands to make the edits.

    'Tain't What You Do*ESC*

  4. Transition to the start of the next repeated item, if needed.

  5. Stop recording the macro.


  6. Run the macro 999 times.


  7. Watch the macro give you time for a snack.

There are many record buffers, in addition to qq and @q. Any letter will work (such as qa and @a). I use qq because it is quite quick.

Dave Jarvis

Mappings to make movements operate on the current screen line in wrap mode. I discovered this in a comment for a Vim tip some time ago, and it has proven quite handy.

function! ScreenMovement(movement)
  if &wrap
    return "g" . a:movement
    return a:movement
onoremap <silent> <expr> j ScreenMovement("j")
onoremap <silent> <expr> k ScreenMovement("k")
onoremap <silent> <expr> 0 ScreenMovement("0")
onoremap <silent> <expr> ^ ScreenMovement("^")
onoremap <silent> <expr> $ ScreenMovement("$")
nnoremap <silent> <expr> j ScreenMovement("j")
nnoremap <silent> <expr> k ScreenMovement("k")
nnoremap <silent> <expr> 0 ScreenMovement("0")
nnoremap <silent> <expr> ^ ScreenMovement("^")
nnoremap <silent> <expr> $ ScreenMovement("$")
+3  A: 

:setlocal autoread

Auto reloads the current buffer..especially useful while viewing log files and it almost serves the functionality of "tail" program in unix from within vim.

Checking for compile errors from within vim. set the makeprg variable depending on the language let's say for perl

:setlocal makeprg = perl\ -c \ %


set makeprg=php\ -l\ %
set errorformat=%m\ in\ %f\ on\ line\ %l

Issuing ":make" runs the associated makeprg and displays the compilation errors/warnings in quickfix window and can easily navigate to the corresponding line numbers.

Naga Kiran
+8  A: 

Map F5 to quickly ROT13 your buffer:

map <F5> ggg?G``

You can use it as a boss key :).

+13  A: 

^O and ^I

Go to older/newer position. When you are moving through the file (by searching, moving commands etc.) vim rember these "jumps", so you can repeat these jumps backward (^O - O for old) and forward (^I - just next to I on keyboard). I find it very useful when writing code and performing a lot of searches.


Go to position where Insert mode was stopped last. I find myself often editing and then searching for something. To return to editing place press gi.


put cursor on file name (e.g. include header file), press gf and the file is opened


similar to gf but recognizes format "[file name]:[line number]". Pressing gF will open [file name] and set cursor to [line number].

^P and ^N

Auto complete text while editing (^P - previous match and ^N next match)


While editing completes to the same line (useful for programming). You write code and then you recall that you have the same code somewhere in file. Just press ^X^L and the full line completed


Complete file names. You write "/etc/pass" Hmm. You forgot the file name. Just press ^X^F and the filename is completed

^Z or :sh

Move temporary to the shell. If you need a quick bashing:

  • press ^Z (to put vi in background) to return to original shell and press fg to return to vim back
  • press :sh to go to sub shell and press ^D/exit to return to vi back

:sp %:h - directory listing / file-chooser using the current file's directory

(belongs as a comment under rampion's cd tip, but I don't have commenting-rights yet)


per this thread

To prefix a set of lines I use one of two different approaches:

One approach is the block select (mentioned by sth). In general, you can select a rectangular region with ctrl-V followed by cursor-movement. Once you've highlighted a rectangle, pressing shift-I will insert characters on the left side of the rectangle, or shift-A will append them on the right side of the rectangle. So you can use this technique to make a rectangle that includes the left-most column of the lines you want to prefix, hit shift-I, type the prefix, and then hit escape.

The other approach is to use a substitution (as mentioned by Brian Agnew). Brian's substitution will affect the entire file (the % in the command means "all lines"). To affect just a few lines the easiest approach is to hit shift-V (which enables visual-line mode) while on the first/last line, and then move to the last/first line. Then type:


The ^ is a regex (in this case, the beginning of the line). By typing this in visual line mode you'll see '<,'> inserted before the s automatically. This means the range of the substitution will be the visual selection.

Extra tip: if your prefix contains slashes, you can either escape them with backslash, or you can use a different punctuation character as the separator in the command. For example, to add C++ line comments, I usually write:

:s:^:// :

For adding a suffix the substitution approach is generally easier unless all of your lines are exactly the same length. Just use $ for the pattern instead of ^ and your string will be appended instead of pre-pended.

If you want to add a prefix and a suffix simultaneously, you can do something like this:


The .* matches the whole line. The & in the replacement puts the matched text (the whole line) back, but now it'll have your prefix and suffix added.

BTW: when commenting out code you'll probably want to uncomment it later. You can use visual-block (ctrl-V) to select the slashes and then hit d to delete them, or you can use a substitution (probably with a visual line selection, made with shift-V) to remove the leading slashes like this:

:s:// ::


Mine is using macros instead of searches - combining a macro with visual mode is sometimes more efficient.

+4  A: 
" insert range ip's
"          ( O O )
" =======oOO=(_)==OOo======

for i in range(1,255) | .put='10.0.0.'.i | endfor
+4  A: 
In normal mode
gf ................ open file under cursor in same window --> see :h path
Ctrl-w f .......... open file under cursor in new window
Ctrl-w q .......... close current window
Ctrl-w 6 .......... open alternate file --> see :h #
gi ................ init insert mode in last insertion position
'0 ................ place the cursor where it was when the file was last edited

:set equalprg=perltidy

+12  A: 

Macros can call other macros, and can also call itself.



...will delete the first word from every line until the end of the file.

This is quite a simple example but it demonstrates a very powerful feature of vim

I didn't know macros could repeat themselves. Cool. Note: qx starts recording into register x (he uses qq for register q). 0 moves to the start of the line. dw delets a word. j moves down a line. @q will run the macro again (defining a loop). But you forgot to end the recording with a final "q", then actually run the macro by typing @q.
Kimball Robinson
I think that's intentional, as a nested and recursive macro.

Neither of the following is really diehard, but I find it extremely useful.

Trivial bindings, but I just can't live without. It enables hjkl-style movement in insert mode (using the ctrl key). In normal mode: ctrl-k/j scrolls half a screen up/down and ctrl-l/h goes to the next/previous buffer. The µ and ù mappings are especially for an AZERTY-keyboard and go to the next/previous make error.

imap <c-j> <Down>
imap <c-k> <Up>
imap <c-h> <Left>
imap <c-l> <Right>
nmap <c-j> <c-d>
nmap <c-k> <c-u>
nmap <c-h> <c-left>
nmap <c-l> <c-right>

nmap ù :cp<RETURN>
nmap µ :cn<RETURN>

A small function I wrote to highlight functions, globals, macro's, structs and typedefs. (Might be slow on very large files). Each type gets different highlighting (see ":help group-name" to get an idea of your current colortheme's settings) Usage: save the file with ww (default "\ww"). You need ctags for this.

nmap <Leader>ww :call SaveCtagsHighlight()<CR>

"Based on: http://stackoverflow.com/questions/736701/class-function-names-highlighting-in-vim
function SaveCtagsHighlight()

    let extension = expand("%:e")
    if extension!="c" && extension!="cpp" && extension!="h" && extension!="hpp"

    silent !ctags --fields=+KS *

    let list = taglist('.*')
    for item in list
     let kind = item.kind

     if     kind == 'member'
      let kw = 'Identifier'
     elseif kind == 'function'
      let kw = 'Function'
     elseif kind == 'macro'
      let kw = 'Macro'
     elseif kind == 'struct'
      let kw = 'Structure'
     elseif kind == 'typedef'
      let kw = 'Typedef'

     let name = item.name
     if name != 'operator=' && name != 'operator ='
      exec 'syntax keyword '.kw.' '.name
    echo expand("%")." written, tags updated"

I have the habit of writing lots of code and functions and I don't like to write prototypes for them. So I made some function to generate a list of prototypes within a C-style sourcefile. It comes in two flavors: one that removes the formal parameter's name and one that preserves it. I just refresh the entire list every time I need to update the prototypes. It avoids having out of sync prototypes and function definitions. Also needs ctags.

"Usage: in normal mode, where you want the prototypes to be pasted:
":call GenerateProptotypes()
function GeneratePrototypes()
    execute "silent !ctags --fields=+KS ".expand("%")
    let list = taglist('.*')
    let line = line(".")
    for item in list
     if item.kind == "function"  &&  item.name != "main"
      let name = item.name
      let retType = item.cmd
      let retType = substitute( retType, '^/\^\s*','','' )
      let retType = substitute( retType, '\s*'.name.'.*', '', '' ) 

      if has_key( item, 'signature' )
       let sig = item.signature
       let sig = substitute( sig, '\s*\w\+\s*,',        ',',  'g')
       let sig = substitute( sig, '\s*\w\+\(\s)\)', '\1', '' )
       let sig = '()'
      let proto = retType . "\t" . name . sig . ';'
      call append( line, proto )
      let line = line + 1

function GeneratePrototypesFullSignature()
    "execute "silent !ctags --fields=+KS ".expand("%")
    let dir = expand("%:p:h");
    execute "silent !ctags --fields=+KSi --extra=+q".dir."/* "
    let list = taglist('.*')
    let line = line(".")
    for item in list
     if item.kind == "function"  &&  item.name != "main"
      let name = item.name
      let retType = item.cmd
      let retType = substitute( retType, '^/\^\s*','','' )
      let retType = substitute( retType, '\s*'.name.'.*', '', '' ) 

      if has_key( item, 'signature' )
       let sig = item.signature
       let sig = '(void)'
      let proto = retType . "\t" . name . sig . ';'
      call append( line, proto )
      let line = line + 1
+2  A: 

Just before copying and pasting to stackoverflow:

:retab 1
:% s/^I/ /g
:% s/^/    /

Now copy and paste code.

As requested in the comments:

retab 1. This sets the tab size to one. But it also goes through the code and adds extra tabs and spaces so that the formatting does not move any of the actual text (ie the text looks the same after ratab).

% s/^I/ /g: Note the ^I is tthe result of hitting tab. This searches for all tabs and replaces them with a single space. Since we just did a retab this should not cause the formatting to change but since putting tabs into a website is hit and miss it is good to remove them.

% s/^/    /: Replace the beginning of the line with four spaces. Since you cant actually replace the beginning of the line with anything it inserts four spaces at the beging of the line (this is needed by SO formatting to make the code stand out).

Martin York
explain it please...
so I guess this won't work if you use 'set expandtab' to force all tabs to spaces.
@Casey: The first two lines will not apply. The last line will make sure you can just cut and paste into SO.
Martin York
+4  A: 

Due to the latency and lack of colors (I love color schemes :) I don't like programming on remote machines in PuTTY. So I developed this trick to work around this problem. I use it on Windows.

You will need

  • 1x gVim
  • 1x rsync on remote and local machines
  • 1x SSH private key auth to the remote machine so you don't need to type the password
  • 1x Pageant
  • 1x PuTTY

Setting up remote machine

Configure rsync to make your working directory accessible. I use an SSH tunnel and only allow connections from the tunnel:

address =
hosts allow =
port = 40000
use chroot = false
    path = /home/xplasil/divine/bledge_ce
    read only = false

Then start rsyncd: rsync --daemon --config=rsyncd.conf

Setting up local machine

Install rsync from Cygwin. Start Pageant and load your private key for the remote machine. If you're using SSH tunelling, start PuTTY to create the tunnel. Create a batch file push.bat in your working directory which will upload changed files to the remote machine using rsync:

rsync --blocking-io *.cc *.h SConstruct rsync://localhost:40001/bledge_ce

SConstruct is a build file for scons. Modify the list of files to suit your needs. Replace localhost with the name of remote machine if you don't use SSH tunelling.

Configuring Vim That is now easy. We will use the quickfix feature (:make and error list), but the compilation will run on the remote machine. So we need to set makeprg:

set makeprg=push\ &&\ plink\ -batch\ [email protected]\ \"cd\ /home/xplasil/divine/bledge_ce\ &&\ scons\ -j\ 2\"

This will first start the push.bat task to upload the files and then execute the commands on remote machine using SSH (Plink from the PuTTY suite). The command first changes directory to the working dir and then starts build (I use scons).

The results of build will show conviniently in your local gVim errors list.

Roman Plášil
A much simpler solution would be to use bcvi: http://sshmenu.sourceforge.net/articles/bcvi/
+2  A: 

I collected these over the years.

" Pasting in normal mode should append to the right of cursor
nmap <C-V>      a<C-V><ESC>
" Saving
imap <C-S>      <C-o>:up<CR>
nmap <C-S>      :up<CR>
" Insert mode control delete
imap <C-Backspace> <C-W>
imap <C-Delete> <C-O>dw
nmap    <Leader>o       o<ESC>k
nmap    <Leader>O       O<ESC>j
" tired of my typo
nmap :W     :w

Launch another editor or commands by using !commandName

Sachin Chourasiya
Interestingly, this can be useful when combined with svn:Add current file to version control:!svn add %Commit:!svn ci -m 'message'Commit only current file:!svn ci -m 'message' %Update:!svn up

:wq is my one of my all-time favorites!

Alternatively, you can use :x
+3  A: 

When working on a project where the build process is slow I always build in the background and pipe the output to a file called errors.err (something like make debug 2>&1 | tee errors.err). This makes it possible for me to continue editing or reviewing the source code during the build process. When it is ready (using pynotify on GTK to inform me that it is complete) I can look at the result in vim using quickfix. Start by issuing :cf[ile] which reads the error file and jumps to the first error. I personally like to use cwindow to get the build result in a separate window.

Anders Holmberg
+1  A: 

A few useful ones:

:set nu # displays lines
:44     # go to line 44
'.      # go to last modification line

My favourite: Ctrl + n WORD COMPLETION!

+1  A: 

Corrects indentation for entire file. I was missing my trusty <C-a><C-i> in Eclipse but just found out vim handles it nicely.


I use MacVim, which has tabs, and I'm obsessive about never leaving my keyboard. But MacVim tabs are sort of bolted onto the underlying Vim, and so are not quite equivalent to buffers. However, using a few mappings it can be done.

"switch tabs using left / right arrow keys
map <Right> :tabnext<Enter>
map <Left> :tabprevious<Enter>

Also, this might be the most overlooked feature Vim has had for a long time: :help netrw

It might be common sense, but I used Vim for many years until finding out about the Netrw plugin. I spend more time editing remote than local files, so vim over ssh tunnels is something I couldn't live without!

+1  A: 

Typing == will correct the indentation of the current line based on the line above.

Actually, you can do one = sign followed by any movement command. ={movement}

For example, you can use the % movement which moves between matching braces. Position the cursor on the { in the following code:

if (thisA == that) {
//not indented
if (some == other) {
x = y;

And press =% to instantly get this:

if (thisA == that) {
    //not indented
    if (some == other) {
        x = y;

Alternately, you could do =a{ within the code block, rather than positioning yourself right on the { character.

Kimball Robinson
holy sh*t that's awesome
Tamás Szelei

Create a function to execute the current buffer using it's shebang (assuming one is set) and call it with crtl-x.

map <C-X> :call CallInterpreter()<CR>

au BufEnter *
\ if match (getline(1) , '^\#!') == 0 |
\   execute("let b:interpreter = getline(1)[2:]") |
\ endif

fun! CallInterpreter()
    if exists("b:interpreter")
        exec("! ".b:interpreter." %")

My favourite recipe to switch back and forth between windows:

function! SwitchPrevWin()
    let l:winnr_index = winnr()
    if l:winnr_index > 1
       let l:winnr_index -= 1
       "set winnr_index to max window open
        let l:winnr_index = winnr('$')
    exe l:winnr_index . "wincmd w" 

nmap <M-z> :call SwitchPrevWin()
imap <M-z> <ESC>:call SwitchPrevWin()

nmap <C-z> :wincmd w
imap <C-z> <ESC>:wincmd w
+8  A: 

Vim will open a URL, for example

vim http://stackoverflow.com

Nice when you need to pull up the source of a page for reference.

For me it didn't open the source; instead it apparently used elinks to dump rendered page into a buffer, and then opened that.
Ivan Vučica