Using the commentary.vim plugin to learn about Vim’s operators, motions and text objects.
commentary.vim provides several ways to comment or uncomment lines. First install the plugin (see my post about installing Vim plugins):
$ git clone https://tpope.io/vim/commentary.git ~/.vim/pack/plugins/start/vim-commentary
$ vim -u NONE -c "helptags commentary/doc" -c q
…and now:
-
Press gcc in normal mode to comment or uncomment the current line.
You can precede gcc with a count, for example 3gcc comments or uncomments three lines (the current line and the two below it).
-
Select some lines then press gc in visual mode to comment or uncomment the selected line(s):
-
gc{motion} in normal mode comments or uncomments all lines that the given
{motion}
moves over.This works with any of Vim’s built-in motions or text objects and ones provided by plugins. See
:help motion.txt
for all the built-in motions and text objects you can use. Here’s some examples:-
j moves to the line below and k moves to the line above, so:
- gcj comments or uncomments the current line and the line below it.
- gck comments or uncomments the current line and the one above it.
-
Motions can take counts: 3j moves down three lines and 3k moves up three lines, so:
- gc3j comments or uncomments the current line and three lines below it.
- gc3k comments or uncomments the current line and the three above it.
- You can also put the count at the start of the command: 3gcj or 3gck.
-
gg moves to the top of the file and G moves to the bottom of the file, so:
- gcgg comments or uncomments the current line and every line above it to the top of the file.
- gcG comments or uncomments the current line and every line below it.
-
ap is a text object for the current paragraph, so:
- gcap comments or uncomments the current paragraph.
- Text objects work with counts too: either 3gcap or gc3ap comments or uncomments three paragraphs (the current paragraph and the two below it).
-
vim-indent-object is a plugin that adds ii as a text object for the current indented block and ai for the current indented block including the first line above the indentation, so:
- gcii comments or uncomments the current indented block.
- gcai comments or uncomments the current indented block and the first line above it.
-
vim-textobj-entire adds ae as a text object for the entire file so gcae comments or uncomments the entire file.
-
Commentary.vim itself also adds gc as a text object for the current comment so gcgc uncomments all lines of the current comment.
Like any text object gc can be used as the object of any command that expects one. For example dgc deletes the current comment, ygc copies (yanks) the current comment, >gc or <gc indents or dedents the current comment, etc.
-
-
Type
:[range]Commentary
in command line mode to comment or uncomment a range of lines.For example
:'<,'>Commentary
will comment or uncomment the currently selected lines (the same as pressing gc in visual mode), or:3,5Commentary
will comment or uncomment lines 3-5 (see:help cmdline-ranges
). -
Finally,
Commentary
can be used with Vim’s:global
command (see:help :global
) to comment or uncomment all lines that match a pattern, for example:g/TODO/Commentary
comments or uncomments all lines containingTODO
.
Vim’s dot command with gc
Because commentary.vim commands either comment a line (if it’s not already commented) or uncomment a line (if it’s already commented) you can use . (the dot command) to toggle a previous comment or uncomment action. For example after using gcap to comment out a paragraph . will now uncomment the same paragraph. If you move the cursor to a different paragraph then . will comment or uncomment that paragraph.
Vim operators, motions and text objects
To understand a command like gcgc (uncomment a comment) you first have to understand Vim’s concepts of operators, motions and text objects.
Many of Vim’s normal mode keyboard commands have this form:
{operator} {motion}
For example dw deletes from the cursor to the start of the next word. d is the delete operator and w is a motion that jumps to the start of the next word:
Motions are keyboard commands that move the cursor around. For example:
h and l to move one character to the left and right,
0 or Home to jump to the start of the line,
^ to jump to the first non-blank character on the line,
$ or End to jump to the end of the line,
g_ to jump to the last non-blank character on the line,
{number}G to jump to line {number}
(for example 42G to jump to line 42),
j and k to move down to the next line or up to the previous line,
w to jump to the start of the next word,
e to jump to the end of the next word,
b to jump to the start of the previous word,
ge to jump to the end of the previous word.
) and ( jump to the next and previous sentence,
whereas } and { jump to the next and previous paragraph.
There are many more motions, see :help motion.txt
for them all.
Operators are commands that operate on text. For example: d to delete, y to “yank” (copy), gu to change to lowercase, gU to change to uppercase, ~ to toggle case, > to indent and < to dedent.
To operate on some text you type an operator followed by a motion:
{operator} {motion}
For example gU$ will uppercase everything from the cursor position to the end of the line. gU is the uppercase operator and $ is a motion to the end of the line:
When you type an operator Vim goes into “operator pending mode”: it displays the operator that was typed in the bottom-right and waits for you to tell it what text to operate on by typing a motion:
Text objects are commands that you can use in visual mode to select defined ranges of text surrounding the cursor. For example aw stands for “around word”, typing aw in visual mode expands the selection in both directions at once to encompass the entire word under the cursor including any trailing whitespace:
iw (“inner word”) selects the word without trailing whitespace, as and is select sentences, ap and ip select paragraphs.
There are several text objects for selecting text within pairs of surrounding characters.
i[, a[,
i(, a(,
i<, a<,
i{, a{,
i', a',
i", a",
i` and a`
select text within or around pairs of [...]
‘s, (...)
‘s, <...>
‘s, {...}
‘s, '...'
‘s, "..."
‘s or `...`
‘s:
The i versions select only the text inside the brackets whereas the a versions select the brackets themselves as well):
You can type either the opening or the closing bracket, for example i] is the same as i[, a) is the same as a(, etc.
There’s also it and at which select text within or around pairs of HTML opening and closing tags like <div>...</div>
:
After selecting text objects in visual mode you can type an operator command to operate on the selected text.
For example with your cursor on some text inside some [...]
‘s
press v to enter visual mode,
i[ to select the text inside the [...]
‘s
then d to delete the text:
Visual mode is a great way to practice text objects: you can see what you’re selecting and you can type as many motions as you need to get exactly the selection you want before typing an operator. You can even adjust the selection by just moving the cursor around with the plain old arrow keys or h, j, k and l. You can swap the cursor to the other end of the selection with o so you can adjust it from both ends:
Once you get used to some text objects there’s a faster way to use them. Text objects can be used directly in place of the motions in operator commands:
{operator} {text object}
di[ will delete everything inside a pair of [...]
‘s without having to go into visual mode first:
Or >ap will indent the current paragraph directly:
And that’s what gcgc is: it’s an {operator} {text object}
command:
commentary.vim provides both a gc operator for commenting or uncommenting
and a gc text object for the current comment.
In the command gcgc the first gc is the “toggle comment” operator
and the second gc is the “current comment” text object.
So gcgc uncomments the entire current comment:
Footnote: you can’t use gc to select a comment
You can’t use gc as a motion in normal mode or visual mode. For example you can’t type gc in visual mode to select a comment. Instead, gc in visual mode comments or uncomments the selected lines. Since the same key sequence gc is used as an operator and a text object it can’t be both at once in normal mode or visual mode, it has to be one or the other. So gc is a text object in operator-pending mode only. In normal mode and visual mode it’s an operator.