Armin Ronacher

Sharing Vim Tricks

written by Armin Ronacher, on Thursday, July 29, 2010 15:11.

If you are a Vim user, you probably have your own set of tricks that make your editing life a more pleasant experience. So here my set of things I love about Vim and might be worth sharing.

Some things first: normal mode = mode you enter with ESC, insert mode = mode you enter with i (or any other insert starting key).

Searching

That's probably a no brainer because everybody does it all the time, but searching in Vim is a pretty cool experience. Standard search is from normal mode by typing /searchword. To go to the next result use n. If you want to search in the reverse direction, use ? instead of /. If you want to continue the search with the last searchword, just use / or ?.

Sometimes you want to search for the word you are just having your cursor over. That's possible by using * in normal mode, which will search for that words forward, # searches for that word backwards.

When you use * you will notice in the status bar that Vim is wrapping the word in \< and \>. This marks beginning of word and end of word. That way if you search for \<foo\>, it will match foo but not foobar.

Replacing

Generally replacing works with the command :%s/search for/replace with/g. For replacing some weird rules exist which are worth knowing. First of all, the / can be replaced with pretty much everything else. If the slash is part of your searchword, you could also use :%s#search for#replace with#g. The second weird rule is that if you want to insert a newline, \n won't do that, \r does. For replacements \n is actually the nullbyte! But don't worry, \r inserts the correct newline sign that is currently in use for this document. The g means: “replace all matches in a line”. Without that, it would only replace the first occurrence of each line. This is a pretty obscure thing that this is not the default, but in some cases you might want to remove the /g. If you replace that way, Vim will do replacements for the searchword on each line in the file without asking. If you add a c to the flags, it will ask for confirmation for each match.

So far, so good. Now how would you search for the last searchword and replace this? Just leave out the last search: :%s//replace with/. This is especially useful when combined with *.

Another helpful thing is to only replace in a selection. That's very easy. Just select the lines you want with visual selection and then leave out the % sign when doing the replacement. The % just tells vim to operate on the whole document, not having anything there would mean just operating on the current line.

Ways to Insert

As programmer in most languages it makes a lot of sense to think in lines. Vim does that. The most common block selection operates on lines and so do searching and replacing. This line-based thinking also comes in handy when doing inserts. o inserts a new line, O creates a new line in front of the current one. In both cases you will end up in insert mode.

But there are cooler ways to insert too by using motion commands!

Motion Commands

Vim has a couple of motion commands. These need a bit of explanation but trust me, they are awesome. First the most common commands that support motion: y{motion} for copying into a register, c{motion} for deleting and stepping into insert mode, d{motion} for just deleting without going to the insert mode and of course v{motion} to select something.

Now what the hell is {motion}? Motion commands are commands that move the cursor. The probably most awesome motion command is iCHAR where CHAR is a special character to search for in both directions. There the extra rule applies that parentheses are properly inverted for you. This works for ", ', ( and others. Vim is clever enough to adhere to the escaping rules of the language you are working with. This for example means that the command ci" looks selects everything between the next two quotes, deletes the contents and goes to insert mode (c = change). If you want to have it selected instead, you can use vi". vi( will select everything between the current set of parentheses etc (v = visual selection).

The following other motion commands exist: b moves the cursor to the beginning of the word, e to the end. {count}j would go {count} lines down (j = jump I suppose). f{char} looks for a character on the right, F{char} to the left. t and T work like f and F but go one character more (before match, after match). Last but not least there is {count}w which moves {count} words.

Awesome File Navigation

There is a little undocumented (or badly documented feature) of Vim called autochdir. Some people warn about it because it might break plugins, but I never had any issues with it and I am using it for a long, long time. To enable it, you just have to add this to the vimrc: set autochdir.

When enabled, Vim will change into the folder of the file of the buffer. This is pretty handy because :e then works relative to the file. So for example if you are in foo/bar.py and want to edit foo/baz.py you only have to do :e baz.py. Thanks to the automatic completion with Tab and ^D this makes navigating in trees fun. If you have a file open already it will be put into a buffer. If you then substitute :e with :b it will only complete to files that were already open. Because this also supports partial matches, very often a :b baz is enough to go to the baz.py file.

Why The Hell is this not a Default?

There are a couple of things to add to the vimrc where I really wonder why this is not the default:

set title. When this is on your vimrc, the terminal title will automatically reflect what buffer you are working in. This also works in GUI mode, but there it just does nothing. This really should be the default.

Steal my Config

If you want my config, you can download it from this hg repository: mitsuhiko-dotvim.

Comments

  1. Funny you should mention this now, I sent an email to some people about my fav new trick. I'll paste it here, it's about being more productive with django/rails/moin and vim.

    The prob: I want to be able to see the output from a running app while I'm writing code

    My trick: screen / byobu (which is a customized configuration for screen)

    Launch screen
    ctrl+a S (capital S) - to split the window
    ctrl+a tab - to switch to bottom
    ctrl+a :resize 10 - to make it smaller (assuming you'r window is bigger than 20 lines) ctrl+a c - to open a console Here you launch your command you want to monitor, either the django manage.py or tail -f a log
    ctrl+a tab - to switch back to the top
    Now open vim and edit like normal

    Here's a screenshot:
    www.flickr.com/photos/newz2000/4496071224/

    Obviously the cost of doing this on a small window as in that image makes it a questionable solution, but if your windows are bigger it's nice.

    Oh, if you want a small console window but you some times need to scroll, then:

    ctrl+a tab - switch to the bottom ctrl+a esc - I think this is called "copy" mode because you can copy and paste. I never use that. Use the arrows to go up and down esc to get back to the bottom and resume normal operation ctrl+a tab

    Last tip: switch the keyboard shortcut in screen/byobu to ctrl+t so that ctrl+a still works in bash. In byobu press F9 to get a nice menu.

    —  Matt Nuzum on Thursday, July 29, 2010 16:32 #

  2. :set foldmethod=indent is a godesend for Python (and well-indented) code.

    —  Ali on Thursday, July 29, 2010 16:36 #

  3. I don't set autochdir. Instead:
    In my .vimrc:

    " change the working directory to the directory containing the current file

    if has("autocmd")
    autocmd bufenter * :lcd %:p:h
    endif " has("autocmd")

    Once this is done I can suspend (^z) and I am in the directory where I invoked vim. Ordinary unix.

    However, if shell out of vim:
    :shell

    I am in the directory of the file that I am _editing_

    I use vim out of terminals, to fully take advantage of screen and ipython and zsh, so basically I can edit several buffers, :shell into their directories to do whatever I want, or ^z and I'm in what usually is the root of the application that I'm working on.

    —  Kevin on Thursday, July 29, 2010 16:36 #

  4. Although I prefer to set my filetypes in the ftplugin/* files, instead of .vimrc , in the Python sourcecode ( Python-2.7/Misc/Vim ) are updated syntax files and a vimrc which, one would assume, have canonical settings.

    —  Kevin on Thursday, July 29, 2010 17:04 #

  5. —  Amit Mendapara on Thursday, July 29, 2010 17:21 #

  6. "{count}j would go {count} lines down (j = jump I suppose)"

    The source of "hjkl" navigation in vi is ancient terminal keyboard: en.wikipedia.org/wiki/Vi#History

    —  angri on Thursday, July 29, 2010 18:04 #

  7. I use gvim/vim as my Python IDE too. You can see my configuration in code.google.com/p/trespams-vim/

    Is mainly Python oriented. I also have this lines in my .bashrc

    hgdiff() { vimdiff -c 'map q :qa!<CR>' <(hg cat "$1") "$1"; }

    svndiff() { vimdiff -c 'map q :qa!<CR>' <(svn cat "$1") "$1"; }

    —  aaloy on Thursday, July 29, 2010 18:07 #

  8. I like, in your vimrc, the idea of "don't outdent hashes" but I'm not able to get that to work. Is the "X" a special character?

    —  Rob on Thursday, July 29, 2010 18:10 #

  9. Some of the commands I like and use most are `dtX` ("delete to <X>") and `ctX` ("change to <X>"). Especially the latter is very handy to change the content of XML element names (enclosed in angle brackets) or attribute values (enclosed in quotes).

    There is a command to remove a file's BOM, but I forgot which one it was.

    While I didn't dig that much into configuration and scripting (besides binding <F9> to `:explore` and similar things), I do appreciate the vi plugins for Firefox (vimperator) and Intellij IDEA (IdeaVim) which I use on a daily basis (as well as [g]vi[m] itself).

    —  Jochen Kupperschmidt on Thursday, July 29, 2010 18:51 #

  10. I don't like 'autochdir', as I sometimes want to :e path/relative/to/project/root. I use this mapping instead:

    map ,E :e <C-R>=substitute(expand("%:h"), '.\zs$', '/', '')<CR>

    besides, netrw explorer opens the current buffer's directory by default when I do :E<CR>.

    I've written about my vim config here: <a href="mg.pov.lt/blog/unix-is-an-ide.html">Unix is an IDE, or my Vim plugins</a>

    —  Marius Gedminas on Thursday, July 29, 2010 19:43 #

  11. I like to set scrolloff=2 to get some more context for searches and :Sex for navigating the file system. @matt: screen -x can connect multiple terminals to one screen session (that can hold multiple terms); this is especially useful for pair programming, remote guidance or ...

    —  Benjamin Schweizer on Thursday, July 29, 2010 20:19 #

  12. I use ctrl+c to enter normal mode instead of esc. Once you get used to it it's faster than reaching out for the esc key at the top left.

    —  Arthur Koziel on Thursday, July 29, 2010 21:05 #

  13. ctags (exuberant) and vim work great together. Use 'set tags=<tagfile>' to set your tags file and C-] to jump to the definition of the term under the cursor. C-t to jump back to your source.

    —  Neil on Friday, July 30, 2010 1:57 #

  14. vim defaults aren't great. I have lots of generally useful default setting changes in my www.pixelbeat.org/settings/.vimrc

    I also wrote a quick summary of useful shortcuts when I was first learning vim: www.pixelbeat.org/vim.tips.html

    —  Pádraig Brady on Friday, July 30, 2010 15:00 #

  15. instead of autochdir, I bind `gc` to change to the directory of the current file:

    noremap gc :lcd %:h<Cr>

    I use NERDTree, and I map `gn` to open it; it stands for "go nerd!"

    noremap gn :NERDTree<Cr>

    I also like the auto-completion to behave like bash; only filling the unique parts of the filename:

    set wildmode=list:longest

    Finally this really useful shortcut for navigating between buffer splits (windows), I got this from someone on SO:

    " use ctrl-h/j/k/l to switch between splits
    noremap <c-j> <c-w>j
    noremap <c-k> <c-w>k
    noremap <c-l> <c-w>l
    noremap <c-h> <c-w>h

    —  hasen on Wednesday, August 4, 2010 3:24 #

  16. Something I recently learned to use in Vim after years of usage are buffers.

    Most vimmers know about buffers: a window is a graphical representation of a buffer, and so is a tab or a split and so on.

    What most people don't realize is two things: a. You want "set hidden" in your .vimrc - this makes it so that if you switch buffer from one you have undo history and perhaps even unsaved changes, Vim will simply hide the buffer, b. The :b command is extremely useful to switch between open files, for example :b dels<tab> would complete to `path/to/models.py`

    So instead of having 900 tabs open (when you can only really reach Cmd-1 through 4 easily anyway) you have very few tabs, and instead switch between buffers.

    —  Ludvig Ericson on Wednesday, August 18, 2010 5:57 #

Leave a Reply