← Back to all projects

LEARN VIM MOTIONS

Most text editors (Notepad, VS Code, Sublime) treat text as a simple string of characters. You place a cursor and insert/delete characters. This is Modeless editing. It's intuitive, but inefficient.

Learn Vi Motions: The Language of Text Editing

Goal: Wire your brain to speak the “grammar” of Vim. Stop editing character-by-character and start editing by word, sentence, block, and logic.


Why Vim Motions Matter

Most text editors (Notepad, VS Code, Sublime) treat text as a simple string of characters. You place a cursor and insert/delete characters. This is “Modeless” editing. It’s intuitive, but inefficient.

Vim is a Modal editor. It treats text as Structured Objects (words, sentences, paragraphs, code blocks).

To master Vim, you must stop thinking:

  • “Move cursor right 5 times, backspace 3 times, type ‘hello’.”

And start thinking:

  • “Change inside quotes” (ci")
  • “Delete until next comma” (dt,)
  • “Copy this paragraph” (yap)

You are not learning a set of shortcuts (like Ctrl+C). You are learning a Language.

The Grammar of Vim

Vim commands follow a linguistic structure: Verb + Adjective + Noun.

┌─────────────────────────────────────────────────────────────────────────────┐
│                         THE VIM COMMAND GRAMMAR                             │
└─────────────────────────────────────────────────────────────────────────────┘

    ┌──────────────────────────────────────────────────────────────────────┐
    │                         COMMAND STRUCTURE                             │
    │                                                                       │
    │      [COUNT] + OPERATOR + [COUNT] + MOTION/TEXT-OBJECT               │
    │                                                                       │
    │      Example: 2      d           3     w                             │
    │               ↓      ↓           ↓     ↓                             │
    │            "twice" "delete"  "three" "words"                         │
    │                                                                       │
    │      Result: Delete 6 words (2 × 3 = 6)                              │
    └──────────────────────────────────────────────────────────────────────┘

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────────────────┐
│    OPERATORS    │    │    MODIFIERS    │    │       MOTIONS/OBJECTS       │
│    (Verbs)      │    │   (Adjectives)  │    │         (Nouns)             │
├─────────────────┤    ├─────────────────┤    ├─────────────────────────────┤
│ d = delete      │    │ i = inner       │    │ w = word    W = WORD        │
│ c = change      │    │ a = around      │    │ s = sentence                │
│ y = yank (copy) │    │ t = till        │    │ p = paragraph               │
│ v = visual      │    │ f = find        │    │ b = back word               │
│ > = indent      │    │ 2,3,4 = count   │    │ e = end of word             │
│ < = outdent     │    │                 │    │ } = next paragraph          │
│ = = format      │    │                 │    │ { = prev paragraph          │
│ g~ = toggle case│    │                 │    │ " = quotes   ' = quotes     │
│ gu = lowercase  │    │                 │    │ ( ) = parentheses           │
│ gU = uppercase  │    │                 │    │ { } = braces   [ ] = brackets│
└─────────────────┘    └─────────────────┘    └─────────────────────────────┘

                    ┌───────────────────────────────────────┐
                    │         EXAMPLE COMBINATIONS          │
                    ├───────────────────────────────────────┤
                    │ d   + i   + w   = delete inner word   │
                    │ c   + a   + "   = change around "     │
                    │ y   + 2   + j   = yank 2 lines down   │
                    │ >   + i   + {   = indent inner block  │
                    │ gU  + a   + p   = UPPERCASE paragraph │
                    └───────────────────────────────────────┘

Vim Command Grammar

  1. Verbs (Operators): What you want to do.
    • d: Delete
    • c: Change (delete + insert)
    • y: Yank (copy)
    • v: Visual select
    • >: Indent
  2. Adjectives (Counts/Modifiers): How many or which one.
    • 3: Three times
    • i: Inside
    • a: Around
  3. Nouns (Motions/Objects): The target.
    • w: Word
    • s: Sentence
    • p: Paragraph
    • t": Tag (HTML/XML)
    • }: Block

Examples:

  • d2w: Delete (verb) 2 (adjective) words (noun).
  • ci(: Change (verb) inside (adjective) parentheses (noun).

Core Concept Analysis

1. The Modes: Why “Normal” is Normal

In other editors, you are always in “Insert Mode”. In Vim, you spend most of your time in Normal Mode.

┌─────────────────────────────────────────────────────────────────────────────┐
│                           VIM'S MODAL EDITING                               │
└─────────────────────────────────────────────────────────────────────────────┘

                              ┌──────────────┐
                              │ NORMAL MODE  │  ← You spend 80% of time here
                              │  (Default)   │
                              │              │
                              │ • Navigate   │
                              │ • Delete     │
                              │ • Copy/Paste │
                              │ • Undo/Redo  │
                              └──────┬───────┘
                                     │
           ┌─────────────────────────┼─────────────────────────┐
           │                         │                         │
           ▼                         ▼                         ▼
    ┌──────────────┐          ┌──────────────┐          ┌──────────────┐
    │ INSERT MODE  │          │ VISUAL MODE  │          │ COMMAND MODE │
    │              │          │              │          │              │
    │ Enter: i,a,o │          │ Enter: v,V   │          │ Enter: :     │
    │ Exit: <Esc>  │          │       Ctrl+v │          │ Exit: Enter  │
    │              │          │ Exit: <Esc>  │          │       or Esc │
    │ • Type text  │          │              │          │              │
    │ • Add content│          │ • Select     │          │ • Save :w    │
    │              │          │ • Highlight  │          │ • Quit :q    │
    │              │          │ • Block ops  │          │ • Search /   │
    └──────────────┘          └──────────────┘          └──────────────┘

                    ┌─────────────────────────────────────┐
                    │         MODE TRANSITIONS            │
                    ├─────────────────────────────────────┤
                    │ Normal → Insert:  i, I, a, A, o, O  │
                    │ Normal → Visual:  v, V, Ctrl+v      │
                    │ Normal → Command: :                 │
                    │ Any    → Normal:  <Esc> or Ctrl+[   │
                    └─────────────────────────────────────┘

                    ┌─────────────────────────────────────┐
                    │       INSERT MODE VARIANTS          │
                    ├─────────────────────────────────────┤
                    │ i = insert before cursor            │
                    │ I = insert at start of line         │
                    │ a = append after cursor             │
                    │ A = append at end of line           │
                    │ o = open line below                 │
                    │ O = open line above                 │
                    └─────────────────────────────────────┘

Vim Modal Editing

  • Normal Mode: For navigation and manipulation. Keys are commands, not characters.
  • Insert Mode: For typing new text.
  • Visual Mode: For selecting blocks of text.
  • Command Mode: For global operations (save, quit, search-replace).

Insight: You only enter Insert Mode to add content. As soon as you stop typing, you hit Esc to return to Normal Mode. This keeps your hands on the home row and your brain in “command” mode.

2. The Dot Command (.)

The . key repeats the last change. This is the single most powerful feature in Vim. If you structure your edits correctly (e.g., using dw instead of repeating backspace), the . key allows you to replay complex edits with a single keystroke. It turns you into a macro machine.

┌─────────────────────────────────────────────────────────────────────────────┐
│                         THE DOT COMMAND                                     │
│                    Vim's "Do It Again" Button                               │
└─────────────────────────────────────────────────────────────────────────────┘

                         THE DOT FORMULA

    ┌─────────────────────────────────────────────────────────────────┐
    │                                                                 │
    │   ONE CHANGE  +  ONE MOTION  +  REPEAT (.)  =  PRODUCTIVITY    │
    │                                                                 │
    │         ↓              ↓              ↓                         │
    │     Make edit      Navigate      Press "."                      │
    │      once        to next spot    to replay                      │
    │                                                                 │
    └─────────────────────────────────────────────────────────────────┘

                      WHAT DOES "." REPEAT?

    ┌─────────────────────────────────────────────────────────────────┐
    │  The dot command repeats the last CHANGE, which includes:       │
    │                                                                 │
    │  • Everything from entering Insert mode to leaving it           │
    │    (i...text...<Esc> is ONE change)                            │
    │                                                                 │
    │  • Operators with motions (dw, cit, yap, etc.)                 │
    │                                                                 │
    │  • Single-key changes (x, r, ~, etc.)                          │
    └─────────────────────────────────────────────────────────────────┘

                         PRACTICAL EXAMPLE

    Task: Change "foo" to "bar" in multiple places

    ┌──────────────────────────────────────────────────────────────────┐
    │  Step 1: Search for pattern                                      │
    │  /foo<Enter>                                                     │
    │  Cursor jumps to first "foo"                                     │
    │                                                                  │
    │  Step 2: Make the change ONCE                                    │
    │  cw bar <Esc>                                                    │
    │  "change word" + type "bar" + exit insert mode                   │
    │                                                                  │
    │  Step 3: Navigate and repeat                                     │
    │  n     → jump to next "foo"                                      │
    │  .     → replay "change word to bar"                             │
    │  n     → jump to next "foo"                                      │
    │  .     → replay again                                            │
    │  (repeat n . n . n . as needed)                                  │
    └──────────────────────────────────────────────────────────────────┘

                    GOOD vs BAD REPEATABILITY

    ┌─────────────────────┬────────────────────────────────────────────┐
    │     BAD (. = ?)     │          GOOD (. = whole action)          │
    ├─────────────────────┼────────────────────────────────────────────┤
    │  x x x x x          │  dw  (delete word)                        │
    │  (. repeats "x")    │  (. repeats "delete word")                │
    ├─────────────────────┼────────────────────────────────────────────┤
    │  $a text <Esc>      │  A text <Esc>                             │
    │  (. repeats "a")    │  (. repeats "append at EOL + text")       │
    ├─────────────────────┼────────────────────────────────────────────┤
    │  F( x f) x          │  df)  (delete to and including ')')       │
    │  (. repeats "x")    │  (. repeats the entire deletion)          │
    └─────────────────────┴────────────────────────────────────────────┘

                        KEY INSIGHT

    ┌─────────────────────────────────────────────────────────────────┐
    │  Think BEFORE you edit:                                         │
    │  "How can I make this change repeatable with a single '.'?"     │
    │                                                                 │
    │  Use COMPOUND commands:                                         │
    │  • A instead of $a    (append at end of line)                   │
    │  • I instead of ^i    (insert at start of line)                 │
    │  • C instead of c$    (change to end of line)                   │
    │  • S instead of cc    (substitute entire line)                  │
    │  • O instead of ko    (open line above)                         │
    └─────────────────────────────────────────────────────────────────┘

Vim Dot Command

3. Text Objects: Editing Semantics

Instead of highlighting text with a mouse, you address the “object” you want to edit.

┌─────────────────────────────────────────────────────────────────────────────┐
│                         VIM TEXT OBJECTS                                    │
│                    "Inner" vs "Around" Explained                            │
└─────────────────────────────────────────────────────────────────────────────┘

                    THE GIFT BOX MENTAL MODEL
    ┌─────────────────────────────────────────────────────────┐
    │                                                         │
    │    ┌─────────────────────────────────────────┐         │
    │    │   ┌─────────────────────────────────┐   │         │
    │    │   │                                 │   │         │
    │    │   │         The Gift               │   │ ← AROUND │
    │    │   │       (i = inner)               │   │   (a)    │
    │    │   │                                 │   │         │
    │    │   └─────────────────────────────────┘   │         │
    │    │               The Box                   │         │
    │    └─────────────────────────────────────────┘         │
    │                                                         │
    └─────────────────────────────────────────────────────────┘

    EXAMPLE: The string "hello world"

    Original:   "hello world"
                ↑           ↑
                │           └─ closing quote (delimiter)
                └─ opening quote (delimiter)

    di" (delete inner quotes):
    Before: "hello world"     After: ""
            ^^^^^^^^^^^^             ↑↑
            deleted                  quotes remain

    da" (delete around quotes):
    Before: "hello world"     After: (nothing)
            ^^^^^^^^^^^^^
            entire thing deleted including quotes

┌─────────────────────────────────────────────────────────────────────────────┐
│                     COMMON TEXT OBJECTS                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   WORDS                          BLOCKS/DELIMITERS                          │
│   ──────                         ─────────────────                          │
│   iw = inner word                i" = inner quotes "..."                    │
│   aw = around word               a" = around quotes                         │
│   iW = inner WORD (whitespace)   i' = inner single quotes '...'             │
│   aW = around WORD               i` = inner backticks `...`                 │
│                                  i( or ib = inner parentheses (...)         │
│   SENTENCES & PARAGRAPHS         i{ or iB = inner braces {...}              │
│   ──────────────────────         i[ = inner brackets [...]                  │
│   is = inner sentence            i< = inner angle brackets <...>            │
│   as = around sentence           it = inner HTML tag <div>...</div>         │
│   ip = inner paragraph           at = around HTML tag                       │
│   ap = around paragraph                                                     │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

                    VISUAL COMPARISON
    ┌────────────────────────────────────────────────────────┐
    │  Code:  function(arg1, arg2)                           │
    │                  ^^^^^^^^^^^                           │
    │                  └─ cursor here                        │
    │                                                        │
    │  di(  →  function()         (deletes args only)        │
    │  da(  →  function           (deletes args + parens)    │
    │  ci(  →  function(█)        (change: cursor inside)    │
    └────────────────────────────────────────────────────────┘

    ┌────────────────────────────────────────────────────────┐
    │  Code:  <div class="box">content</div>                 │
    │                          ^^^^^^^                       │
    │                          └─ cursor here                │
    │                                                        │
    │  dit  →  <div class="box"></div>  (delete inner tag)   │
    │  dat  →  (nothing)                (delete entire tag)  │
    │  cit  →  <div class="box">█</div> (change inner tag)   │
    └────────────────────────────────────────────────────────┘

Vim Text Objects

  • iw: Inner Word (the word under cursor).
  • it: Inner Tag (content inside <div>...</div>).
  • i": Inner Quotes (content inside "...").
  • ap: Around Paragraph (the whole paragraph + whitespace).

4. Navigation: Search > Scroll

Beginners scroll with j and k. Masters search.

  • f{char}: Jump to the next occurrence of {char} on this line.
  • /pattern: Jump to the next occurrence of “pattern” in the file.
  • *: Jump to the next occurrence of the word under the cursor.

Concept Summary Table

Concept Cluster What You Need to Internalize
Modal Editing You are not always writing. You are mostly navigating and refactoring. Use Normal mode by default.
The Grammar Operator + Motion = Action. Think in sentences (d2w), not keystrokes.
Text Objects Don’t select manually. Tell Vim what to select (i", at, iw).
The Dot Formula One change + One motion + . = Infinite productivity.
Search Navigation Don’t move your eyes to the cursor; move the cursor to your eyes (using /, f, L).
Registers “Copy/Paste” is actually “Yank/Put” into named slots ("ay, "bp).

Deep Dive Reading By Concept

Read these chapters to build a strong mental model before or during the projects.

The Philosophy & Basics

| Concept | Book & Chapter | | :— | :— | | The Vim Way (Dot Formula) | Practical Vim by Drew Neil — Ch. 1: “The Vim Way” | | Normal Mode | Practical Vim — Ch. 2: “Normal Mode” | | Insert Mode | Practical Vim — Ch. 3: “Insert Mode” |

| Concept | Book & Chapter | | :— | :— | | File Navigation | Practical Vim — Ch. 8: “Navigate Inside Files with Motions” | | Search Navigation | Learning the vi and Vim Editors — Ch. 3: “Moving Around in a Hurry” | | Jumps & Marks | Practical Vim — Ch. 9: “Navigate Between Files with Jumps” |

Operations (Editing)

| Concept | Book & Chapter | | :— | :— | | Visual Mode | Practical Vim — Ch. 4: “Visual Mode” | | Copy & Paste (Registers) | Practical Vim — Ch. 10: “Copy and Paste” | | Macros | Practical Vim — Ch. 11: “Macros” | | Patterns & Regex | Practical Vim — Ch. 12: “Matching Patterns and Literals” |


Project 1: The “No-HJKL” Navigator

  • File: navigation_practice.txt (Create a large text file)
  • Difficulty: Level 1: Beginner
  • Knowledge Area: Horizontal/Vertical Navigation
  • Main Book: Practical Vim (Chapter 8)

Real World Outcome

You will navigate a 1000-line log file or code file without touching your mouse or the arrow keys, and without repeatedly mashing j or l. You will be able to look at a specific semicolon on the screen and teleport your cursor to it instantly.

Here’s what you’ll actually see in your terminal when you open a large file:

$ vim server_error.log

Initial screen (cursor at top):

█2025-01-15 10:23:45 ERROR: Database connection failed
2025-01-15 10:23:46 INFO: Retrying connection...
2025-01-15 10:23:47 ERROR: Timeout after 30s
...
[Line 1/1247]

Scenario: You need to jump to the word “Timeout” visible on line 3.

Without Vim motions, you’d press: j j w w w w w w (8+ keystrokes)

With Vim motions, you type: /Timeout Enter (2 keystrokes)

After /Timeout + Enter:

2025-01-15 10:23:45 ERROR: Database connection failed
2025-01-15 10:23:46 INFO: Retrying connection...
2025-01-15 10:23:47 ERROR: █imeout after 30s
...
[Line 3/1247]

Scenario: Now you want to jump to the semicolon after “30s” on the same line.

You can see it 8 characters to the right. Instead of pressing l 8 times, you type: f;

After f;:

2025-01-15 10:23:47 ERROR: Timeout after 30s█

Scenario: There are 4 more semicolons visible on screen. You want to jump to the 3rd one.

You type: 3; (repeat the last f search 3 times)

Cursor teleports across multiple lines instantly.

Using screen-relative motions - Before M: (viewing lines 100-150 of the file)

█00: function initialize() {
101:   setupDatabase();
102:   loadConfig();
...
125:   startServer();    ← Middle of visible screen
...
148:   return true;
149: }
150: // End of init

After typing M:

100: function initialize() {
101:   setupDatabase();
102:   loadConfig();
...
█25:   startServer();    ← Cursor teleported here
...
148:   return true;
149: }
150: // End of init

The power: Your eyes see a target, your brain thinks the motion, your cursor teleports. No holding down keys. No mouse reaching. Pure thought-to-action.

The Core Question You’re Answering

“How do I move my cursor at the speed of my eyes?” Most people look at a target, then hold an arrow key until the cursor arrives. This disconnect breaks flow. You want to think “Go to ‘function’” and have the cursor arrive there.

Concepts You Must Understand First

Stop and research these before coding:

  1. Line Search (f/t): How to jump to a character on the current line.
  2. Word Motion (w/b/e): The difference between a “word” and a “WORD” (whitespace delimited).
  3. Screen Motion (H/M/L): Moving relative to the visible screen (High, Middle, Low).
  4. The Search Command (/): Using search as a motion operator.

Questions to Guide Your Design

Before practicing, think through these:

  1. Precision: If I want to delete from here to the next comma, how do I do it? (df, or dt,)
  2. Efficiency: If I need to go down 50 lines, is 50j the best way? Or is 50G or /target better?
  3. Repetition: If I used f; to jump to a semicolon, how do I go to the next one without typing f; again? (Hint: ;)

Thinking Exercise

The “Gaze” Test Open a file. Look at a random word.

  • Don’t touch the keyboard.
  • Formulate the exact keystrokes to get there in your head.
  • Example target: The word “Return” inside a function 10 lines down.
  • Plan: /Return -> Enter.
  • Now execute.

The Interview Questions They’ll Ask

  1. “What is the difference between f and t?”
  2. “How do you center the current line on the screen?” (zz)
  3. “How do you move to the matching closing brace?” (%)

Hints in Layers

Hint 1: Line Jumps To delete everything from cursor to the next period: dt. (delete til period).

Hint 2: Screen Jumps Use H to go to the top of the window, M to middle, L to bottom. Combine with relative numbers.

Hint 3: Search as Motion d/foo deletes from cursor until the next occurrence of “foo”.

Books That Will Help

| Topic | Book | Chapter | | :— | :— | :— | | Motions | “Practical Vim” | Ch. 8 | | Basic Movement | “Learning the vi and Vim Editors” | Ch. 3 |


Project 2: The JSON Surgeon (Text Objects)

  • File: messy_config.json
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Text Objects / Selection
  • Main Book: Practical Vim (Visual Mode / Text Objects)

Real World Outcome

You will take a minified or messy JSON/Config file and restructure it. You will change values, delete keys, and copy entire objects without ever manually highlighting text (clicking and dragging). You will edit purely by structure.

Here’s what you’ll see when editing a JSON configuration file. You open config.json:

BEFORE:

{"database":{"host":"old-server.com","port":5432,"credentials":{"username":"admin","password":"temp123"}},"cache":{"enabled":true}}

The cursor is somewhere in the middle of this mess. You want to:

  1. Change the password value
  2. Delete the entire credentials object
  3. Change “enabled” from true to false

Task 1: Change the password - Cursor is anywhere inside "temp123". You type: ci"

After ci" (change inner quote):

{"database":{"host":"old-server.com","port":5432,"credentials":{"username":"admin","password":"█"}},"cache":{"enabled":true}}

Vim deleted temp123 and put you in insert mode inside the quotes. You type the new password secure_pass_2024 and press Esc:

{"database":{"host":"old-server.com","port":5432,"credentials":{"username":"admin","password":"secure_pass_2024█"}},"cache":{"enabled":true}}

Task 2: Delete the entire credentials object - You navigate your cursor anywhere inside the credentials block. You type: da{ (delete around braces)

After da{:

{"database":{"host":"old-server.com","port":5432,"credentials":},"cache":{"enabled":true}}

Wait, that kept the word “credentials”:. Let’s include it. Put cursor on the “c” of “credentials” and type: df} (delete forward to })

Result:

{"database":{"host":"old-server.com","port":5432},"cache":{"enabled":true}}

Task 3: Change true to false - Navigate to “true” (you can use /true then Enter). Cursor on the “t”. You type: cw (change word), then type false, then Esc:

After cwfalseEsc:

{"database":{"host":"old-server.com","port":5432},"cache":{"enabled":false}}

The magic: You never touched your mouse. You never manually selected text by dragging. You told Vim “change the thing inside these quotes” (ci"), “delete the thing around these braces” (da{), “change this word” (cw). You edited by STRUCTURE, not by position.

The Core Question You’re Answering

“How do I edit the meaning of the code, not just the characters?” Code is hierarchical. You have blocks inside blocks. You want to operate on “the inner block” or “the outer block” regardless of how many lines it spans.

Concepts You Must Understand First

  1. Text Objects (i vs a): Inner (content only) vs Around (content + surrounding delimiters).
  2. Delimiters: How Vim understands ( ), { }, [ ], " ", ' '.
  3. The Change Operator (c): Deleting text and immediately entering Insert Mode.

Questions to Guide Your Design

  1. Selection: How do I select everything inside these braces? (vi{)
  2. Replacement: How do I replace the string inside these quotes? (ci")
  3. Deletion: How do I delete this whole function block? (da{)

Thinking Exercise

The “Inside/Around” Mental Model Imagine a gift box.

  • Inner (i): The gift inside the box.
  • Around (a): The gift + the box itself.
  • If you di{ (delete inner brace), you keep the braces but empty the contents.
  • If you da{ (delete around brace), you remove the braces and the contents.

The Interview Questions They’ll Ask

  1. “What is the command to change the text inside the current paragraph?” (cip)
  2. “How do you copy a function including its braces?” (ya{)
  3. “Why use ci" instead of di" then i?” (Because . will repeat the whole change action).

Hints in Layers

Hint 1: Changing Values Cursor anywhere inside "value". Type ci" -> type new value -> Esc.

Hint 2: Deleting Blocks Cursor anywhere inside a { ... } block. Type da{ to delete the whole object.

Hint 3: Hierarchy If you are inside nested braces {{ }}. di{ works on the closest pair. 2di{ works on the next one out.

Books That Will Help

| Topic | Book | Chapter | | :— | :— | :— | | Text Objects | “Practical Vim” | Ch. 8 (Tip 52 approx) | | Visual Mode | “Practical Vim” | Ch. 4 |


Project 3: The Code Refactor (Change Operator)

  • File: legacy_script.py
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Operators / Dot Command
  • Main Book: Practical Vim (Chapter 1 & 2)

Real World Outcome

You will rename a variable that appears 20 times in a file, but not every occurrence (so a global find/replace won’t work). You will do this by making the change once, and then hopping to specific spots and pressing . to repeat it instantly.

Here’s what you’ll see when refactoring code. You open calculate.py:

BEFORE:

def process_data(data):
    temp = data.filter()
    temp = temp.transform()
    result = temp.validate()

    temp = load_cache()  # Different 'temp' - don't rename this one
    cache_result = temp.get()

    temp = result.finalize()  # Back to original 'temp' - rename this
    return temp

You want to rename the first set of temp variables to filtered_data, but NOT the one used for cache (line 5). A global find/replace would break the code.

Step 1: Position cursor on first temp (line 2) and press *

After *: Vim highlights all occurrences of temp in the file and jumps to the next one:

def process_data(data):
    temp = data.filter()
    emp = temp.transform()       Cursor here, all 'temp' highlighted
    result = temp.validate()

    temp = load_cache()
    cache_result = temp.get()

    temp = result.finalize()
    return temp

Step 2: Go back to first temp - Press N (previous match) or gg to go to top, then navigate to line 2. Put cursor on the “t” of “temp”.

Step 3: Make the change once - Type: cw filtered_data Esc

After cwfiltered_dataEsc:

def process_data(data):
    filtered_data = data.filter()
    temp = temp.transform()
    result = temp.validate()

    temp = load_cache()
    cache_result = temp.get()

    temp = result.finalize()
    return temp

Step 4: Jump to next occurrence - Press n (next match)

After n:

def process_data(data):
    filtered_data = data.filter()
    emp = temp.transform()       Cursor here
    result = temp.validate()
...

Step 5: Repeat the change - Press . (dot command)

After .:

def process_data(data):
    filtered_data = data.filter()
    filtered_data = temp.transform()
    result = temp.validate()
...

It changed “temp” to “filtered_data” instantly! The dot command replayed your entire edit: “delete word, type ‘filtered_data’, exit insert mode.”

Step 6: Continue the pattern - Press n to jump to next occurrence (line 3), press . to rename it. Press n again (line 4), press . to rename it.

Step 7: Skip the cache temp - Press n to jump to line 5 temp = load_cache(). You DON’T want to rename this one. Just press n again to skip it. Press n again to skip line 6.

Step 8: Rename the last ones - Press n to get to line 8, press . to rename. Press n to get to line 9, press . to rename.

FINAL RESULT:

def process_data(data):
    filtered_data = data.filter()
    filtered_data = filtered_data.transform()
    result = filtered_data.validate()

    temp = load_cache()  # Unchanged - correct!
    cache_result = temp.get()

    filtered_data = result.finalize()
    return filtered_data

The workflow: One change (cwfiltered_dataEsc) + Navigation (n) + Repeat (.) = Selective refactoring at superhuman speed. You made 1 manual edit and pressed . 5 times. No copy-paste, no retyping, no manual selection.

The Core Question You’re Answering

“How do I make repetitive editing tasks feel like magic?” The Dot Command is Vim’s “Do it again” button. It captures your last edit (from entering Insert mode to leaving it).

Concepts You Must Understand First

  1. The Dot Formula: One Motion + One Change.
  2. Repeatable Changes: Why dw is better than x x x.
  3. Search Navigation: Using * to find the word under the cursor.

Questions to Guide Your Design

  1. Optimization: I want to change “foo” to “bar”.
    • Bad way: l l x x x i b a r Esc. (The . will only repeat the last typed char).
    • Good way: cw bar Esc. (The . will repeat “Change word to bar”).
  2. Navigation: How do I find the next “foo”? (* or n).

Thinking Exercise

The Repeat Trace Write a sentence: “The cat sat on the cat.”

  • Cursor on first “cat”.
  • cw “dog” Esc. (Sentence: “The dog sat on the cat.”)
  • Move to next “cat” (w or *).
  • Press ..
  • Result: “The dog sat on the dog.”
  • Notice how . replayed “Delete word + Insert ‘dog’ + Escape”.

The Interview Questions They’ll Ask

  1. “What exactly does the dot command repeat?”
  2. “Why is A (append at end of line) more repeatable than $a?”
  3. “How do you search for the word under the cursor?” (*)

Hints in Layers

Hint 1: The Setup Place cursor on start of variable. cw -> type new name -> Esc.

Hint 2: The Loop Press n to go to next match. Press . to repeat change. Press n again. If you want to skip one, just press n again without pressing ..

Books That Will Help

| Topic | Book | Chapter | | :— | :— | :— | | The Dot Command | “Practical Vim” | Ch. 1 & 2 | | Pattern Search | “Practical Vim” | Ch. 12 |


Project 4: The Markdown Re-Sequencer (Line Operations)

  • File: todo_list.md
  • Difficulty: Level 1: Beginner
  • Knowledge Area: Visual Block / Line Motions
  • Main Book: Practical Vim (Chapter 4)

Real World Outcome

You will turn a messy dump of text into a structured TODO list. You will move paragraphs around, add checkboxes to 50 lines at once, and indent blocks of code—all without tedious copy-pasting or line-by-line typing.

Here’s exactly what you’ll see in your Vim editor. Start with this plain text in todo_list.md:

Buy groceries
Call dentist
Fix bug in login form
Review PR #234
Update documentation

Step 1: Add checkboxes using Visual Block mode Place cursor at the start of line 1 (on “B” of “Buy”). Press Ctrl+v to enter Visual Block mode. Press 4j to select down 4 lines. You’ll see a vertical column selection:

█Buy groceries
│Call dentist
│Fix bug in login form
│Review PR #234
│Update documentation

Now press I (Shift+i) to insert at the start of all lines. Type - [ ] (dash, space, open bracket, space, close bracket, space). Press Esc. Wait a moment and watch the magic—all lines update simultaneously:

- [ ] Buy groceries
- [ ] Call dentist
- [ ] Fix bug in login form
- [ ] Review PR #234
- [ ] Update documentation

Step 2: Move lines around Need to prioritize “Fix bug in login form”? Place cursor on that line. Press dd to cut it. Move cursor to line 1. Press P (uppercase p) to paste above. Your screen now shows:

- [ ] Fix bug in login form
- [ ] Buy groceries
- [ ] Call dentist
- [ ] Review PR #234
- [ ] Update documentation

Step 3: Indent a section Want to indent the last two items as sub-tasks? Place cursor on “Review PR #234”. Press V (uppercase v) for Visual Line mode. Press j to select both lines:

- [ ] Fix bug in login form
- [ ] Buy groceries
- [ ] Call dentist
█- [ ] Review PR #234
█- [ ] Update documentation

Press > to indent. Result:

- [ ] Fix bug in login form
- [ ] Buy groceries
- [ ] Call dentist
    - [ ] Review PR #234
    - [ ] Update documentation

You just restructured a 5-line TODO list in under 15 keystrokes, no mouse required.

The Core Question You’re Answering

“How do I manipulate rectangular blocks of text and whole lines?” Standard editors select in streams (lines wrapping). Vim can select columns (Visual Block).

Concepts You Must Understand First

  1. Line Operations: dd (delete line), yy (copy line), p (paste line).
  2. Visual Block Mode: Ctrl+v. How to select a vertical column of text.
  3. Range Operations: How to apply a command to multiple lines.

Questions to Guide Your Design

  1. Column Editing: How do I add “- [ ] “ to the start of 10 lines simultaneously?
  2. Reordering: How do I swap this paragraph with the one above it? (dd then k then p).
  3. Indentation: How do I indent these 5 lines? (V (visual line) -> 5j -> >).

Thinking Exercise

The Column Mental Model Imagine your text file is a grid (like Excel).

  • Switch to Visual Block Mode (Ctrl+v).
  • Move down. You are now selecting a column, not lines.
  • Press I (Shift+i). You are now inserting on all selected lines.
  • Type text.
  • Press Esc. Watch it propagate to all lines.

The Interview Questions They’ll Ask

  1. “How do you paste a line before the current line?” (P)
  2. “How do you insert text on multiple lines at once?” (Visual Block I)
  3. “How do you join two lines together?” (J)

Hints in Layers

Hint 1: Moving Lines dd cuts the line. Move cursor. p pastes it below. P pastes it above.

Hint 2: Visual Block Insert Ctrl+v -> Select column -> I (Shift+i) -> Type text -> Esc. Wait a second for it to apply.

Hint 3: Paragraph Jumps Use { and } to jump over blocks of text to move faster.

Books That Will Help

| Topic | Book | Chapter | | :— | :— | :— | | Visual Mode | “Practical Vim” | Ch. 4 | | Copy and Paste | “Practical Vim” | Ch. 10 |


Project 5: The Log Parser (Macros)

  • File: server_log.txt (Messy data)
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Macros / Registers
  • Main Book: Practical Vim (Chapter 11)

Real World Outcome

You will clean up a CSV file where the columns are misaligned, dates are wrong, and quotes are missing. You will record your actions on the first line, and then tell Vim to “do that 1000 times,” cleaning the entire file in milliseconds.

Here’s exactly what you’ll see. Open server_log.txt with messy CSV data:

John,Smith,john@email.com,2024-01-15
Sarah,Jones,sarah@email.com,2024-02-20
Michael,Brown,michael@email.com,2024-03-10

But wait—the data has issues. Some names need quotes, emails are inconsistent. Let’s say you need to wrap each name field in quotes and add a column number at the start.

Target transformation: Each line should become 1,"John","Smith",john@email.com,2024-01-15

Step 1: Position cursor and start recording Place cursor on line 1, column 1 (the “J” in “John”). Press qa to start recording a macro into register a. You’ll see recording @a in the status line at the bottom of Vim.

Step 2: Record the transformation on one line Now perform these keystrokes (Vim will remember them):

0                    " Go to start of line (cursor: █John,Smith...)
i1,"<Esc>            " Insert '1,"' at start (now: 1,"█John,Smith...)
f,                   " Find first comma (cursor: 1,"John█,Smith...)
i"<Esc>              " Insert quote before comma (now: 1,"John"█,Smith...)
l                    " Move right one char (cursor: 1,"John",█Smith...)
i"<Esc>              " Insert quote (now: 1,"John","█Smith...)
f,                   " Find next comma (cursor: 1,"John","Smith█,john@...)
i"<Esc>              " Insert quote (now: 1,"John","Smith"█,john@...)
j0                   " Down to next line, go to start
q                    " Stop recording

Step 3: Watch it in action Your first line now looks like: 1,"John","Smith",john@email.com,2024-01-15

The cursor is on line 2. Now press @a to replay the macro once. Line 2 transforms instantly:

1,"John","Smith",john@email.com,2024-01-15
2,"Sarah","Jones",sarah@email.com,2024-02-20
Michael,Brown,michael@email.com,2024-03-10

Step 4: Apply to remaining lines You have 100 more lines? No problem. Press 100@a and watch Vim blaze through the file. In under a second, you’ll see in your status bar something like:

102 lines processed

Your CSV file in Vim now shows 100 perfectly formatted rows, all transformed by the exact same sequence of keystrokes you recorded once.

Alternative: Apply to all remaining lines Or use Visual mode: Place cursor on line 3. Press V (Visual Line), then G to select to end of file. Type :normal @a and press Enter. Every selected line runs your macro. Done.

The Core Question You’re Answering

“How do I automate complex edits without learning a scripting language?” Macros allow you to record a sequence of keystrokes into a register (variable) and replay them.

Concepts You Must Understand First

  1. Registers: Storage slots in Vim ("a, "b, …).
  2. Recording: qa (Record to register ‘a’).
  3. Playback: @a (Play register ‘a’).
  4. Atomic Motions: Using motions that work regardless of line content (e.g., 0 instead of <<<<).

Questions to Guide Your Design

  1. Repeatability: Does your macro work if the name “John” is 4 letters and “Christopher” is 11? (Use f, instead of lllll).
  2. Reset: Does your macro end by moving to the start of the next line? (Crucial for loops).
  3. Counters: Can you use a macro to number lines? (Using Ctrl+A to increment numbers).

Thinking Exercise

The Robot Script Write down your steps for one line:

  1. Go to start of line (0).
  2. Find first comma (f,).
  3. Delete char (x).
  4. Go down one line (j). Now record exactly that.

The Interview Questions They’ll Ask

  1. “How do you edit an existing macro?” (Paste register, edit, yank back).
  2. “How do you run a macro on all selected lines?” (Visual selection -> :normal @a).
  3. “What happens if a macro fails (beep) in the middle of a loop?” (It stops).

Hints in Layers

Hint 1: Start Clean Always start recording from a known position (usually start of line 0).

Hint 2: The End Move Ensure your macro ends by positioning the cursor ready for the next run (e.g., j0).

Hint 3: Recursive Macros You can record a macro that calls itself (dangerous but powerful).

Books That Will Help

| Topic | Book | Chapter | | :— | :— | :— | | Macros | “Practical Vim” | Ch. 11 | | Registers | “Practical Vim” | Ch. 10 |


Project 6: The HTML Tag Wrapper (Surround Simulation)

  • File: index.html
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Marks / Registers / Insert-Normal
  • Main Book: Practical Vim

Real World Outcome

You will take a plain text list and wrap items in <li> tags, wrap the list in <ul>, and modify attributes. You will do this manually to understand how plugins like vim-surround work under the hood.

Here’s exactly what you’ll see in your Vim editor. Start with this plain text list in index.html:

Apples
Oranges
Bananas
Grapes

Your goal: Convert this into a proper HTML unordered list with <li> tags around each item, and a <ul> wrapper around everything.

Step 1: Wrap first item in <li> tags using marks Place cursor on “Apples”. Press ma to set mark a at the start of the word. Your screen looks like:

█Apples
Oranges
Bananas
Grapes

Now move to the end of “Apples” by pressing e (cursor is now on the “s”). Press yiw to yank (copy) the inner word into the default register. Now type I<li> (capital I to insert at line start) and you’ll see:

<li>█Apples
Oranges
Bananas
Grapes

Press Esc to exit insert mode. Now append the closing tag: Press A</li> (capital A to append at line end):

<li>Apples</li>█
Oranges
Bananas
Grapes

Press Esc. First item done!

Step 2: Use a register to save and reuse the wrapper Let’s be smarter for the remaining items. Place cursor on line 2 (“Oranges”). Press yiw to yank the word into the default register. Now press S (capital S to substitute entire line), and type:

<li><Ctrl+r>"</li>

When you press Ctrl+r then " (the double-quote key) while in insert mode, Vim pastes the contents of the default register (the word “Oranges”). Your line becomes:

<li>Apples</li>
<li>Oranges</li>█
Bananas
Grapes

Press Esc. Line 2 is done!

Step 3: Repeat for remaining items For line 3, place cursor on “Bananas”. Press yiw, then S, then type <li><Ctrl+r>"</li>, press Esc. Repeat for “Grapes”. Your editor now shows:

<li>Apples</li>
<li>Oranges</li>
<li>Bananas</li>
<li>Grapes</li>█

Step 4: Add the <ul> wrapper using marks Now wrap everything in <ul> tags. Place cursor on line 1. Press O (capital O to open line above) and type <ul>, press Esc. Your screen shows:

<ul>
<li>Apples</li>█
<li>Oranges</li>
<li>Bananas</li>
<li>Grapes</li>

Press G to jump to the last line, then press o (lowercase o to open line below) and type </ul>, press Esc. Final result:

<ul>
<li>Apples</li>
<li>Oranges</li>
<li>Bananas</li>
<li>Grapes</li>
</ul>█

Step 5: Using marks to jump around Let’s say you need to copy an attribute from line 1 and paste it on line 5. Place cursor on line 1, press ma to set mark a. Navigate to line 5 with 5G. Do your work. Now press `a (backtick + a) to jump back to the exact cursor position where mark a was set. Press 'a (single quote + a) to jump to the beginning of that line instead.

Using named registers Want to save “Apples” for later use? Place cursor on the word and press "ayiw (yank inner word into register a). Navigate anywhere in the file. Press "ap to paste from register a. The word “Apples” appears at cursor position, no matter how much you’ve copied/pasted in between.

The Core Question You’re Answering

“How do I save my place in a file and move text between locations?” You will learn to use Marks (ma) to drop an anchor, move away, and pull text back to the anchor.

Concepts You Must Understand First

  1. Marks: m{char} to set, `{char} to jump.
  2. Named Registers: "aY (Yank line into register ‘a’).
  3. Insert-Normal Mode: Ctrl+o allows one normal command while in insert mode.

Questions to Guide Your Design

  1. Anchoring: How do I remember where “here” is so I can jump back after copying something? (ma).
  2. Transplanting: How do I move a line from the bottom of the file to here? (Delete to register, move, paste).

Thinking Exercise

The Teleporter

  • Set mark a at top (ma).
  • Go to bottom (G).
  • Set mark b (mb).
  • Jump to a (`a).
  • Jump to b (`b).

The Interview Questions They’ll Ask

  1. “What is the difference between d and "ad?” (The second saves to register ‘a’).
  2. “How do you jump to the exact location of a mark vs just the line?” (`a vs 'a).
  3. “How do you paste from register ‘a’?” ("ap).

Hints in Layers

Hint 1: Wrapping Text Yank the word. Type <div>. Press Ctrl+r then " (default register) to paste while in insert mode. Type </div>.

Hint 2: Marks Use capital marks (mA) for file-global marks (jump between files).

Books That Will Help

| Topic | Book | Chapter | | :— | :— | :— | | Marks | “Learning the vi and Vim Editors” | Ch. 3 (Marking Your Place) | | Registers | “Practical Vim” | Ch. 10 |


Project 7: The “Vim Golf” Challenge

  • File: golf_challenge.txt
  • Difficulty: Level 4: Expert
  • Knowledge Area: Optimization
  • Main Book: Online Resources / VimGolf

Real World Outcome

You will look at a text transformation and solve it in the fewest keystrokes possible. This turns editing into a game and forces you to learn obscure, high-efficiency commands.

Example Challenge: Convert “hello world” to “HELLO WORLD” and add exclamation marks.

Starting state:

hello world█

Naive Solution (16 keystrokes):

v$            " Visual select to end of line (cursor: hello world█)
y             " Yank
gU            " Uppercase (now: HELLO WORLD█)
A             " Append at end
!             " Type exclamation
Esc           " Back to normal

Score: 16 keystrokes

Vim Golf Solution (4 keystrokes):

gU$           " Uppercase to end of line (now: HELLO WORLD█)
A!            " Append exclamation and enter insert mode
Esc           " Back to normal (now: HELLO WORLD!█)

Score: 4 keystrokes

You’ll practice on VimGolf.com where you submit your solution and see how you rank against others globally. The site shows you the winning solution and you’ll discover commands like ~ (toggle case), Ctrl+a (increment number), and xp (swap characters) that you never knew existed.

The Core Question You’re Answering

“Is there a faster way?” This project trains your lateral thinking. Instead of “Delete line, type new line”, you might find “Increment number” (Ctrl+a) or “Swap case” (~).

Concepts You Must Understand First

  1. Obscure Operators: ~ (case swap), gu (lowercase), gU (uppercase).
  2. Increment/Decrement: Ctrl+a, Ctrl+x.
  3. Compound Commands: xp (transpose characters), ddp (swap lines).

Questions to Guide Your Design

  1. Math: Can I turn “10px” into “12px” without typing? (2Ctrl+a).
  2. Case: Can I turn “HELLO” to “hello” without retyping? (gUaw).
  3. Swaps: “teh” -> “the”. How? (xp).

Thinking Exercise

The Keystroke Audit Record yourself editing. Count the keys. “I pressed l 5 times.” -> Score: 5. “I pressed f,.” -> Score: 2. Winner: f,.

The Interview Questions They’ll Ask

  1. “How do you swap two characters?” (xp).
  2. “How do you increment the first number on the line?” (Ctrl+a).
  3. “How do you toggle case?” (~).

Hints in Layers

Hint 1: Don’t Enter Insert Mode Vim Golf challenges are often solved without ever hitting i.

Hint 2: Visual Selection Counts Avoid visual selection if a direct operator (d3w) works. v adds a keystroke.

Books That Will Help

| Topic | Book | Chapter | | :— | :— | :— | | Efficiency | “Practical Vim” | Ch. 1 (The Vim Way) |


Project 8: The Config Builder (Vanilla Vimrc)

  • File: .vimrc
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Vim Configuration / Vimscript
  • Main Book: Modern Vim / Learning vi and Vim

Real World Outcome

You will create a configuration file that makes Vim behave exactly how you want. You will enable line numbers, relative numbering, syntax highlighting, and custom key maps. You will own your tools.

BEFORE (Stock Vim with no .vimrc): When you open a Python file, you see this bare-bones view:

def calculate_total(items):
    total = 0
    for item in items:
        total += item.price
    return total
█
  • No line numbers
  • No syntax highlighting (all text is one color)
  • Need to hit Esc key (far from home row)
  • When you search with /total, the matches stay highlighted forever

AFTER (With your custom ~/.vimrc):

" Your .vimrc configuration
set number                  " Show absolute line numbers
set relativenumber          " Show relative numbers (makes 5j easier)
syntax on                   " Enable syntax highlighting
set hlsearch                " Highlight search results
set incsearch              " Show matches as you type
set ignorecase             " Case insensitive search
set smartcase              " Case sensitive if uppercase present
inoremap jj <Esc>          " Map jj to Escape in insert mode
nnoremap <leader>h :nohl<CR>  " Clear search highlighting with Space+h
let mapleader = " "        " Set spacebar as leader key

Now when you open the same file you see:

  4│def calculate_total(items):
  3│    total = 0
  2│    for item in items:
  1│        total += item.price
  1│    return total
  2│█
  • Line numbers appear (absolute on left: 345, 346, 347…)
  • Relative numbers show distance (1, 2, 3 above and below cursor)
  • Python keywords like def, for, return are colored differently
  • When in insert mode, you can type jj to escape (no reaching for Esc)
  • After searching, you press Space+h to clear highlighting

You’ll test your config by opening code files and verifying each setting works as expected.

The Core Question You’re Answering

“How do I make the editor work for me, instead of me working for the editor?”

Concepts You Must Understand First

  1. Set Options: set number, set hlsearch.
  2. Mappings: map, nmap (normal mode map), imap (insert mode map).
  3. The Leader Key: Creating your own namespace for commands.

Questions to Guide Your Design

  1. Relative Numbers: Why do many Vimmers use set relativenumber? (It makes 10j easier to calculate).
  2. Escaping: Esc is far away. Can you map jj to Esc?
  3. Search: How do I stop the highlighting after a search? (:nohl).

Thinking Exercise

The Pain Audit What annoys you? “I hate reaching for Ctrl+w to switch windows.” Fix it: nnoremap <C-h> <C-w>h.

The Interview Questions They’ll Ask

  1. “What is the difference between map and noremap?” (Recursive vs Non-recursive. Always use noremap unless you know why not).
  2. “What is the Leader key?”
  3. “How do you reload .vimrc without restarting?” (:source %).

Hints in Layers

Hint 1: The Leader let mapleader = " " (Space bar). Now you can map Space + w to save file.

Hint 2: Comments In .vimrc, comments start with ".

Books That Will Help

| Topic | Book | Chapter | | :— | :— | :— | | Configuration | “Modern Vim” | Tips 26-28 | | Settings | “Learning the vi and Vim Editors” | Appendix B |


Project 9: The Code Navigator (CTags & Jumps)

  • File: Large Source Code Repository (e.g., Redis source)
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Jump List / Tags
  • Main Book: Practical Vim (Chapter 16)

Real World Outcome

You will explore a massive unfamiliar codebase. You will jump from a function call to its definition in another file, and jump back, without a file explorer.

The Experience: You’ve cloned the Redis source code (thousands of files). You open src/server.c and see:

/* src/server.c - line 5234 */
int main(int argc, char **argv) {
    initServerConfig();
    loadServerConfig(config_file);
    initServer();
    

You wonder “What does initServerConfig() actually do?” Place your cursor on the function name and press Ctrl+]:

JUMP! Vim instantly opens src/config.c at line 892:

/* src/config.c - line 892 */
void initServerConfig(void) {
    server.port = CONFIG_DEFAULT_SERVER_PORT;
    server.tcp_backlog = CONFIG_DEFAULT_TCP_BACKLOG;
    

You explore a bit, then see it calls createSharedObjects(). Cursor on that name, press Ctrl+] again:

JUMP! Now you’re in src/object.c at line 445:

/* src/object.c - line 445 */
void createSharedObjects(void) {
    shared.crlf = createObject(OBJ_STRING, sdsnew("\r\n"));
    

You’ve gone 3 levels deep (main -> initServerConfig -> createSharedObjects). To get back, you press Ctrl+o (jump back):

JUMP BACK! You’re back in src/config.c at line 892.

Press Ctrl+o again:

JUMP BACK! You’re back in src/server.c at line 5234 in main().

Your jump list looks like this (visible with :jumps):

  jump line  col file/text
    3  5234    4 src/server.c
    2   892   10 src/config.c
    1   445    8 src/object.c
>

You’ve navigated a complex codebase without opening a single file browser or typing a file path. The tags file (generated by ctags -R .) maps every function, variable, and struct definition, letting you traverse code like a graph.

The Core Question You’re Answering

“How do I build a mental map of code structure?”

Concepts You Must Understand First

  1. The Jump List: Vim remembers where you’ve been. Ctrl+o (back), Ctrl+i (forward).
  2. Tags: Using ctags to index code.
  3. Definition Jumps: Ctrl+] (jump to tag/definition).

Questions to Guide Your Design

  1. Traversal: I’m inside main(). It calls init(). How do I see init()?
  2. Return: I’m done with init(). How do I go back to main()? (Ctrl+t or Ctrl+o).
  3. Local vs Global: gd goes to local declaration.

Thinking Exercise

The Breadcrumb Trail Navigate 5 levels deep into function calls. Now try to get back to the start pressing only one key combination repeatedly. (Ctrl+o).

The Interview Questions They’ll Ask

  1. “How do you jump to the definition of the word under cursor?”
  2. “What is the difference between Ctrl+o and u?” (Jump list vs Undo list).
  3. “How do you generate a tags file?” (ctags -R .).

Hints in Layers

Hint 1: Ctags You need to install ctags on your system for Ctrl+] to work efficiently in C/C++ projects.

Hint 2: The Change List g; goes to the last place you made a change.

Books That Will Help

| Topic | Book | Chapter | | :— | :— | :— | | Ctags | “Practical Vim” | Ch. 16 | | Jumps | “Practical Vim” | Ch. 9 |


Project 10: The Search-Replace Master (Substitutions)

  • File: database_dump.sql
  • Difficulty: Level 4: Expert
  • Knowledge Area: Ex Commands / Regex
  • Main Book: Practical Vim (Chapter 14)

Real World Outcome

You will take a text file of names “Last, First” and convert them to SQL INSERT INTO users (name) VALUES ('First Last'); using a single complex command.

BEFORE - You have a file names.txt with this content:

Doe, John
Smith, Jane
Johnson, Bob
Williams, Alice

You need to convert this to SQL INSERT statements with the names in “First Last” format.

The Command: You type this one Ex command in Vim:

:%s/\v(\w+), (\w+)/INSERT INTO users (name) VALUES ('\2 \1');/g

Breaking it down:

  • % = apply to all lines in the file
  • s = substitute command
  • /\v = “very magic” mode (less escaping needed)
  • (\w+) = capture group 1: one or more word characters (the last name)
  • , = match the literal comma and space
  • (\w+) = capture group 2: one or more word characters (the first name)
  • / = separator between find and replace
  • INSERT INTO users (name) VALUES (' = literal text
  • \2 \1 = reference to captured groups (first name, then last name)
  • '); = literal text to close the SQL statement
  • /g = global flag (all occurrences on each line)

You press Enter.

AFTER - The file instantly transforms:

INSERT INTO users (name) VALUES ('John Doe');
INSERT INTO users (name) VALUES ('Jane Smith');
INSERT INTO users (name) VALUES ('Bob Johnson');
INSERT INTO users (name) VALUES ('Alice Williams');

All four lines transformed in milliseconds. You see the confirmation at the bottom of Vim:

4 substitutions on 4 lines

Advanced variation: If you only wanted to transform lines containing “Smith”, you’d use:

:g/Smith/s/\v(\w+), (\w+)/INSERT INTO users (name) VALUES ('\2 \1');/

This combines the :g (global) command with :s (substitute) - only lines matching “Smith” get transformed.

The Core Question You’re Answering

“How do I perform programmatic text processing?” Vim’s command line (:) exposes the power of sed and Regex.

Concepts You Must Understand First

  1. The Substitute Command: :%s/find/replace/g.
  2. Capture Groups: \( ... \) and \1, \2.
  3. Ranges: :1,10s/... (Lines 1-10 only).

Questions to Guide Your Design

  1. Pattern Matching: How do I match “Word, Word”? (\w\+, \w\+).
  2. Swapping: How do I swap them? (\2 \1).
  3. Context: How do I execute this only on lines containing “User”? (:g/User/s/...).

Thinking Exercise

Regex Construction Don’t write the whole command at once.

  1. Search first: /pattern. Check matches.
  2. Start substitute: :%s// (uses last search).

The Interview Questions They’ll Ask

  1. “What does % mean in :%s?” (The whole file range).
  2. “How do you make search case-insensitive?” (\c).
  3. “How do you reuse the matched pattern in the replacement?” (&).

Hints in Layers

Hint 1: Very Magic Use \v at the start of regex to avoid escaping parentheses. /\v(group) instead of /\(group\).

Hint 2: Confirmation Add c at the end (:%s/.../.../gc) to confirm each replacement.

Books That Will Help

| Topic | Book | Chapter | | :— | :— | :— | | Substitution | “Practical Vim” | Ch. 14 | | Global Commands | “Practical Vim” | Ch. 15 |


Project Comparison Table

Project Difficulty Time Depth of Understanding Fun Factor
1. No-HJKL Navigator Beginner Weekend ⭐⭐⭐ ⭐⭐
2. JSON Surgeon Intermediate Weekend ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
3. Code Refactor Intermediate Weekend ⭐⭐⭐⭐ ⭐⭐⭐
4. Markdown Sequencer Beginner Weekend ⭐⭐ ⭐⭐⭐
5. Log Parser Advanced 1 Week ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
6. HTML Wrapper Advanced Weekend ⭐⭐⭐ ⭐⭐
7. Vim Golf Expert Ongoing ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
8. Config Builder Intermediate Weekend ⭐⭐⭐ ⭐⭐⭐
9. Code Navigator Advanced 1 Week ⭐⭐⭐⭐ ⭐⭐⭐
10. Search-Replace Expert Weekend ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐