Text Objects
Text Objects are a way to manipulate a piece of text in a structured way. They allow you to refer to blocks of text based on their purpose and perform powerful actions. For instance:
- Selecting inside of a function.
- Select the next argument.
- Select the next changed text tracked by git.
- Select the previous type.
Notice that in each item in the above list we select something? This builds upon the idea that we talked about in the selection-first approach section.
Text objects allow us to use this mechanism to be even more productive.
Using Text Objects
For example, with the following Python file:
1 class Thing: 2 def __init__(self): 3 self.thing = "Hi" 4 5 def say_thing(self): 6 print(self.thing) NOR file.py [+] 1 sel 1:1
Basic Example
-
Move your cursor in the
__init__
method, and press maf for match around function to select the entire method:1 class Thing: 2 def __init__(self): 3 self.thing = "Hi" 4 5 def say_thing(self): 6 print(self.thing) NOR file.py [+] 1 sel 3:21
-
Use mif for match inside function to select the body of the method:
1 class Thing: 2 def __init__(self): 3 self.thing = "Hi" 4 5 def say_thing(self): 6 print(self.thing) NOR file.py [+] 1 sel 3:21
-
Additionally, you can move between most text objects.
For instance, use ]f with go to the previous function.
1 class Thing: 2 def __init__(self): 3 self.thing = "Hi" 4 5 def say_thing(self): 6 print(self.thing) NOR file.py [+] 1 sel 6:21
Syntax
- mi +
<textobject>
to match inside a textobject. Highlight a smaller region of the text object, for example the body of a function. - ma +
<textobject>
to match around a textobject. Selects the entire text object, which usually includes surrounding whitespace. - ] +
<textobject>
to go to the next instance of the textobject. - [ +
<textobject>
to go to the previous instance of the textobject.
List of Text Objects
p
,w
andW
: primitive text objects(
,)
,{
,}
,[
,]
,<
,>
,'
,"
and`
: pair text objectsg
: git hunkf
,t
,a
,c
,T
,g
: tree-sitter text objects
Primitive
word
A word consists only of alphanumeric characters and underscores, so a-Z
, 0-9
and _
.
For instance, take the following file, with two cursors:
1 println!("Hey, world!"); ~ NOR file.rs [+] 2 sels 1:4
-
Match inside word with miw:
1 println!("Hey, world!"); ~ NOR file.rs [+] 2 sels 1:7
-
Matching around word with maw:
1 println!("Hey, world!"); ~ NOR file.rs [+] 2 sels 1:7
Note that we now also have the space before the world
as our selection!
WORD
A WORD is always delimited by whitespace such as newlines, tabs and spaces.
Consider this file again:
1 println!("Hey, world!"); ~ NOR file.rs [+] 2 sels 1:4
-
Match inside WORD with miW:
1 println!("Hey, world!"); ~ NOR file.rs [+] 2 sels 1:14
-
Matching around WORD with maW:
1 println!("Hey, world!"); ~ NOR file.rs [+] 1 sel 1:24
Note that the first selection was println!("Hey,
and the second selection is world!");
, since these selections share a common character (the space), they essentially merge.
Paragraph
A paragraph is delimited by two newlines, as well as start and end of files. For example in the following file with 3 cursors:
1 ```md 2 One two three four. 3 4 Five six seven eight. 5 6 Nine ten eleven. 7 ``` NOR file.md [+] 3 sels 2:12
-
Match inside paragarph with mip:
1 ```md 2 One two three four. 3 4 Five six seven eight. 5 6 Nine ten eleven. 7 ``` NOR file.md [+] 3 sels 2:20
-
Match around paragraph with map:
1 ```md 2 One two three four. 3 4 Five six seven eight. 5 6 Nine ten eleven. 7 ``` NOR file.md [+] 3 sels 3:1
Pair Text Objects
These allow you to select:
- Inside of the surrounding pair, excluding the surrounding characters
- Inside of the surrounding pair, including the surrounding characters
For example, with the following state:
1 const say = (s: string) 2 => console.log(s); NOR file.ts [+] 1 sel 1:19
-
Pressing mi( will select:
1 const say = (s: string) 2 => console.log(s); NOR file.ts [+] 1 sel 1:22
-
While ma( will select:
1 const say = (s: string) 2 => console.log(s); NOR file.ts [+] 1 sel 1:23
Full list of available pairs:
(
and)
[
and]
{
and}
<
and>
'
and'
"
and"
`
and`
Git Hunk
If you are in a repository, then you will also have the g
for git hunk textobject.
It will select the entire change.
For instance, if we have the following file, with the added lines visible by the green bar indicator on the gutter:
1 const sayHi = 2 (name: string) 3 => `Hi, ${name}!`; 4 ▍ 5 ▍console.log( 6 ▍ sayHi("World") 7 ▍); NOR file.ts [+] 1 sel 5:9
Using mig will select the git hunk:
1 const sayHi = 2 (name: string) 3 => `Hi, ${name}!`; 4 ▍ 5 ▍console.log( 6 ▍ sayHi("World") 7 ▍); NOR file.ts [+] 1 sel 7:3
Tree-sitter Text Objects
Available for most languages, specifically ones with text objects support. See the full list of all languages with configured text object queries.
To find out for your language from the terminal, run hx --health <language>
. If queries for a specific language like python are available, running hx --health python
will show:
Textobject queries: ✓
List of available text objects:
f
for functiont
for typea
for argumentc
for commentT
for Test
Syntax-aware Motions
Some commands allow you to move the selection according to its location in the syntax tree. For example, many languages have the following syntax for function calls:
1 fn(arg1, arg2, arg3); ~ NOR file.ts [+] 1 sel 1:5
-
If you use Alt + n, it will select the next sibling:
1 fn(arg1, arg2, arg3); ~ NOR file.ts [+] 1 sel 1:13
-
Similarly, Alt + p selects the previous sibling:
1 fn(arg1, arg2, arg3); ~ NOR file.ts [+] 1 sel 1:4
-
Alt + o will expand selection to the parent node:
1 fn(arg1, arg2, arg3); ~ NOR file.ts [+] 1 sel 1:19
Next step
Now that you have text objects in your toolkit, you’ve mostly learned the most useful text manipulation features of Helix.
Check out surrounds which provides another set of powerful commands.