← Back to articles

Code Editing Workflows

Path: Computer Tech/Development/Editors/Neovim/LazyVim Workflows/Code Editing Workflows.mdUpdated: 2/3/2026

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.

OperatorActionMnemonic
dDelete (cut)delete
cChange (delete + insert mode)change
yYank (copy)yank
>Indent rightshift >
<Indent leftshift <
=Auto-indent= format
gUUppercasego Uppercase
guLowercasego uppercase
~Toggle case~

Motions (How Far)

Motions define where the operator acts.

Word Motions

MotionMoves to...
wStart of next word
eEnd of word
bBack to start of word
WNext WORD (ignores punctuation)
EEnd of WORD
BBack 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

MotionMoves to...
0Start of line
^First non-blank character
$End of line
g_Last non-blank character
ggFirst line of file
GLast line of file
{number}GGo to line number

Search Motions

MotionAction
f{char}Find next char on line
F{char}Find previous char on line
t{char}To (before) next char
T{char}To (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

MotionMoves 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 = inner (excludes surrounding delimiters)
  • a = around (includes surrounding delimiters)

Common Text Objects

ObjectMeaningExample
iwInner worddiw = delete word under cursor
awAround worddaw = delete word + space
isInner sentencecis = change sentence
asAround sentencedas = delete sentence
ipInner paragraphyip = yank paragraph
apAround paragraphdap = delete paragraph
i( or i)Inside parensdi( = delete inside ()
a( or a)Around parensda( = delete () and contents
i{ or i}Inside bracesdi{ = delete inside {}
a{ or a}Around bracesda{ = delete {} and contents
i[ or i]Inside bracketsci[ = change inside []
a[ or a]Around bracketsya[ = yank [] and contents
i"Inside quotesci" = change inside ""
a"Around quotesda" = delete "" and contents
i'Inside single quotesdi' = delete inside ''
a'Around single quotesca' = change '' and contents
itInside tag (HTML)dit = delete inside
atAround tagdat = delete 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

KeyModeDescription
vCharacter-wise visualSelect characters
VLine-wise visualSelect full lines
Ctrl+vBlock visualSelect 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

ActionCommandExample
Change wordciwChange inner word
Delete worddawDelete around word
Change inside quotesci"Change text in ""
Delete inside parensdi(Delete inside ()
Yank lineyyCopy line
Pastep / PAfter/before cursor
Repeat.Repeat last change
UndouUndo
RedoCtrl+rRedo
Indent>>Indent line
Record macroqaRecord to register a
Replay macro@aReplay 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: