Learn Practice Daily golf Reference
The Vim Way·Lesson 1 of 7·7 min·0/10 exercises

Meet the dot command

. repeats your last change, like a rubber stamp: ink it once with a change, then stamp it anywhere.

Scene

Day four, 8:50 a.m. The price migration starts today. Before any new price can go in, the new menu service needs forty lines across the menu files brought into its format, each with one small, repetitive fix.

You could make each fix by hand, forty times. Or you could make it once and let the smallest key on the keyboard do the other thirty-nine.

From memory

Warm-up from earlier chapters

Two from earlier chapters, from memory, before the new idea. Two wrong tries show the answer.

Open a fresh line below and start typing.
press the keys…
1 of 2
Open a fresh line below and start typing.

Ink once, stamp anywhere

Every Byte Burrito bag gets its logo from one rubber stamp: ink it once, then stamp, stamp, stamp. . is that stamp. Make a change once, and that inks it. Then press . wherever the cursor is, and Vim makes the same change there.

Before
export interface MenuItem {
id: string;
name: string;
price: number;
}
Ireadonly Esc
export interface MenuItem {
readonly id: string;
name: string;
price: number;
}
j.
export interface MenuItem {
readonly id: string;
readonly name: string;
price: number;
}
j.
export interface MenuItem {
readonly id: string;
readonly name: string;
readonly price: number;
}
Ink the stamp once (I, type readonly, Esc), then every j . stamps the next line.
1const tax = 0.0875
1const tip = 0.15
2const fee = 2.5
3const rush = 45
NORMALLoading the editor…1:1
Try it

Stamp it

The new menu service wants every field readonly. Ink the stamp on the first field with I, then j . down the rest.

Fix the marked spots · 4 left
1export interface MenuItem {
2 id: string;
1 name: string;
2 price: number;
3 spicy: boolean;
4}
NORMALLoading the editor…0.0s2:3

This exercise needs a keyboard. Read on, and play it at your computer.

One change, one stamp

The stamp holds exactly one change. Everything from entering Insert mode to pressing Esc counts as one, however much you typed, and so does a single command like x. Make a different change and you have a new stamp: . always repeats the last one.

Check yourself

What did you ink?

1log("ready")
1log("set")
NORMAL
Keys pressed: A;Escj.

You press A, type ;, press Esc, then j and .. What happens on line 2?

Pick an answer (or press its number), then watch the engine prove it.
Try it

Drop the dollar signs

The new service adds the currency itself, so the $ in each old price has to go. Get to the first one, x it, then stamp the rest.

Fix the marked spots · 4 left
1export const OLD_PRICES = [
1 "$9.50",
2 "$8.25",
3 "$10.00",
4 "$11.00",
5];
NORMALLoading the editor…0.0s1:1

This exercise needs a keyboard. Read on, and play it at your computer.

A stamp in the wrong place

The stamp always holds your last change, so check what you inked last before you stamp. Stamped the wrong thing somewhere? The undo button from your first morning, u, lifts the last change off again: one u, one stamp.

Check yourself

Which stamp is inked?

1const TIP = 0.15;;
1const FEE = 2.5
NORMAL
Keys pressed: xj.

TIP has a doubled ;, so you x the extra one. Then you press j and ., hoping to add a ; to FEE. What happens?

Pick an answer (or press its number), then watch the engine prove it.
Try it

Lift the wrong stamp

That just happened in prices.ts. Take the wrong stamp back with u, then ink the right one and stamp it on the next line.

1 of 2Your x was the last change, so j . stamped an x on the 5. Take it back: u.
2const TAX = 0.0875;
1const TIP = 0.15;
3const FEE = 2.5
1const RUSH = 45
NORMALLoading the editor…1/20.0s3:14

This exercise needs a keyboard. Read on, and play it at your computer.

Try it

Semicolon runs

Before it was switched off, the Formatter took the semicolons off whole runs of lines in files nobody had checked yet. Fix the first line of each run with A, then stamp your way down.

1 of 3Fix the marked spots · 3 left
1export const menu = [
1 { id: "al-pastor", name: "Al Pastor", price: 9.5, spicy: true },
2 { id: "veggie", name: "Garden Veggie", price: 8.25, spicy: false },
3 { id: "carnitas", name: "Carnitas", price: 10, spicy: false },
4];
5
6export function findItem(id: string) {
7 const item = menu.find((m) => m.id === id);
8 if (!item) throw new Error("not on the menu: " + id);
9 return item;
10}
NORMALLoading the editor…1/30.0s1:1

This exercise needs a keyboard. Read on, and play it at your computer.

From memory

Stamp, from memory

Read the situation, press the keys.

Repeat the last change, right here.
scroll here, then press the keys
1 of 3
Repeat the last change, right here.
Challenge

Price stamp

Four runs of lines across the codebase, each missing its semicolons. Ink once per run, then stamp. A clock times the run for your own records.

Stuck? Show a hintfirst line of a run: A;<Esc> · each line after: j.
1 of 4Fix the marked spots · 4 left
1function averageRating(reviews: Review[]) {
1 if (reviews.length === 0) return 0;
2 const sum = reviews.reduce((acc, r) => acc + r.stars, 0);
3 const avg = sum / reviews.length;
4 return Math.round(avg * 10) / 10;
5}
6
7const best = reviews.filter((r) => r.stars === 5);
8console.log("five-star reviews:", best.length);
NORMALLoading the editor…1/40.0s1:1

This exercise needs a keyboard. Read on, and play it at your computer.

Boss round

Currency day

The last file before the menu service will start: three different changes, each needed four times. Ink a stamp, use it, ink the next. Semicolons on the Order fields, no $ in the old prices, and export in front of the four constants.

Stuck? Show a hintA;<Esc> then j. j. j. · x then j. j. j. · Iexport <Esc> then j. j. j.
1 of 3Fix the marked spots · 4 left
1export interface Order {
1 id: string;
2 items: string[];
3 total: number;
4 paid: boolean;
5}
6
7export const OLD_PRICES = [
8 "$9.50",
9 "$8.25",
10 "$10.00",
11 "$11.00",
12];
13
14const TAX = 0.0875;
15const TIP = 0.15;
16const FEE = 2.5;
17const RUSH = 45;
NORMALLoading the editor…1/30.0s1:1

This exercise needs a keyboard. Read on, and play it at your computer.

The menu service startsFinish the exercise above to see it.

Extra practice optional

The chapter is done. These rounds keep going as long as you like: stop whenever it stops being useful.

Endless

Stamp forever

Endless runs of lines that lost their semicolons, in bigger batches as you go. One A each, then stamps.

Level 1Fix the marked spots · 3 left
1const MAX_DISTANCE_KM = 8;
1const riders = await loadRiders({ online: true });
2const nearest = riders.sort((a, b) => a.distance - b.distance)[0];
3if (!nearest || nearest.distance > MAX_DISTANCE_KM) {
4 return refund(order, "No rider nearby, sorry!");
5}
6assign(order, nearest);
7log("assigned", order.id, nearest.name);
NORMALLoading the editor…lv 1 · 0 done0.0s1:1

This exercise needs a keyboard. Read on, and play it at your computer.