Edit code with textobjects
A textobject selects a meaningful piece of text: a word, quoted string, argument, or function. Once it is selected, the same editing commands work on any of them. This article starts with words and quotes, then uses functions, arguments, and the surrounding code structure to navigate and make changes.
Start with Basics if you have not made your first edit yet.
Use the default keys below, and open a fresh scratch buffer with :new for the
first exercise. Type or paste the starting text, then press Esc.
Change a word or the text inside quotes
Start with:
status = "draft"
- Move anywhere inside
statusand pressmiwto select the whole word. - Check that only
statusis selected. Pressc, typestate, thenEsc. - Move inside
draftand pressmi"to select the text inside the quotes. - Press
c, typeready, thenEsc.
The result is:
state = "ready"
You do not need to move to the start of a word or count its letters.
mi selects the inside of a textobject; ma includes its
surroundings. For example, ma" selects the quotes as well as their contents.
Use mi" when the quotes should stay in place.
Try it: change ready to in review, keeping the quotes. Then use u to
undo that edit and U to redo it.
Move between functions
Save this example as greetings.rs and open it in Mitos. The .rs extension
selects Rust syntax support. In an unnamed scratch buffer, use :lang rust
instead.
#![allow(unused)]
fn main() {
fn greet(name: &str) -> String {
format!("Hello, {name}")
}
fn farewell(name: &str) -> String {
format!("Goodbye, {name}")
}
}
- Put the cursor inside the
greetfunction. - Press
]fto move to the next function,farewell. - Press
[fto return togreet. - Press
mafto select the whole function. Check thatfarewellis outside the selection.
Use these motions when you want the next function rather than a particular line
number. [a and ]a move between parameters; [t and ]t move between types.
See the textobject reference for other kinds of object.
Code objects need a syntax grammar and textobject queries for the language; they do not need a language server. Check Language support if these commands do not select anything. Words and quoted pairs also work in plain text.
Limit a change to one function
In the example above, both functions have a parameter named name. Change it
to guest only in greet:
- Put the cursor inside
greetand pressmafto select the whole function, including its signature. - Press
s, type\bname\b, thenEnter. Only the two occurrences in the selected function should be highlighted. - Press
Alt-r, typeguest, thenEnter.
The result is:
#![allow(unused)]
fn main() {
fn greet(guest: &str) -> String {
format!("Hello, {guest}")
}
fn farewell(name: &str) -> String {
format!("Goodbye, {name}")
}
}
maf selects the whole function; mif selects its body. The exact boundaries
depend on the language: in Rust, the body selection includes its braces. For
an edit that includes a parameter in the signature, use maf. For copying a
body, start with mif, inspect the selection, then press y.
The search is still a text match. It will also match name in a comment or
string inside the selection. Use Space r with a language server that supports
renaming when you want to change a code symbol and its references.
After working with several matches, press , to keep one selection and ; to
collapse it to its cursor before navigating elsewhere.
Select an argument as one piece
A word is not always the right unit. Open a fresh scratch buffer with :new,
set its language with :lang rust, and enter this statement. Press Esc when
you finish typing:
#![allow(unused)]
fn main() {
let label = greet(user.name());
}
Put the cursor on name and press mia. The argument user.name() should be
selected, including the method call but excluding greet and its outer
parentheses. Press c, type guest.name(), then Esc:
#![allow(unused)]
fn main() {
let label = greet(guest.name());
}
This works the same way as changing a word: select a useful unit, inspect it, then act. Next, use syntax-aware motions to move between related pieces or select the expression around them.
Move between siblings
Siblings are pieces of syntax within the same enclosing structure. For example, the arguments in a call share an argument list. Sibling motions follow that structure, including punctuation such as commas and brackets.
Open a fresh Rust scratch buffer with :new, then :lang rust, for each of the
remaining exercises. Enter the starting example and press Esc:
#![allow(unused)]
fn main() {
let total = add(first, second, third);
}
- Put the cursor on
firstand pressmiw. - Press
Alt-nonce. In this Rust example, the comma is selected. - Press
Alt-nagain to selectsecond. - Press
Alt-ptwice to return through the comma tofirst. - Press
Alt-ntwice to selectsecondagain. Pressc, typeupdated, thenEsc.
The result is:
#![allow(unused)]
fn main() {
let total = add(first, updated, third);
}
Alt-n and Alt-p work on expressions and statements as well as arguments.
If there is no sibling in that direction, they can move out to an enclosing
structure to find one. Inspect the highlight after each move; the selection
can leave the argument list. Use ]a and [a when you specifically want to
navigate by argument or parameter textobjects.
Expand to a parent and shrink back
A parent contains the selected piece. In the original add(first, second, third) example, second belongs to an argument list, and that list belongs to
the call. Starting from the unedited example in a fresh Rust buffer:
- Put the cursor on
secondand pressmiw. - Press
Alt-oto select(first, second, third), including the parentheses. - Press
Alt-oagain to selectadd(first, second, third). - Press
Alt-ito return to the argument list, thenAlt-iagain to return tosecond.
You can now change just second with c, copy it with y, or expand again
before acting on a larger expression.
This is useful when you know the code you want by its shape rather than its length. For example, expand to the whole call before copying it, so the selection includes the arguments and closing parenthesis.
Alt-i retraces expansions while their selection history is available. Moving
elsewhere, changing the selections another way, or editing clears that expansion
history. Without it, shrinking selects a child of the current structure;
it may not return to the piece you started from.
Edit siblings or children together
Use Alt-a when you want separate selections for related pieces instead of
moving through them one at a time. Start with:
#![allow(unused)]
fn main() {
let values = [first, second, third];
}
- Put the cursor on
firstand pressmiw. - Press
Alt-a. Check that the three values are selected separately, leaving the commas and brackets outside the selections. - Press
ms"to add double quotes around each selection.
The result is:
#![allow(unused)]
fn main() {
let values = ["first", "second", "third"];
}
You can reach the same selections from their parent. Press u to undo the
quotes, then , to keep one selection. With its cursor inside the array:
- Press
ma[to select the array including its brackets. - Press
Alt-Ito select its children separately. This is uppercaseI: hold Alt and Shift while pressingi. - Check the three selected values, then press
ms"to get the same result.
Alt-a selects siblings, including the starting piece; Alt-I selects the
children of the selected structure. In this array, both methods select the
values without punctuation. The pieces available depend on the language grammar.
See Surround for other ways to wrap selected text.
Press , to keep one selection when you finish. Before making an edit, you can
use Alt-u to undo an unwanted selection change.
Choose a useful unit
| What you want | Start with |
|---|---|
| A particular kind of object, such as a word or argument | miw, mia, or another textobject |
| The next or previous function or parameter | ]f / [f or ]a / [a |
| The next or previous piece of syntax, including punctuation | Alt-n or Alt-p |
| A larger enclosing expression | Alt-o; use Alt-i to retrace recent expansions |
| Separate selections for sibling structures | Alt-a |
| Separate selections for the contents of a structure | Select the parent, then Alt-I |
Try selecting a value in a nested array or call, expanding to its parent, and then selecting that parent’s children. Inspect each selection before editing: the same keys can work at several levels of the code.
Previous: Editing effectively · Next: Repeat and combine edits