Combine and Conquer
Much of Vim’s power stems from the way that operators and motions can be combined. In this tip, we’ll look at how this works and consider the implications.
Operator + Motion = Action
The d{motion}
command can operate on a single character (dl
), a complete word (daw
), or an entire paragraph (dap
). Its reach is defined by the motion. The same goes for c{motion}
, y{motion}
, and a handful of others. Collectively, these commands are called operators. You can find the complete list by looking up :h operator , while Table 2, Vim's Operator Commands, on page 25, summarizes some of the more common ones.
Trigger | Effect |
---|---|
c |
Change |
d |
Delete |
y |
Yank into register |
g~ |
Swap case |
gu |
Make lowercase |
gU |
Make uppercase |
> |
Shift right |
< |
Shift left |
= |
Autoindent |
! |
Filter {motion} lines through an external program |
Table 2—Vim’s Operator Commands |
The g~
, gu
, and gU
commands are invoked by two keystrokes. In each case, we can consider the g
to be a prefix that modifies the behavior of the subsequent keystroke. See Meet Operator-Pending Mode, on page 27, for further discussion.
The combination of operators with motions forms a kind of grammar. The first rule is simple: an action is composed from an operator followed by a motion. Learning new motions and operators is like learning the vocabulary of Vim. If we follow the simple grammar rules, we can express more ideas as our vocabulary grows.
Suppose that we already know how to delete a word using daw
, and then we learn about the gU
command (see :h gU ). It’s an operator too, so we can invoke gUaw
to convert the current word to SHOUTY case. If we then expand our vocabulary to include the ap
motion, which acts upon a paragraph, then we find two new operations at our disposal: dap
to delete, or gUap
to make the whole paragraph shout.
Vim’s grammar has just one more rule: when an operator command is invoked in duplicate, it acts upon the current line. So dd
deletes the current line, while >>
indents it. The gU command is a special case. We can make it act upon the current line by running either gUgU
or the shorthand gUU
.
Extending Vim’s Combinatorial Powers
The number of actions that we can perform using Vim’s default set of operators and motions is vast. But we can expand these even further by rolling our own custom motions and operators. Let’s consider the implications.
Custom Operators Work with Existing Motions
The standard set of operators that ships with Vim is relatively small, but it is possible to define new ones. Tim Pope’s commentary.vim plugin provides a good example.2 This adds a command for commenting and uncommenting lines of code in all languages supported by Vim.
The commentary command is triggered by gc{motion}
, which toggles commenting for the specified lines. It’s an operator command, so we can combine it with all of the usual motions. gcap
will toggle commenting for the current paragraph. gcG
comments from the current line to the end of the file. gcc
comments the current line.
If you’re curious about how to create your own custom operators, start by reading :h :map-operator .
Custom Motions Work with Existing Operators
Vim’s standard set of motions is fairly comprehensive, but we can augment it further by defining new motions and text objects.
Kana Natsuno’s textobj-entire plugin is a good example.3 It adds two new text objects to Vim: ie
and ae
, which act upon the entire file.
If we wanted to autoindent the entire file using the =
command, we could run gg=G
(that is, gg
to jump to the top of the file and then =G
to autoindent everything from the cursor position to the end of the file). But if we had the textobj-entire plugin installed, we could simply run =ae
. It wouldn’t matter where our cursor was when we ran this command; it would always act upon the entire file.
Note that if we had both the commentary and textobj-entire plugins installed, we could use them together. Running gcae
would toggle commenting throughout the current file.
If you’re curious about how to create your own custom motions, start by reading :h omap-info .
結合與征服
Vim的強大功能在很大程度上源自於操作符和動作指令可以被組合使用的方式。在這個技巧中,我們將探討它是如何工作的,並考慮其含義。
操作符 + 動作 = 行動
d{motion}
命令可以操作一個單獨的字符(dl
)、一個完整的單詞(daw
)或一個整個段落(dap
)。其作用範圍由動作指令定義。c{motion}
、y{motion}
以及其他一些命令同樣如此。這些命令統稱爲操作符。你可以通過查找:h operator
找到完整列表,而第25頁的表2,Vim的操作命令,總結了一些更常見的操作符。
g~
、gu
和gU
命令通過兩次按鍵調用。在每種情況下,我們可以認爲g
是一個修改後續按鍵行爲的前綴。更多討論見第27頁的遇見操作符-等待模式。
操作符與動作的組合形成了一種語法。第一條規則很簡單:一個行動由一個操作符後跟一個動作組成。學習新的動作和操作符就像學習Vim的詞彙一樣。如果我們遵循簡單的語法規則,隨着詞彙量的增長,我們可以表達更多的想法。
假設我們已經知道如何使用daw
刪除一個單詞,然後我們學習了gU
命令(見:h gU
)。它也是一個操作符,所以我們可以調用gUaw
將當前單詞轉換爲大寫。如果我們然後擴展我們的詞彙表包括ap
動作,它作用於一個段落,那麼我們發現有兩個新的操作可用:dap
刪除,或gUap
使整個段落大寫。
Vim的語法只有另一條規則:當一個操作命令被重複調用時,它作用於當前行。所以dd
刪除當前行,而>>
縮進它。gU
命令是一個特例。我們可以通過運行gUgU
或簡寫gUU
使其作用於當前行。
擴展Vim的組合能力
我們可以使用Vim默認的操作符和動作集合執行的動作數量是巨大的。但通過創建我們自己的自定義動作和操作符,我們可以進一步擴展這些功能。讓我們考慮一下其含義。
自定義操作符與現有動作兼容
隨Vim一起提供的標準操作符集相對較小,但定義新的操作符是可能的。Tim Pope的commentary.vim插件提供了一個很好的例子。這個插件爲Vim支持的所有語言中的代碼行添加了註釋和取消註釋的命令。
評論命令通過gc{motion}
觸發,它爲指定的行切換註釋。這是一個操作命令,所以我們可以將它與所有常用的動作結合。gcap
將切換當前段落的註釋。gcG
從當前行評論到文件的末尾。gcc
評論當前行。
如果你好奇如何創建你自己的自定義操作符,請開始閱讀:h :map-operator
。
自定義動作與現有操作符兼容
Vim的標準動作集相當全面,但我們可以通過定義新的動作和文本對象進一步增強它。
Kana Natsuno的textobj-entire插件是一個很好的例子。它爲Vim添加了兩個新的文本對象:ie
和ae
,它們作用於整個文件。
如果我們想使用=
命令自動縮進整個文件,我們可以運行gg=G
(即,gg
跳到文件頂部然後=G
從光標位置到文件末尾自動縮進一切)。但如果我們安裝了textobj-entire插件,我們可以簡單地運行=ae
。當我們運行這個命令時,光標的位置無關緊要;它總是作用於整個文件。
注意,如果我們同時安裝了commentary和textobj-entire插件,我們可以將它們一起使用。運行gcae
將切換整個當前文件的註釋。
如果你好奇如何創建你自己的自定義動作,請開始閱讀:h omap-info
。