Skip to content

01.The Vim Way

Tip 1. Meet the Dot Command

The dot command lets us repeat the last change. It is the most powerful and versatile command in Vim.

Vim’s documentation simply states that the dot command “repeats the last change” (see :h . ).

What is a change?

To understand the power of the dot command, we have to realize that the “last change” could be one of many things. A change could act at the level of individual characters, entire lines, or even the whole file.

md
Line one
Line two
Line three
Line four
  • x deletes the character under the cursor (change on individual characters)
  • dd deletes the current line (change on entire lines)
  • >G increases the indentation from the current line until the end of the file (change on the whole file)

The x, dd, and > commands are all executed from Normal mode, but we also create a change each time we dip into Insert mode. From the moment we enter Insert mode (by pressing i, for example) until we return to Normal mode (by pressing <Esc>), Vim records every keystroke. After making a change such as this, the dot command will replay our keystrokes.

The Dot Command Is a Micro Macro

Later, in Chapter 11, Macros, we’ll see that Vim can record any arbitrary number of keystrokes to be played back later. This allows us to capture our most repetitive workflows and replay them at a keystroke. We can think of the dot command as being a miniature macro, or a “micro” if you prefer.

We’ll see a few applications of the dot command throughout this chapter. We’ll also learn a couple of best practices for working with the dot command in Tip 9, Compose Repeatable Changes, and Tip 23, Prefer Operators to Visual Commands Where Possible.

Tip 2. Don't Repeat Yourself

For such a common use case as appending a semicolon at the end of a series of lines, Vim provides a dedicated command that combines two steps into one.

Reduce Extraneous Movement

js
var foo = 1;
var bar = "a";
var foobar = foo + bar;

Practice Problems

  1. How to add semicolons at the end?
  2. How to delete semicolons at the end?
  3. How do I delete the last character in each line using Vim?
md
12345a
123456b
1234567c
12345678d
123456789e

Answer: :53,57s/.$/

All these commands in Normal mode switch to Insert mode:

  • i switch to Insert mode before the cursor
  • I insert text at the beginning of the line
  • a appends after the current cursor position
  • A appends at the end of the current line
  • o open a new line below the current one
  • O open a new line above the current one
  • cw cut to the end of current word and switch to Insert mode
  • cc cut the entire line and switch to Insert mode
  • s cut the current character and switch into Insert mode
  • S cut the entire line and switch to Insert mode

Exit from Insert to Normal mode

  • <Esc> or <C-[> exit Insert mode

From the moment we enter Insert Mode (by pressing i) until we return to Normal mode (by pressing <Esc>), Vim records every keystroke.

md
This is a test line to play around with the following commands.

Two for the Price of One

Compound CommandEquivalent in Longhand
Cc$
scl
S^C
I^i
A$a
oA<CR>
Oko

Question

  • s vs xi: how do they affect registers differently?
  • S vs ddi: how do they affect registers differently?

Tip 3. Take One Step Back, Then Three Forward

We can pad a single character with two spaces (one in front, the other behind) by using an idiomatic Vim solution. At first it might look slightly odd, but the solution has the benefit of being repeatable, which allows us to complete the task effortlessly.

js
var foo = "method(" + argument1 + "," + argument2 + ")";
  • f{char} tells Vim to look ahead for the next occurrence of the specified character and then move the cursor directly to it if a match is found
  • we could jump to the next occurrence by repeating the f+ command, or
  • ; will repeat the last search that the f command performed
  • x deletes a character in Normal mode
  • s deletes a character and enters Insert mode

Tip 4. Act, Repeat, Reverse

IntentActRepeatReverse
Make a change{edit}.u
Scan a line for next characterf{char} or t{char};,
Scan a line for previous characterF{char} or T{char};,
Scan document for next match/pattern<CR>nN
Scan document for previous match?pattern<CR>nN
Perform substitution:s/target/replacement&u
Execute a sequence of changesqx{changes}q@xu

Table 1 — Repeatable Actions and How to Reverse Them

  • :s%/target/replacement change the 1st matched occurrence
  • :s%/target/replacement/g change all occurrences without "confirming each substitution"
  • :s%/target/replacement/gc change all occurrences, 1 by 1 "confirming each substitution"

Tip 5. Find and Replace by Hand

Vim has a :substitute command for find-and-replace tasks, but with this alternative technique, we'll change the first occurrence by hand and then find and replace every other match one by one. The dot command will save us from labor, but we'll meet another nifty one-key command that makes jumping between matches a snap.

md
...We're waiting for content before the site can go live...
...If you are content with this, let's go ahead with it...
...We'll launch as soon as we have the content...

Suppose that we want to use the word "copy" instead of "content". We can just use the substitute command:

Method 1 (replacement for the entire file)

  • :%s/content/copy/g

Method 2 (search without typing)

  • * command executes a search for the word under the cursor
    • the cursor will jump to the next match, and
    • all occurrences will be highlighted
  • cw command deletes to the end of the word and then drops us into Insert mode
  • during a search, press the n key, our cursor advances to the next occurrence

If you don't see any highlighting, try running :set hlsearch command.

Method 2 is equivalent to :s%/target/replacement/gc

Tip 6. Meet the Dot Formula

Summarizes Tip 2 3 5

The Ideal: One Keystroke to Move, One Keystroke to Execute