Shell from vi

A good sign of a philosophically sound interactive Unix tool is the facilities it offers for interacting with the filesystem and the shell: specifically, how easily can you run file operations and/or shell commands with reference to data within the tool? The more straightforward this is, the more likely the tool will fit neatly into a terminal-driven Unix workflow.

If all else fails, you could always suspend the task with Ctrl+Z to drop to a shell, but it’s helpful if the tool shows more deference to the shell than that; it means you can use and (even more importantly) write tools to manipulate the data in the program in whatever languages you choose, rather than being forced to use any kind of heretical internal scripting language, or worse, an over-engineered API.

vi is a good example of a tool that interacts openly and easily with the Unix shell, allowing you to pass open buffers as streams of text transparently to classic filter and text processing tools. In the case of Vim, it’s particularly useful to get to know these, because in many cases they allow you to avoid painful Vimscript, and to do things your way, without having to learn an ad-hoc language or to rely on plugins. This was touched on briefly in the “Editing” article of the Unix as IDE series.

Choosing your shell

By default, vi will use the value of your SHELL environment variable as the shell in which your commands will be run. In most cases, this is probably what you want, but it might pay to check before you start:

:set shell?

If you’re using Bash, and this prints /bin/bash, you’re good to go, and you’ll be able to use Bash-specific features or builtins such as [[ comfortably in your command lines if you wish.

Running commands

You can run a shell command from vi with the ! ex command. This is inherited from the same behaviour in ed. A good example would be to read a manual page in the same terminal window without exiting or suspending vi:

:!man grep

Or to build your project:

:!make

You’ll find that exclamation point prefix ! shows up in the context of running external commands pretty consistently in vi.

You will probably need to press Enter afterwards to return to vi. This is to allow you to read any output remaining on your screen.

Of course, that’s not the only way to do it; you may prefer to drop to a forked shell with :sh, or suspend vi with ^Z to get back to the original shell, resuming it later with fg.

You can refer to the current buffer’s filename in the command with %, but be aware that this may cause escaping problems for files with special characters in their names:

:!gcc % -o foo

If you want a literal %, you will need to escape it with a backslash:

:!grep \% .vimrc

The same applies for the # character, for the alternate buffer.

:!gcc # -o bar
:!grep \# .vimrc

And for the ! character, which expands to the previous command:

:!echo !
:!echo \!

You can try to work around special characters for these expansions by single-quoting them:

:!gcc '%' -o foo
:!gcc '#' -o bar

But that’s still imperfect for files with apostrophes in their names. In Vim (but not vi) you can do this:

:exe "!gcc " . shellescape(expand("%")) . " -o foo"

The Vim help for this is at :help :!.

Reading the output of commands into a buffer

Also inherited from ed is reading the output of commands into a buffer, which is done by giving a command starting with ! as the argument to :r:

:r !grep vim .vimrc

This will insert the output of the command after the current line position in the buffer; it works in the same way as reading in a file directly.

You can add a line number prefix to :r to place the output after that line number:

:5r !grep vim .vimrc

To put the output at the very start of the file, a line number of 0 works:

:0r !grep vim .vimrc

And for the very end of the file, you’d use $:

:$r !grep vim .vimrc

Note that redirections work fine, too, if you want to prevent stderr from being written to your buffer in the case of errors:

:$r !grep vim .vimrc 2>>vim_errorlog

Writing buffer text into a command

To run a command with standard input coming from text in your buffer, but without deleting it or writing the output back into your buffer, you can provide a ! command as an argument to :w. Again, this behaviour is inherited from ed.

By default, the whole buffer is written to the command; you might initially expect that only the current line would be written, but this makes sense if you consider the usual behaviour of w when writing directly to a file.

Given a file with a first column full of numbers:

304 Donald Trump
227 Hillary Clinton
3   Colin Powell
1   Spotted Eagle
1   Ron Paul
1   John Kasich
1   Bernie Sanders

We could calculate and view (but not save) the sum of the first column with awk(1), to see the expected value of 538 printed to the terminal:

:w !awk '{sum+=$1}END{print sum}'

We could limit the operation to the faithless electoral votes by specifying a line range:

:3,$w !awk '{sum+=$1}END{print sum}'

You can also give a range of just ., if you only want to write out the current line.

In Vim, if you’re using visual mode, pressing : while you have some text selected will automatically add the '<,'> range marks for you, and you can write out the rest of the command:

:'<,'>w !grep Bernie

Note that this writes every line of your selection to the command, not merely the characters you have selected. It’s more intuitive to use visual line mode (Shift+V) if you take this approach.

Filtering text

If you want to replace text in your buffer by filtering it through a command, you can do this by providing a range to the ! command:

:1,2!tr '[:lower:]' '[:upper:]'

This example would capitalise the letters in the first two lines of the buffer, passing them as input to the command and replacing them with the command’s output.

304 DONALD TRUMP
227 HILLARY CLINTON
3 Colin Powell
1 Spotted Eagle
1 Ron Paul
1 John Kasich
1 Bernie Sanders

Note that the number of lines passed as input need not match the number of lines of output. The length of the buffer can change. Note also that by default any stderr is included; you may want to redirect that away.

You can specify the entire file for such a filter with %:

:%!tr '[:lower:]' '[:upper:]'

As before, the current line must be explicitly specified with . if you want to use only that as input, otherwise you’ll just be running the command with no buffer interaction at all, per the first heading of this article:

:.!tr '[:lower:]' '[:upper:]'

You can also use ! as a motion rather than an ex command on a range of lines, by pressing ! in normal mode and then a motion (w, 3w, }, etc) to select all the lines you want to pass through the filter. Doubling it (!!) filters the current line, in a similar way to the yy and dd shortcuts, and you can provide a numeric prefix (e.g. 3!!) to specify a number of lines from the current line.

This is an example of a general approach that will work with any POSIX-compliant version of vi. In Vim, you have the gU command available to coerce text to uppercase, but this is not available in vanilla vi; the best you have is the tilde command ~ to toggle the case of the character under the cursor. tr(1), however, is specified by POSIX–including the locale-aware transformation–so you are much more likely to find it works on any modern Unix system.

If you end up needing such a command during editing a lot, you could make a generic command for your private bindir, say named upp for uppercase, that forces all of its standard input to uppercase:

#!/bin/sh
tr '[:lower:]' '[:upper:]'

Once saved somewhere in $PATH and made executable, this would allow you simply to write the following to apply the filter to the entire buffer:

:%!upp

The main takeaway from this is that the scripts you use with your editor don’t have to be in shell. You might prefer Awk:

#!/usr/bin/awk -f
{ print toupper($0) }

Or Perl:

#!/usr/bin/env perl
print uc while <>;

Or Python, or Ruby, or Rust, or …

ed supports this Incidentally, this “filtering” feature is where vi‘s heritage from ed ends as far as external commands are concerned. In POSIX ed, there isn’t a way to filter a subset of the buffer text through a command in one hit. It’s not too hard to emulate it with a temporary file, though, using all the syntax learned above:

*1,2w !upp > tmp
*1,2d
*0r tmp
*!rm tmp

However, there is a way to filter a whole file in one hit:

*e !upp < %

Vim character info

Vim will show you the decimal, octal, and hex index of the character under the cursor if you type ga in normal mode. Keying this on an ASCII a character yields the following in the status bar:

<a>  97,  Hex 61,  Octal 141

This information can be useful, but it’s worth it to extend it to include some other relevant information, including the Unicode point and name of the character, its HTML entity name (if applicable), and any digraph entry method. This can be done by installing the characterize plugin by Tim Pope.

With this plugin installed, pressing ga over a yields a bit more information:

<a> 97, \141, U+0061 LATIN SMALL LETTER A

This really shines however when inspecting characters that are available as HTML entities, or as Vim digraphs, particularly commonly used characters like an EM DASH:

<—> 8212, U+2014 EM DASH, ^K-M, &mdash;

Or a COPYRIGHT SYMBOL:

<©> 169, \251, U+00A9 COPYRIGHT SIGN, ^KCo, ^KcO, :copyright:, &copy;

Or as one of the eyes in a look of disapproval:

<ಠ> 3232, U+0CA0 KANNADA LETTER TTHA

Note that ga shows you all the Unicode information for the character, along with any methods to type it as a digraph, and an appropriate HTML entity if applicable.

If you work with multibyte characters a lot, whether for internationalization reasons or for typographical correctness in web pages, this may be very useful to you.

Special characters in Vim

Particularly when editing documents for human consumption rather than code, it’s often necessary to enter special characters into a document that can’t otherwise be produced by a single key press:

  • Letters with diacritical marks like ä, é, and ô — Vim refers to these as digraphs — a particular problem when using a US keyboard layout
  • Unicode characters like typographic dashes or copyright symbols ©, or other symbols from the multi-byte portion of the UTF-8 character set (including foreign languages)
  • Literal control characters like <Tab>

Vim has a method for inserting each of these within the editor, rather than having to copy-paste them from another document. We won’t discuss Vim’s alternative multibyte input methods here, and will assume that you’re using a keyboard with a US or UK layout, and predominantly type in English — apologies to international readers, but I do not have another type of keyboard to test this out!

Some of the following assumes that you’re using Vim in a UTF-8 capable terminal, and with the encoding option in your .vimrc set to utf-8, which is highly recommended for the vast majority of editing requirements:

set encoding=utf-8

It also assumes that your font is capable of displaying all of the characters concerned; monospace fonts with workable symbol coverage include Consolas, Inconsolata, and Ubuntu Mono.

Digraphs

Vim has a special shorthand for entering characters with diacritical marks. If you need some familiar variant of a Latin alphabet character with a diacritical mark or embellishment, it’s likely you’ll be able to input it with the digraph system. It also has support for some other sometimes-needed characters like thorn Þ and eszett ß, and Cyrillic characters.

Digraph input is started in insert or command mode (but not normal mode) by pressing Ctrl-k, then two printable characters in succession; the first is often the “base” form of the letter, and the second denotes the appropriate embellishment.

Some simple examples that might occasionally be needed for English speakers to correctly type one of the language’s many “loan words”:

  • Ctrl-k c , -> ç
  • Ctrl-k e ' -> é
  • Ctrl-k o ^ -> ô
  • Ctrl-k a ! -> à
  • Ctrl-k u : -> ü
  • Ctrl-k = e ->

This is just a small sample; Vim has support for a great many digraphs. Take a look at the relevant section of the documentation for a complete treatment of the feature. You can also type :digraphs within Vim to get a complete list of digraphs — several screenfuls of them!

Note that you can enter all of these characters using the Unicode mode discussed later in this article as well; two-character mnemonic digraphs simply happen to be easier to remember than four-digit codes.

Unicode characters

For characters not covered in the digraph set, you can also enter unicode characters by referring to their code page number. In insert or command mode (but not normal mode) this is done by typing Ctrl-v and then u, followed by the hexadecimal number. Some potentially useful examples:

  • Ctrl-v u 2018 -> , a LEFT SINGLE QUOTATION MARK
  • Ctrl-v u 2019 -> , a RIGHT SINGLE QUOTATION MARK
  • Ctrl-v u 2014 -> , an EM DASH
  • Ctrl-v u 00a9 -> ©, a COPYRIGHT SIGN

These are handy in some cases when writing HTML documents, as an alternative to using HTML entities like &mdash; or &copy;. An exhaustive summary of these characters and their codes is available on the Unicode website.

Other non-printable characters

The unicode character input method is actually a specialised case of inputting literal characters with a Ctrl-v prefix. We can input other non-printable and control characters using this prefix:

  • Ctrl-v <Enter> -> ^M
  • Ctrl-v <Tab> -> ^I

This is sometimes handy when conforming to someone else’s tab style, and can also be handy when searching for characters literally in searches.

Advanced Vim registers

Registers in Vim are best thought of as scratch spaces for text, some of which are automatically filled by the editor in response to certain actions. Learning how to use registers fluently has a lot of subtle benefits, although it takes some getting used to because the syntax for using them is a little awkward.

If you’re reasonably fluent with Vim by now, it’s likely you’re already familiar with the basic usage of the 26 named registers, corresponding to the letters of the alphabet. These are commonly used for recording macros; for example, to record a series of keystrokes into register a, you might start recording with qa, and finish with q; your keystrokes could then be executed with @a.

Similarly, we can store text from the buffer itself rather than commands in these registers, by prepending "a to any command which uses a register, such as the c, d, and y commands:

  • "ayy — Read current line into register a.
  • "bP — Paste contents of register b above current line.
  • "cc3w — Change three words, putting the previous three words into register c.

Like many things in Vim, there’s a great deal more functionality to registers for those willing to explore.

Note that here I’ll be specifically ignoring the *, +, and ~ registers; that’s another post about the generally unpleasant business of making Vim play nice with system clipboards. Instead, I’ll be focussing on stuff that only applies within a Vim session. All of this is documented in :help registers.

Capital registers

Yanking and deleting text into registers normally replaces the previous contents of that register. In some cases it would be preferable to append to a register, for example while cherry-picking different lines from the file to be pasted elsewhere. This can be done by simply capitalizing the name of the register as it’s referenced:

  • "ayyReplace the contents of register a with the current line.
  • "AyyAppend the current line to register a.

This works for any context in which an alphabetical register can be used. Similarly, to append to a macro already recorded in register a, we can start recording with qA to add more keystrokes to it.

Viewing register contents

A good way to start getting a feel for how all the other registers work is to view a list of them with their contents during an editing session with :registers. This will show the contents of any register used in the editing session. It might look something like this, a little inscrutable at first:

:registers
--- Registers ---
""   Note that much of it includes
"0   execut
"1   ^J^J
"2   16 Oct (2 days ago)^J^Jto Jeff, Alan ^JHi Jeff (cc Alan);^J^JPlease 
"3   <?php^Jheader("Content-Type: text/plain; charset=utf-8");^J?>^J.^J
"4   ^J
"5   Business-+InternationalTrade-TelegraphicTransfers-ReceivingInternati
"6   ../^J
"7       diff = auto^J    status = auto^J    branch = auto^J    interacti
"8   ^J[color]^J    ui = auto^J    diff = auto^J    status = auto^J    br
"9       ui = true^J
"a    escrow
"b   03wdei^R=2012-^R"^M^[0j
"c   a
"e   dui{<80>kb^[^[
"g   ^[gqqJgqqjkV>JgqqJV>^[Gkkkjohttp://tldp.org/LDP/abs/html/^[I[4]: ^[k
"h   ^[^Wh:w^Mgg:w^M^L:w^Mjk/src^Mllhh
"j   jjjkkkA Goo<80>kb<80>kb<80>kbThis one is good pio<80>kbped through a
"-   Note that much of it includes
".    OIt<80>kb<80>kb<80>kbIt might looks <80>kb<80>kb something like thi
":   register
"%   advanced-vim-registers.markdown
"/   Frij

The first column contains the name of the register, and the second its contents. The contents of any of these registers can be pasted into the buffer with "ap, where a is the name of any of them. Note that there are considerably more registers than just the named alphabetical ones mentioned above.

Unnamed register

The unnamed register is special in that it’s always written to in operations, no matter whether you specified another register or not. Thus if you delete a line with dd, the line’s contents are put into the unnamed register; if you delete it with "add, the line’s contents are put into both the unnamed register and into register a.

If you need to explicitly reference the contents of this register, you can use ", meaning you’d reference it by tapping " twice: "". One handy application for this is that you can yank text into the unnamed register and execute it directly as a macro with @".

Man, and you thought Perl looked like line noise.

Black hole register

Another simple register worth mentioning is the black hole register, referenced with "_. This register is special in that everything written to it is discarded. It’s the /dev/null of the Vim world; you can put your all into it, and it’ll never give anything back. A pretty toxic relationship.

This may not seem immediately useful, but it does come in handy when running an operation that you don’t want to clobber the existing contents of the unnamed register. For example, if you deleted three lines into the unnamed register with 3dd with the intent of pasting them elsewhere with p, but you wanted to delete another line before doing so, you could do that with "_dd; line gone, and no harm done.

Numbered registers

The read-only registers 0 through 9 are your “historical record” registers. The register 0 will always contain the most recently yanked text, but never deleted text; this is handy for performing a yank operation, at least one delete operation, and then pasting the text originally yanked with "0p.

The registers 1 through 9 are for deleted text, with "1 referencing the most recently deleted text, "2 the text deleted before that, and so on up to "9.

The small delete register

This read-only register, referenced by "-, stores any text that you deleted or changed that was less than one line in length, unless you specifically did so into some other named register. So if you just deleted three characters with 3x, you’ll find it in here.

Last inserted text register

The read-only register ". contains the text that you last inserted. Don’t make the mistake of using this to repeat an insert operation, though; just tap . for that after you leave insert mode, or have the foresight to prepend a number to your insert operation; for example, 6i.

Filename registers

The read-only register "% contains the name of the current buffer’s file. Similarly, the "# register contains the name of the alternate buffer’s file.

Command registers

The read-only register ": contains the most recently executed : command, such as :w or :help. This is likely only of interest to you if you’re wanting to paste your most recent command into your Vim buffer. For everything else, such as repeating or editing previous commands, you will almost certainly want to use the command window.

Search registers

The read-only register / contains the most recent search pattern; this can be handy for inserting the search pattern on the command line, by pressing Ctrl-R and then / — very useful for performing substitutions using the last search pattern.

Expression register

Here’s the black sheep of the bunch. The expression register = is used to treat the results of arbitrary expressions in register context. What that means in actual real words is that you can use it as a calculator, and the result is returned from the register.

Whenever the expression register is referenced, the cursor is put on the command line to input an expression, such as 2+2, which is ended with a carriage return.

This means in normal mode you can type "=2+2<Enter>p, and 4 will be placed after the cursor; in insert or command mode you can use Ctrl-R then =2+2<Enter> for the same result. If you don’t find this syntax as impossibly awkward as I do, then this may well suit you for quick inline calculations … personally, I’d drop to a shell and bust out bc for this.

Knowing your registers well isn’t as profound a productivity boost as squelching a few of the other Vim anti-patterns, but it can certainly save you some of the annoyance of lost text.

Start Vim with splits

If you want to call Vim to edit more than one file, you can add an option to the command line to open all of the buffers in split windows on startup:

  • -O — Open all buffers in vertically split windows, like :vsp
  • -o — Open all buffers in horizontally split windows, like :sp

Command line splits

The same can also be done for tabs:

  • -p — Open all buffers in tabs, like :tabnew

Command line tabs

Avoiding the arrow keys

For shell users, moving to the arrow keys on the keyboard is something of an antipattern, moving away from the home row so central to touch typists. It therefore helps to find ways to avoid using the arrow keys in order to maintain your flow.

Bash

The arrow keys in Bash are used to move back and forth on the current command line (left and right), and up and down through the command history (up and down). This leads to the old shell user’s maxim:

“Those that don’t remember history are doomed to press Up repeatedly.”

There are alternatives to both functions. To move left or right by one character on the command line without deleting characters already placed, we can use Ctrl-B and Ctrl-F.

However, to make things a bit faster, there are four other key combinations to move back and forth on a line that are worth learning too:

  • Alt-B — Move back a word
  • Alt-F — Move forward a word
  • Ctrl-A — Move to the start of the line
  • Ctrl-E — Move to the end of the line

Similarly, to move up and down through history, we can use Ctrl-P and Ctrl-N respectively. Don’t forget that rather than keep tapping one of these, you can search backward or forward through history with Ctrl-R and Ctrl-S.

Whoops, I think I just taught you some Emacs.

Vim

To avoid the arrow keys in normal mode in Vim, use h, j, k, and l instead. This can take a little getting used to, but the benefits in terms of comfort for your hands and speed is easily worth it; using the arrow keys is one of the Vim anti-patterns.

If you’re asking “How do I avoid the arrow keys to move in insert mode?”, the answer is that you shouldn’t be moving in insert mode at all; it’s inefficient. When in insert mode you should be inserting text, and maybe using backspace or delete every now and then. To move through text, switching back to normal mode is vastly more efficient.

Moving in command mode is similar. If you need to move around on the command line, in most cases you should pull up the command window so that you can edit the command in normal mode, and then just tap Enter to run it.

In general, when you start thinking about moving through any kind of text, you should reflexively hit Esc or Ctrl-[ to go into normal mode, in order to take advantage of a whole keyboard’s worth of navigation shortcuts.

Vim annoyances

Like any highly interactive application, Vim has a few annoyances even for experienced users. Most of these consist of the editor doing something unexpected, particularly with motions or the behavior of regular expressions and registers. This is often due to vi and Vim being such venerable editors; their defaults sometimes make less sense decades after their creation.

Fortunately, Vim being the configurable editor that it is, many of the more common annoyances can be easily worked around. Bear in mind that not all of these are necessarily problems; if you actually prefer the way something behaves, you should stick with it.

Cursor jumps around while joining lines

If you want to keep the cursor in place when you join lines with J, you can do this, dropping a mark before the operation to which you return afterwards:

nnoremap J mzJ`z

Jumping lands on top or bottom of screen

If you’d like to center the window automatically around the cursor after jumping to a location with motions like n (next search pattern occurrence) or } (end of next paragraph), you can arrange that by remapping to add a zz after the motion:

nnoremap n nzz
nnoremap } }zz

If you don’t need the jump to land you in the exact middle of the screen, but just don’t want it to land right at the edge, you could also use scrolloff:

set scrolloff=10

Note that this also starts scrolling the window with single-line movements like j and k at this boundary, too, which you may not want.

Skipping lines when wrap is set

By default, the j and k keys don’t move by row; they move by line. This means that if you have the wrap option set, you might skip across several rows to reach the same point in an adjacent line.

This can be frustrating if you prefer the more intuitive behavior of moving up to the character immediately above the current one. If you don’t like this behavior, you can fix it by mapping j to gj, and k to gk, which moves by rows rather than lines:

nnoremap j gj
nnoremap k gk

If you think you might need the default behavior at some point, you might want to include reverse mappings so you can move linewise with gj and gk:

nnoremap gj j
nnoremap gk k

Wrapping breaks words

By default, setting wrap displays lines by breaking words if necessary. You can force it to preserve words instead by only breaking at certain characters:

set linebreak

You can define the characters at which Vim should be allowed to break lines with the breakat option. By default this includes spaces and tabs.

Backup files are a nuisance

If you’re developing with a version control system, you might find the in-place backups Vim keeps for saved files with the ~ suffix more annoying than useful. You can turn them off completely with nobackup:

set nobackup

Alternatively, you can set a single directory for them to keep them out of the way with backupdir:

set backupdir=~/.vim/backup

Swap files are a nuisance

Swap files can be similarly annoying, and unnecessary on systems with a lot of memory. If you don’t need them, you can turn them off completely:

set noswapfile

If you do find the swap files useful but want to prevent them cluttering your current directory, you can set a directory for them with directory:

set directory=~/.vim/swap

Accidentally hitting unwanted keys in normal mode

Some of the keys in normal mode bring up functions that aren’t terribly useful to a lot of people, and tend to accidentally get hit when Caps Lock is on, or when aiming for another key. Common nuisance keys are:

  • F1 for help; :help is generally more useful for the experienced user
  • Q to start ex mode; annoying when you intended to start recording a macro with q
  • K to bring up a man page for the word under the cursor; annoying when you’re not writing in C or shell script, and there isn’t a sensible choice of keywordprg for your chosen language

The simplest way to deal with these is to remap them to <nop> so that they don’t do anything:

nnoremap <F1> <nop>
nnoremap Q <nop>
nnoremap K <nop>

Startup message is irritating

If you don’t like the startup message that appears when you open Vim without a filename, you can remove it by adding the I flag to shortmess:

set shortmess+=I

Can’t backspace past start of operation

If you’re in insert mode, by default you can’t use backspace to delete text past the start of the insert operation; that is, you can’t backspace over where you first pressed insert. This is old vi behavior, and if you don’t like it, you can make backspace work everywhere instead:

set backspace=indent,eol,start

Flashing screen is annoying

If you don’t require the error feedback, you can turn off the flashing screen for the “visual bell”:

set visualbell t_vb=

Don’t know what mode I’m in

If you lose track of the current mode, you can get a convenient --INSERT-- indicator at the bottom of the screen with:

set showmode

If you’re having this problem a lot, however, you might want to take stock of how much time you’re spending in insert mode when you’re not actively typing; it’s good Vim practice to stay out of it otherwise, even when you stop to think.

Keep making typos of common commands

If you’re fat-fingering :wq and similar commands a lot due to a sticky shift key, take a look at the Vim command typos fix. Also, don’t forget about ZZ and ZQ as quicker alternatives to :wq and :q!.

Don’t want case sensitive patterns

If you don’t care for case-sensitive searches and substitutions, you can turn it off completely:

set ignorecase

You might find the slightly cleverer behavior of smartcase is better, though. This option only applies case sensitivity if at least one of the letters in the pattern is uppercase; otherwise, case is ignored.

set smartcase

Doesn’t replace all occurrences

The default behavior for the substitute operation, :s/pattern/replacement/, is to replace only the first occurrence of the pattern. To make it replace all occurrences on the appropriate lines, you add the g suffix. If you find that you never need to substitute for only the first occurrence of a pattern in a line, you can add that flag to the patterns by default:

set gdefault

If you do happen to need to replace only the first occurrence one day, you can get the default behavior back by adding the g suffix to your pattern; its meaning is reversed by this option.

Can’t move into blank space in visual block mode

If you need to define a block in visual block mode with bounds outside the actual text (that is, past the end of lines), you can allow this with:

set virtualedit=block

This will let you move around the screen freely while in visual block mode to define your selections. As an example, this can make selecting the contents of the last column in a formatted table much easier.

Filename completion on command line is confusing

If you’re used to the behavior of shell autocomplete functions for completing filenames, you can emulate it in Vim’s command mode:

set wildmode=longest,list

With this set, the first Tab press (or whatever your wildchar is set to) will expand a filename or command in command mode to the longest common string it can, and a second press will display a list of all possible completions above the command line.

Yanking lines is inconsistent

D deletes from the cursor to the end of the line; C changes from the cursor to the end of the line. For some reason, however, Y yanks the entire line, both before and after the cursor. If this inconsistency bothers you, you can fix it with a remapping:

nnoremap Y y$

New splits appear in unintuitive places

If your language of choice is read from left to right, you may find it annoying that by default Vim places new vertical splits to the left of the current pane, and horizontal splits above the current pane. You can fix both:

set splitbelow
set splitright

Caps Lock sends Vim crazy

Caps Lock in normal mode makes Vim go haywire. This isn’t really Vim’s fault; Caps Lock is generally a pretty useless key. It’s often useful for Vim users to remap it, so that it sends the same signal as a more useful key; Control and Escape are common choices. You might even find this reduces strain on your hands.

Several of these fixes were inspired by Steve Losh’s .vimrc file. Thanks also to commenters Alpha Chen and Rob Hoelz for suggestions.

Vim misconceptions

Vim isn’t the best tool for every task, and there’s no reason you shouldn’t stick to your GUI IDE if you know it like the back of your hand and are highly productive in it. The very basic best practices for text editing in general apply just as well to more familiar editing interfaces as they do to Vim, so nobody should be telling you that Vim is right for everyone and everything and that you’re wrong not to use it.

However, because Vim and vi-like editors in general have a lot of trouble shaking off the connotations of their serverside, terminal-only, mouseless past, there are a few persistent objections to even trying Vim that seem to keep cropping up. If you’re someone curious about Vim but you heard it was useless for any of the following reasons, or if you’re an experienced user looking to convince a hesitant neophyte to try Vim, the following list might clear a few things up.

Vim takes too long to learn

If you want analogues to all of the features in your IDE, that would likely take some time, just as it would in any other new editor. However, if all you need to start is to be able to enter text, move around, and load and save files, you just need to know:

  • i to enter insert mode, Esc to leave it
  • Arrow keys to move around in both modes
  • :e <filename> to load a document
  • :w <filename> to save a document
  • :q to quit, :q! to ignore unsaved changes

To do pretty much everything Windows Notepad would let you do, on top of that you’d only need to learn:

  • dd to cut a line
  • yy to copy a line
  • p to paste a line
  • /<pattern> to search for text
  • n to go to the next result
  • :s/pattern/replacement to replace text

From that point, you only get faster as you learn how to do new things. So saying that Vim takes weeks to learn is a bit disingenuous when the essentials can easily be mastered with a few minutes’ practice.

Granted, the arrow keys are a bit of an anti-pattern, but you can worry about that later.

Vim has no GUI

Vim has a GUI version called Gvim for both Windows and Unix. For Mac OS X, the MacVim port is preferred. For experienced users the GUI’s only real advantage over the terminal version is a wider color palette, but it has a toolbar and other GUI elements which some new users may find useful.

Vim doesn’t have spell checking

Vim allows spell checking with system dictionaries, using :set spell and :set spelllang. Misspelt and unknown words are highlighted appropriately.

Vim doesn’t have syntax highlighting

Vim has support for syntax highlighting that can be turned on with :syntax enable, for a very wide variety of programming languages, markup languages, and configuration file syntaxes.

Vim only allows eight colours

This is a limitation of terminal emulators rather than of Vim itself, but most modern GUI terminal emulators allow 256 colours anyway with a little extra setup. The GUI version, Gvim, has full color support with the familiar rrggbb color definitions.

Vim doesn’t have class/function folding

Vim does in fact have support for folding, based on both code structure and manually defined boundaries. See :help folding for details.

Vim doesn’t have autocompletion

Vim allows basic completion using words already in the current buffer, and also more advanced omnicompletion using language dictionaries for constants, variables, classes, and functions.

Vim doesn’t have a file browser

Vim has had the Netrw plugin bundled for some time, which provides a pretty capable filesystem browser.

Vim can’t do network editing

Again, the bundled Netrw plugin handles this. Editing files over FTP and SCP links is pretty transparent. You can open a file on a remote server by entering the following, which will prompt for your username and password:

:e ftp://ftp.example.com/index.html

When you’re done editing, you just enter :w to save the file, and it’s automatically uploaded for you. You can record your FTP credentials in a .netrc file to save having to type in usernames and passwords all the time. URIs with scp:// work the same way; with a good public key infrastructure set up, you can use Vim quite freely as a network-transparent editor.

Vim doesn’t have tabs or windows

The model Vim uses for tabs and windows is rather different from most GUI editors, but both are supported and have been for some time.

Vim has too many modes

It has three major modes: normal mode, insert mode, and command mode. There’s a fourth that’s Vim-specific, called visual mode, for selecting text.

Most editors are modal in at least some respect; when you bring up a dialog box, or enter a prefix key to another command, you’re effectively changing modes. The only real difference is that context shifts in Vim are at first less obvious; the screen doesn’t look too different between normal, insert, and command mode.

The showmode option helps to distinguish between insert and normal mode, a common frustration for beginners. This gets easier when you get into the habit of staying out of insert mode when not actually entering text.

Vim doesn’t work with the mouse

Vim works fine with the mouse, in both Gvim and xterm-like terminal emulators, if you really want it. You can change the position of the cursor, scroll through the document, and select text as normal. Setting the below generally does the trick:

:set mouse=a

However, even a little experience in Vim may show you that you don’t need the mouse as much as you think. Careful use of the keyboard allows much more speed and precision, and it’s quite easy to run a complex editing session without even moving from the keyboard’s “home row”, let alone all the way over to the mouse.

Vim doesn’t do Unicode

Vim supports Unicode encodings with the encoding option. It’s likely you’ll only need to put the below in your .vimrc file and then never really think about encoding in your editor again:

:set encoding=utf-8

Vim isn’t being developed or maintained

The original author of Vim, and its current maintainer and release manager, is Bram Moolenaar. At the time of writing, he is working for Google, and is paid to spend some of his time developing Vim. The development mailing list for Vim is very active, and patches are submitted and applied to the publically accessible Mercurial repository on a regular basis. Vim is not a dead project.

Vim is closed source

Vim isn’t proprietary or closed source, and never has been. It uses its own GPL-compatible license called the Vim license.

The original vi used to be proprietary because Bill Joy based the code on the classic UNIX text editor ed, but its source code has now been released under a BSD-style license.