DaleSchool

Text Objects

Beginner20min

Learning Objectives

  • Use text objects like iw and aw
  • Make structural edits with combos like ci", di(, ya{
  • Explain the difference between inner and around

Working Code

Imagine this JavaScript code is open in Vim:

const greeting = "Hello, World!";
function add(a, b) {
  return a + b;
}

With the cursor anywhere on Hello, try these commands:

ci"     → delete the content inside the quotes and enter Insert mode
         result: const greeting = "|";  (| is the cursor)

di(     → delete only the content inside the parentheses
         result: function add() {

daw     → delete the word under the cursor + surrounding whitespace

Text objects work like tweezers. No matter where the cursor sits, Vim recognizes the structure and grabs exactly the right range.

Try It Yourself

Edit this HTML code:

<div class="container">
  <p>Old content.</p>
  <span style="color: red">Warning message</span>
</div>
  1. Place the cursor anywhere on Old content. and press cit. Only the text inside the tag changes.
  2. Place the cursor inside "container" and press ci". You can change just the class name.
  3. On style="color: red", press da" to delete the value and the quotes together.

"Why?"

inner vs. around

Text objects come in two flavors: i (inner) and a (around).

  • i (inner): content only — like tweezers extracting only the inside
  • a (around): content + surrounding delimiters — grabs the whole thing
"Hello, World!"

di"  →  ""              (deletes content inside quotes)
da"  →                   (deletes content including quotes)

diw  →  keeps surrounding whitespace   (word only)
daw  →  removes surrounding whitespace  (word + whitespace)

Key text objects

Text objectinner (i)around (a)Description
WordiwawWhitespace-separated word
Double quotesi"a"Content inside "..."
Single quotesi'a'Content inside '...'
Parenthesesi( or iba( or abContent inside (...)
Bracesi{ or iBa{ or aBContent inside {...}
Bracketsi[a[Content inside [...]
HTML tagitatContent inside <tag>...</tag>
ParagraphipapParagraph separated by blank lines
SentenceisasSentence ending in .

Real-world before/after

ci" — change string content:

Before: const name = "Alice";
           cursor here ──^
type ci"World then Esc
After:  const name = "World";

di( — delete function arguments:

Before: calculateTotal(price, tax, discount)
                    cursor here ──^
di(
After:  calculateTotal()

dap — delete a paragraph entirely:

Before:
This is the first paragraph.
It spans multiple lines.

This is the second paragraph.

With the cursor on the first paragraph, press dap →

After:
This is the second paragraph.

Cursor position doesn't matter

The great thing about text objects is that they work no matter where the cursor is within the range. Press ci" and you change the entire content of the quotes regardless of cursor position. Unlike motions, you don't have to line up the starting point.

Deep Dive

Combining with operators

Text objects combine freely with the operators from the previous lesson:

diw     → delete word
ciw     → change word (enter Insert mode)
yiw     → yank word
di"     → delete inside quotes
ci(     → change inside parentheses
ya{     → yank including braces

Formula: operator + i/a + object

Refactoring practice

Open the code below in Vim and edit it using text objects:

const config = {
  apiUrl: "https://old-api.example.com",
  timeout: 3000,
  headers: { "Content-Type": "text/plain" },
};

function fetchData(url, options, callback) {
  console.log("Fetching data...");
}

Goals:

  1. Change the API URL to "https://new-api.example.com" (use ci")
  2. Change Content-Type to "application/json" (use ci")
  3. Delete every argument of fetchData (use di()
  4. Change the string inside console.log (use ci")

question: "What's the difference between ci\" and ca\"?" options:

question: "Given getData(id, name, email) with the cursor on name, what's the result of di(?" options:

question: "Which command changes only the text inside the HTML tag <p>Hello</p>?" options: