I’ve written another new article over on Vimways for the 2018 Vim advent calendar. This is a followup to my previous article, adding some more detail about ways to use Vim’s runtime directory structure.
Category Archives: Vim
Vimways: From .vimrc to .vim
Link
I’ve written a new article over on Vimways for the 2018 Vim advent calendar. It’s about converting a long and unwieldy .vimrc
into a ~/.vim
runtime directory.
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, —
Or a COPYRIGHT SYMBOL:
<©> 169, \251, U+00A9 COPYRIGHT SIGN, ^KCo, ^KcO, :copyright:, ©
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 MARKCtrl-v u 2019
->’
, a RIGHT SINGLE QUOTATION MARKCtrl-v u 2014
->—
, an EM DASHCtrl-v u 00a9
->©
, a COPYRIGHT SIGN
These are handy in some cases when writing HTML documents, as an alternative to
using HTML entities like —
or ©
. 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 registera
."bP
— Paste contents of registerb
above current line."cc3w
— Change three words, putting the previous three words into registerc
.
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:
"ayy
— Replace the contents of registera
with the current line."Ayy
— Append the current line to registera
.
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
The same can also be done for tabs:
-p
— Open all buffers in tabs, like:tabnew
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 wordAlt-F
— Move forward a wordCtrl-A
— Move to the start of the lineCtrl-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 userQ
to startex
mode; annoying when you intended to start recording a macro withq
K
to bring up aman
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 ofkeywordprg
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 lineyy
to copy a linep
to paste a line/<pattern>
to search for textn
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.