Learn Practice Daily golf Reference
Foundations·Lesson 2 of 6·7 min·0/7 exercises

Move without the mouse

h j k l keep your fingers on the home row. Counts like 5j multiply any motion, the gutter tells you the count, and you walk the kitchen file to fix a ticket that prints twice.

Scene

10:20 a.m. The next ticket says a kitchen ticket prints twice, and the bug is somewhere in kitchen.ts, a dozen lines down. The mouse is in the drawer. Your right hand starts drifting toward the arrow keys, a trip to the far corner of the keyboard and back every time you want to move.

Stop it halfway. Everything you need is already under your fingers, on the home row where they live.

From memory

Warm-up from earlier chapters

One from an earlier chapter, from memory, before the new idea. Two wrong tries show the answer.

Start typing right before the cursor.
press the keys…
1 of 1
Start typing right before the cursor.

Four keys, no trip

In Normal mode, four keys under your right hand move the cursor, so you never leave home: h left, j down, k up, l right. The shapes help: j has a hook that hangs down, k is the tall one that reaches up, and h and l sit on the left and right ends.

h
const tip = order.total * 0.15;
const pay = order.total + tip;
await charge(user, pay);
j
const tip = order.total * 0.15;
const pay = order.total + tip;
await charge(user, pay);
k
const tip = order.total * 0.15;
const pay = order.total + tip;
await charge(user, pay);
l
const tip = order.total * 0.15;
const pay = order.total + tip;
await charge(user, pay);
One press each, from the same cursor: the outline is where you start, the solid block is where you land.
1const tip = order.total * 0.15;
1const pay = order.total + tip;
2await charge(user, pay);
NORMALLoading the editor…1:7
Try it

First steps

Walk onto each green square with h j k l. They start close.

1 of 6Move the cursor onto the
1export async function placeOrder(cart: Cart, user: User) {
1 const total = cart.items.reduce((sum, i) => sum + i.price, 0);
2 const discount = user.isStudent ? total * 0.1 : 0;
3 const order = await db.orders.insert({ userId: user.id, total, discount });
4 await notify(user.phone, "Your burrito is on its way!");
NORMALLoading the editor…1/60.0s1:1

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

Counts multiply

Put a number in front of a motion and Vim repeats it: 5j is five steps down in one breath, and 3l is three to the right. Two keys instead of five, and no counting presses while you go.

1export class Kitchen {
1 private queue: Order[] = [];
2 private busy = false;
3
4 enqueue(order: Order) {
5 this.queue.push(order);
6 this.startNext();
7 }
8
NORMALLoading the editor…1:1

The gutter is a ruler

Look at the line numbers beside the code: they work like a ruler laid along the file. Your line shows its real number; every other line shows how far away it is. The line you want says 4? Press 4j. You never count lines yourself; you read the number off the gutter.

Check yourself

Off by one?

1 startNext() {
1 if (this.busy || this.queue.length === 0) return;
2 this.busy = true;
3 const next = this.queue.shift();
4 cook(next).then(() => this.finish());
5 }
NORMAL
Keys pressed: 4j

The cursor is on startNext(). You press 4j. Which line does it land on?

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

Count, then move

Read the distance off the gutter and jump in one go: 3j instead of j j j. Par assumes you use counts.

1 of 6Move the cursor onto the
1export class Kitchen {
1 private queue: Order[] = [];
2 private busy = false;
3
4 enqueue(order: Order) {
5 this.queue.push(order);
6 this.startNext();
7 }
8
9 startNext() {
10 if (this.busy || this.queue.length === 0) return;
11 this.busy = true;
12 const next = this.queue.shift();
13 printTicket(next);
14 printTicket(next);
15 cook(next).then(() => this.finish());
16 }
17}
NORMALLoading the editor…1/60.0s1:1

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

From memory

Which way?

Read the situation, press the keys.

One line down.
scroll here, then press the keys
1 of 5
One line down.
Challenge

Menu walk

The menu is being reprinted and every line needs a look before it goes out. Twelve stops across menu.ts, getting further apart as you go. Counts welcome.

1 of 12Move the cursor onto the
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/120.0s1:1

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

Boss round

Kitchen tickets

The double print is in this file. Follow an order through kitchen.ts the way the kitchen does, stop by stop, and you'll walk straight into it: two printTicket lines, one after the other. Then fix it: at the start of the second one, type two slashes and a space (// then a space). Two slashes turn a line into a comment, a note the computer skips.

On the way you'll lose your place a few times, on purpose. The gutter says how far back.

Stuck? Show a hintRead the gutter, then one count: 4j, 9k, 14j… On the second printTicket line: i// <Esc>
1 of 14The orders waiting their turn: private queue.
1export class Kitchen {
1 private queue: Order[] = [];
2 private busy = false;
3
4 enqueue(order: Order) {
5 this.queue.push(order);
6 this.startNext();
7 }
8
9 startNext() {
10 if (this.busy || this.queue.length === 0) return;
11 this.busy = true;
12 const next = this.queue.shift();
13 printTicket(next);
14 printTicket(next);
15 cook(next).then(() => this.finish());
16 }
17}
NORMALLoading the editor…1/140.0s1:1

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

One order, one ticketFinish 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

Keep walking

Endless targets on fresh code every ten goals, a little further each level. Stop whenever you like.

Level 1Move the cursor onto the
1export async function placeOrder(cart: Cart, user: User) {
1 const total = cart.items.reduce((sum, i) => sum + i.price, 0);
2 const discount = user.isStudent ? total * 0.1 : 0;
3 const order = await db.orders.insert({ userId: user.id, total, discount });
4 await notify(user.phone, "Your burrito is on its way!");
5 return order.id;
6}
NORMALLoading the editor…lv 1 · 0 done0.0s1:1

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