# Code Editing Workflows Vim's editing model is fundamentally different from other editors. Instead of selecting with a mouse and typing, you **compose operations** using a grammar of operators, motions, and text objects. ## The Vim Grammar Every Vim editing command follows this pattern: ``` [count] [operator] [count] [motion/text-object] ``` **Examples:** - `d3w` = delete 3 words - `c
= change to end of line - `2dd` = delete 2 lines - `di(` = delete inside parentheses - `>5j` = indent next 5 lines ## Operators (Verbs) Operators perform actions on text. | Operator | Action | Mnemonic | |----------|--------|----------| | `d` | Delete (cut) | **d**elete | | `c` | Change (delete + insert mode) | **c**hange | | `y` | Yank (copy) | **y**ank | | `>` | Indent right | shift **>** | | `<` | Indent left | shift **<** | | `=` | Auto-indent | **=** format | | `gU` | Uppercase | **g**o **U**ppercase | | `gu` | Lowercase | **g**o **u**ppercase | | `~` | Toggle case | **~** | ## Motions (How Far) Motions define where the operator acts. ### Word Motions | Motion | Moves to... | |--------|-------------| | `w` | Start of next **w**ord | | `e` | **E**nd of word | | `b` | **B**ack to start of word | | `W` | Next WORD (ignores punctuation) | | `E` | End of WORD | | `B` | Back to start of WORD | **Example:** ```javascript const userName = "John"; ↑ ↑ ↑ w moves here e moves here w moves here // w = treats userName as one word // W = treats everything as one WORD until space ``` ### Line Motions | Motion | Moves to... | |--------|-------------| | `0` | Start of line | | `^` | First non-blank character | | `
| End of line | | `g_` | Last non-blank character | | `gg` | First line of file | | `G` | Last line of file | | `{number}G` | Go to line number | ### Search Motions | Motion | Action | |--------|--------| | `f{char}` | **F**ind next char on line | | `F{char}` | **F**ind previous char on line | | `t{char}` | **T**o (before) next char | | `T{char}` | **T**o (before) previous char | | `;` | Repeat f/F/t/T forward | | `,` | Repeat f/F/t/T backward | **Example:** ```javascript const result = calculateTotal(price, tax); ↑ ↑ fa finds 'a' t) goes before ')' ``` ### Paragraph/Block Motions | Motion | Moves to... | |--------|-------------| | `}` | Next paragraph/block | | `{` | Previous paragraph/block | | `%` | Matching bracket/paren | ## Text Objects (What to Act On) **Text objects** define boundaries intelligently. ### Inner vs Around - `i` = **i**nner (excludes surrounding delimiters) - `a` = **a**round (includes surrounding delimiters) ### Common Text Objects | Object | Meaning | Example | |--------|---------|---------| | `iw` | Inner word | `diw` = delete word under cursor | | `aw` | Around word | `daw` = delete word + space | | `is` | Inner sentence | `cis` = change sentence | | `as` | Around sentence | `das` = delete sentence | | `ip` | Inner paragraph | `yip` = yank paragraph | | `ap` | Around paragraph | `dap` = delete paragraph | | `i(` or `i)` | Inside parens | `di(` = delete inside () | | `a(` or `a)` | Around parens | `da(` = delete () and contents | | `i{` or `i}` | Inside braces | `di{` = delete inside {} | | `a{` or `a}` | Around braces | `da{` = delete {} and contents | | `i[` or `i]` | Inside brackets | `ci[` = change inside [] | | `a[` or `a]` | Around brackets | `ya[` = yank [] and contents | | `i"` | Inside quotes | `ci"` = change inside "" | | `a"` | Around quotes | `da"` = delete "" and contents | | `i'` | Inside single quotes | `di'` = delete inside '' | | `a'` | Around single quotes | `ca'` = change '' and contents | | `it` | Inside tag (HTML) | `dit` = delete inside <tag> | | `at` | Around tag | `dat` = delete <tag> and contents | ## Practical Examples ### Changing Text Inside Delimiters ```javascript // Cursor anywhere inside the quotes const message = "Hello World"; ci" → Change inside quotes → Result: const message = "|"; (in insert mode) // Cursor anywhere in the function call calculate(price, tax) ci( → Change inside parens → Result: calculate(|) (in insert mode) ``` ### Deleting Function Arguments ```javascript function greet(name, age, location) { // ... } // Cursor on "name" di( → delete inside () → Result: function greet() { // Or delete including the parens da( → Result: function greet { ``` ### Changing HTML Tag Contents ```html <div class="container">Old content here</div> <!-- Cursor anywhere in the tag --> cit → Change inside tag → Result: <div class="container">|</div> (insert mode) <!-- Delete tag and contents --> dat → Result: (empty line) ``` ### Yanking (Copying) and Pasting ```javascript const userName = "John"; // Yank word yiw → Yanks "John" // Move cursor somewhere else p → Paste after cursor P → Paste before cursor // Yank entire line yy → Yank line Y → Also yanks line // Yank 3 lines y3j → Yank current + 3 down ``` ### Duplicating Lines ```javascript const name = "John"; // Duplicate line yy → Yank line p → Paste below → Result: const name = "John"; const name = "John"; ``` ### Indenting Code Blocks ```javascript function hello() { const x = 1; const y = 2; return x + y; } // Cursor inside function >i{ → Indent inside {} → Indents all lines inside braces // Or indent 3 lines 3>> → Indent current + next 2 lines ``` ### Commenting Out Code (with nvim-surround) LazyVim includes nvim-surround for quick wrapping. ```javascript const value = 42; // Add single-line comment ys$c → Surround to end of line with comment → Result: // const value = 42; // Surround word with quotes ysiw" → Surround inner word with " → Result: const "value" = 42; // Change surrounding quotes cs"' → Change surrounding " to ' → Result: const 'value' = 42; // Delete surrounding quotes ds" → Delete surrounding " → Result: const value = 42; ``` ## The Dot Command (Repeat) **The `.` command repeats your last change.** This is one of Vim's most powerful features. ### Example 1: Change Multiple Words ```javascript const oldName = "test"; const oldName2 = "test"; const oldName3 = "test"; // On first line: ciwnewName<Esc> → Change "oldName" to "newName" // Move to second line: j^ → Down, to start . → Repeat (changes oldName2 to newName) // Move to third line: j^ . → Repeat again ``` ### Example 2: Delete Function Calls ```javascript console.log("debug 1"); console.log("debug 2"); console.log("debug 3"); // On first line: dd → Delete line // On second line: . → Repeat (delete line) // On third line: . → Repeat (delete line) ``` ### Example 3: Indent Multiple Blocks ```javascript function a() { code; } function b() { code; } // On first function: >i{ → Indent inside braces // Navigate to second function: } → Jump to next block . → Repeat indent ``` ## Visual Mode (Selection) Sometimes you need to see what you're operating on. ### Visual Modes | Key | Mode | Description | |-----|------|-------------| | `v` | Character-wise visual | Select characters | | `V` | Line-wise visual | Select full lines | | `Ctrl+v` | Block visual | Select rectangular blocks | ### Visual Mode Workflow ```javascript const userName = "John"; // Select "userName" and change it: v → Enter visual mode iw → Select inner word c → Change (deletes and enters insert) newName<Esc> → Type new name // Or more simply: ciw → Same thing without visual mode! ``` **Visual mode is useful when:** - You're learning and want to see the selection - You need to verify what you're about to delete - Working with complex, irregular selections **But usually it's faster to skip visual mode:** - `ciw` instead of `viw` + `c` - `dap` instead of `Vap` + `d` ## Multiple Cursors (Visual Block) **Visual block mode** (`Ctrl+v`) lets you edit multiple lines at once. ### Example: Add semicolons to multiple lines ```javascript const a = 1 const b = 2 const c = 3 // On first line, end of line: $ → Go to end Ctrl+v → Visual block mode jj → Select down 2 lines $ → Extend to end of each line A → Append (insert at end) ; → Type semicolon <Esc> → Apply to all lines → Result: const a = 1; const b = 2; const c = 3; ``` ### Example: Comment multiple lines ```javascript const x = 1; const y = 2; const z = 3; // At start of first line: Ctrl+v → Visual block jj → Select 3 lines I → Insert at start // <Esc> → Add comment, apply to all → Result: // const x = 1; // const y = 2; // const z = 3; ``` ## Search and Replace ### Within File ```vim :%s/old/new/g " Replace all in file :%s/old/new/gc " Replace with confirmation :s/old/new/g " Replace in current line :'<,'>s/old/new/g " Replace in visual selection ``` ### Across Multiple Files (with Telescope) ```vim " 1. Find all occurrences Space + s + g → Type "oldFunction" " 2. Send to quickfix Ctrl+q " 3. Replace in all files :cdo s/oldFunction/newFunction/g " 4. Save all :wa ``` ## Macros (Record and Replay) **Macros** record a sequence of commands and replay them. ### Record a Macro ```vim qa " Start recording to register 'a' <commands> " Do your edits q " Stop recording ``` ### Replay Macro ```vim @a " Replay macro 'a' @@ " Replay last macro 10@a " Replay 10 times ``` ### Example: Format JSON Lines ```json name: "John" age: 30 city: "NYC" " Want to add quotes around keys: " Record macro: qa " Start recording ^ " Go to start i"<Esc> " Add opening quote f: " Find colon i"<Esc> " Add closing quote j " Move to next line q " Stop recording " Replay: @a " Runs on second line @a " Runs on third line → Result: "name": "John" "age": 30 "city": "NYC" ``` ## Essential Workflow Patterns ### Pattern 1: Change Inside Thing **Problem:** Change text inside delimiters **Solution:** `ci` + delimiter ```javascript const msg = "old text"; ci" → Change inside quotes function(arg1, arg2) ci( → Change inside parens <div>content</div> cit → Change inside tag ``` ### Pattern 2: Delete Around Thing **Problem:** Delete function call entirely **Solution:** `da` + delimiter ```javascript console.log("debug"); da( → Delete including parentheses → Result: console.log ``` ### Pattern 3: Yank and Duplicate **Problem:** Duplicate a block **Solution:** `yap` + `p` ```javascript function test() { return 42; } yap → Yank around paragraph (entire function) p → Paste below ``` ### Pattern 4: Indent Block **Problem:** Indent nested code **Solution:** `>i{` or `>ap` ```javascript function test() { code; more code; } >i{ → Indent inside braces ``` ### Pattern 5: Quick Word Change **Problem:** Change one word **Solution:** `ciw` ```javascript const oldName = 42; ↑ cursor here ciwnewName<Esc> → Result: const newName = 42; ``` ## Common Mistakes and Fixes **❌ Using backspace to delete words** → Use `db` (delete back word) or `daw` (delete around word) **❌ Selecting with visual mode for simple changes** → Use text objects: `ciw` instead of `viwc` **❌ Not using the dot command** → After any change, repeat with `.` on similar items **❌ Repeating the same manual edit** → Record a macro with `qa`, do the edit, `q`, then `@a` to repeat **❌ Not learning text objects** → `ci"`, `di(`, `ca{` are the most powerful Vim features ## Keybinding Cheat Sheet | Action | Command | Example | |--------|---------|---------| | Change word | `ciw` | Change inner word | | Delete word | `daw` | Delete around word | | Change inside quotes | `ci"` | Change text in "" | | Delete inside parens | `di(` | Delete inside () | | Yank line | `yy` | Copy line | | Paste | `p` / `P` | After/before cursor | | Repeat | `.` | Repeat last change | | Undo | `u` | Undo | | Redo | `Ctrl+r` | Redo | | Indent | `>>` | Indent line | | Record macro | `qa` | Record to register a | | Replay macro | `@a` | Replay macro a | ## Practice Exercise Try these edits on this code: ```javascript function calculateTotal(price, tax) { const subtotal = price; const total = subtotal + tax; console.log("Debug: total is " + total); return total; } ``` **Tasks:** 1. Change `price` to `amount` (use `ciw`) 2. Delete the `console.log` line (use `dd`) 3. Change the string inside the console.log before deleting (use `ci"`) 4. Indent the entire function body (use `>i{`) 5. Duplicate the function (use `yap` then `p`) 6. Change function name (use `ciw` on function name) **Solutions:** 1. Cursor on "price", `ciw`, type "amount", `<Esc>` 2. Cursor on console.log line, `dd` 3. Cursor in string, `ci"`, type new text, `<Esc>` 4. Cursor in function, `>i{` 5. Cursor in function, `yap`, `p` 6. Cursor on "calculateTotal", `ciw`, type new name, `<Esc>` **Related:** - [[Neovim - The Vim Ecosystem]] - Understanding modal editing - [[File Navigation in LazyVim]] - Finding files before editing - [[LSP and Code Intelligence]] - Automated refactoring - [[Git Integration in LazyVim]] - Committing your changes