# 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