Photo by Norbert Braun on Unsplash
Vim Targets: Work on Distant Text Objects with Fewer Keystrokes
Targeting text objects from a distance with convenient keys
Background
If you search about Vim Targets, there are only a handful of resources. However, this plugin could drastically improve your workflow by typing more efficient and more convenient keys. Admittedly, the first time I read the plugin’s docs, I was not really convinced since there are too many details, and I couldn’t imagine having the need for it. Plus, I thought it’s too heavy for my taste. In hindsight, I was wrong.
After some time, bumped into Jaime Gonzalez Garcia’s excellent Vim articles, and his discussion on Vim Targets. Made me realize to take a second look on the Targets plugin.
The b and q Text Objects
When coding, lots of time usually are spent with navigation and editing contents of:
- parentheses: function calls/arguments, tuples, generators, etc
- curly braces: dictionaries, associative arrays, JSON, etc
- square brackets: list, indices, etc
- quotes: labels, messages, texts, etc
Since I’ve been using Targets for some time now, I could say that it has 2 main valuable features for a common editing workflow:
b
: operate on any block — parentheses (()), curly braces({}), square brackets ([]).q
: operate on any quote — single quotes (‘’), double quotes (“”), and backticks (``)
Practical Applications
Block Objects
Given these examples, and assuming that the cursor is at x
which is the first char:
what are the usual options when changing their contents?
f1
thenct]
: find the first char inside of [] which is1
, then change the contents ‘till it reaches]
f1
thenct)
: find the first char inside of () which is1
, then change the contents ‘till it reaches)
f1
thenct}
: find the first char inside of {} which is1
, then change the contents ‘till it reaches}
So, we’ll need 5 chars just to change their contents and they’re not ergonomic to type since they involve numbers and punctuation.
However, if you’re using the Targets plugin, or the Vim 8.2.3255 (July 31 2021) build, you could have these auto-seeking mechanisms:
ci]
: change the contents of the nearest[]
ci(
: change the contents of the nearest()
ci{
/ciB:
change the contents of nearest{}
It’s using 3 chars, hence an improvement over the 5 chars above. There’s still a better way though when using the plugin, via the unified cib
(change inner block)— applicable to all the cases above, and really convenient to type! Moreover, the plugin will auto-seek the nearest applicable text object in the current line or adjacent lines. It’s bi-directional too.
Quote Objects
In case you’re not aware, native Vim/Neovim has auto-seeking behavior for quote objects (i.e. no need to move the cursor inside of quotes to operate on them). So, you could teleport your cursor/focus into it. Given the scenario below:
Assuming the cursor is at x
and we want to change the contents inside of the quotes, we could do these:
ci'
: change the contents of single quotes on the right side of cursor.ci"
: change the contents of double quotes on the right side of cursor.ci`
: change the contents of backticks on the right side of cursor.
There’s a much better way of using ciq
though because it’s:
- bidirectional, doesn’t care if the cursor is at the left/right side of the quoted object
- more ergonomic to type since you don’t need to type punctuation
- less cognitive overhead since
q
covers all the types of quotes
Mappings
b and q are unified text objects, it works because the plugin defines these mappings for various types of brackets/quotes:
We could extend the idea further by defining other mappings or extending the current ones. For example, I created this mapping so that the <>
angle brackets will be included in the b text object (see highlighted part):
I frequently update my Vim/Neovim mappings which usually involves the <>
block/text object, so now I just type cib
also to update them, instead of typing ci<
or ci>
which is less convenient. This is handy also when you’re dealing with lots of HTML tags.
Operating on Adjacent b or q
A common scenario as well is operating on JSON or dictionaries. Suppose we have this object:
Once you’re in one of the b/q text objects like on “alpha”, you could quickly jump on the adjacent occurrences, even if they’re in the other lines:
cinq
: change the inner next q text object which is the “value”cilq
: change the inner last q text object which is the “key” (last simply means previous)
This is also applicable if you want to deal with adjacent parentheses, curly braces, square brackets, or angle brackets (i.e. with cinb
or cilb
).
Operating on Any b or q
Sometimes you’ll need to deal with multiple b or q in the same line. For example, in HTML, it’s common to have this scenario:
Suppose we want to change the “menu” class to “menu-item”, we could do it using a numbered inq
:
c2inq
: change the 2nd inner next quote text object. The three q objects here being1inq
or simplyinq
(“home”),2inq
(“menu”), and3inq
(“#”).
However, if you’re like me and prefer to type letters instead of numbers, you could use the single-char motion in combination with Targets to change “menu” class as above:
s”a
: search for occurrences of ” to go to “menu”, then typea
(assuminga
is the jump label for “menu”)ciq
: change the inner quote text object since you’re already at the “menu”
Essentially, I will prefer typing s”aciq
than c2inq.
It has one more character but easier and faster to type.
Note that the operations in the sample above are just using the change (c
) operation (e.g. cib
or ciq
) mainly for brevity, and of course, we could easily extend it to other operations, like yib
/yiq
, dib
/diq
, and so on.
Performance
Targets may appear to be bloat since it’s capable of lots of things. Surprisingly, it’s lightweight. Here’s the result when I try checking its StartupTime:
Key Takeaways
- Using Targets could increase your efficiency by minimizing the cognitive overload and typing ergonomic keys.
- Targets have many features (including targeting specific function argument or sequence item), but the b and q text objects are my favorite ones since they could be used in various scenarios. And despite the plugin having lots of power, it’s still lightweight.
- Targets could operate on adjacent b and q text objects, and could use numbers to operate on multiple occurrences of it. For multiple occurrences, you might want to consider the single-char motion.
- You could create your own targets or extend existing ones.
- Targets’ should emphasize more the b and q objects in their docs since they are probably their biggest selling points.
Thank you for reading. If you found some value, kindly follow me, or give a reaction/comment on the article, or buy me a coffee. This will mean a lot to me and encourage me to create more content.