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

Compound commands

A I C S o O are combos: a motion and a change in one key, so . repeats them from anywhere on the line.

Scene

2:15 p.m. The specials board lives in specials.ts, and the kitchen has changed its mind about half of it. Line endings to rewrite, whole lines to replace.

You've used A since your first night. What you haven't noticed is why it works so well with this morning's stamp, and that it has siblings for rewriting a line's ending or the whole line.

From memory

Warm-up from earlier chapters

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

Slide to the next copy of the character you last found.
press the keys…
1 of 2
Slide to the next copy of the character you last found.

Two for one

The Byte Burrito menu has combos: a burrito and a drink, one order, one price. Vim has them too. A is $ and a ordered as one key; I is ^ and i; o is A plus a new line. The doors from that 3 a.m. call were combos all along.

Check yourself

Order them separately

1let a = 1
1let total = 2
NORMAL
Keys pressed: $a;Escj.

You add a ; to line 1 with $ a ; Esc, then press j and .. What does line 2 become?

Pick an answer (or press its number), then watch the engine prove it.
1const tax = 0.0875
2const tip = 0.15
1const fee = 2.5
NORMALLoading the editor…2:15
Try it

Combos from anywhere

Semicolons missing again. A once, then j . from wherever the cursor lands: the combo carries the jump to the end.

1 of 3Fix 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…1/30.0s1:1

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

C: the rest of the line

C deletes from the cursor to the end of the line and starts Insert mode: a delete and a door in one order. Perfect for a line whose start is right and whose end is wrong.

Before
const theme = "light"; // default
C"dark";Esc
const theme = "dark";
C takes everything from the cursor to the end of the line, comment included, and you type the new ending.
Try it

New endings

The end of each line is wrong. Get to where the wrong part starts, then C and type the right ending.

1 of 4Change the red text to base * 0.2 : 0
1export function happyHour(item: Item, hour: number) {
1 const base = item.price * item.qty;
2 const off = hour >= 17 && hour < 19 ? TODO;
3 const tax = (base - off) * TAX_RATE;
4 const total = base - off + tax + item.tip;
5 log("happy hour", item.id, base, off, total);
6 return Math.round(total * 100) / TODO;
7}
8
9export const LIMITS = { maxQty: 12, maxTip: 20, rushMinutes: 45 };
NORMALLoading the editor…1/40.0s1:1

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

S: the whole line

S clears the whole line and starts Insert mode, from anywhere on the line, keeping the indentation (see the note below for Vim). When nothing on a line is worth keeping, it's the cheapest combo on the menu.

Before
function first(items) {
return null;
}
Sreturn items[0];Esc
function first(items) {
return items[0];
}
S from the middle of the line: the indentation stays, everything else is retyped.
Try it

Start the line over

Each marked line is junk where code should be. S and type the line back.

1 of 4Change the red text to export const menu = [
1lorem ipsum dolor;export 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 lorem ipsum dolor;
10}
NORMALLoading the editor…1/40.0s1:1

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

From memory

Order the combo

From memory: one key, then type if you need to.

Start typing at the end of the line.
scroll here, then press the keys
1 of 5
Start typing at the end of the line.
Challenge

Rewrite the specials

Wrong endings, junk lines and missing semicolons across the codebase. Pick the combo that needs the least walking each time.

1 of 9Change the red text to export const config = {
1lorem ipsum dolor;export const config = {
1 apiUrl: "https://api.byteburrito.dev",
2 currency: "USD",
3 TODO;
4 openHour: 11,
5 closeHour: 23,
6 slogan: "Code by day, burritos null; // ???
7};
NORMALLoading the editor…1/90.0s1:1

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

Boss round

The specials board

The board goes up at 4. The header needs (updated daily) on its end. Tuesday's special is still a TODO: it should read "Burrito of the day",. A junk line sits where Thursday's thursday: "Free guac", should be, and friday: "Happy hour from 5", is missing altogether, right after it. One combo each; pick the one that needs the least walking.

Stuck? Show a hintheader: A · Tuesday, from the first quote: C · the junk line: S · Friday, from Thursday: o
1 of 4Type ·(updated daily) where it's shown in green
1// specials board·(updated daily)
1export const specials = {
2 monday: "Two-for-one burritos",
3 tuesday: "TODO",
4 wednesday: "Half-price churros",
5 /* ??? */
6};
NORMALLoading the editor…1/40.0s1:1

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

The board goes upFinish 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

Combo kitchen

Endless endings, junk lines and semicolons. Pick the combo, fix it, move on.

Level 1Change the red text to ZONES = [
1// delivery zones: where riders go, and what it costs to get there
1export const 42;ZONES = [
2 { name: "Little Havana", lat: 25.7656, lng: -80.219, fee: 2.5 },
3 { name: "Brickell", lat: 25.7663, lng: -80.1917, undefined;
4 { name: "Wynwood", lat: 25.8005, lng: -80.1994, fee: 3 },
5 { name: "Coral Way", lat: 25.7505, lng: -80.2409, fee: 3.5 },
6 { name: "Downtown", lat: 25.7743, lng: -80.1937, null; // ???
7 { name: "Edgewater", lat: 25.8001, lng: -80.1887, fee: 3 },
8];
9
10export function zoneFor(lat: number, null; // ???
11 return ZONES.find((z) => Math.abs(z.lat - lat) < 0.01 && Math.abs(z.lng - lng) < 0.01);
12}
NORMALLoading the editor…lv 1 · 0 done0.0s1:1

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