這一章我們將來探索Vim映射系統中另外一個神奇的部分:“Operator-Pending映射”。開始之前,我們先解釋下這里面的幾個詞含義。
一個Operator(操作)就是一個命令,你可以在這個命令的后面輸入一個Movement(移動)命令,然后Vim開始對文本執行前面的操作命令,這個操作命令會從你當前所在的位置開始執行,一直到這個移動命令會把你帶到的位置結束。
常用到的Operator有`d`,`y`和`c`。例如:
~~~
按鍵 操作 移動
---- -------- -------------
dw 刪除 到下一個單詞
ci( 修改 在括號內
yt, 復制 到逗號
~~~
## Movement映射
Vim允許你創建任何新的movements,這些movements可以跟所有命令一起工作。執行下面的命令:
~~~
:onoremap p i(
~~~
在緩沖區中輸入下面的文字:
~~~
return person.get_pets(type="cat", fluffy_only=True)
~~~
把光標放到單詞“cat”上,然后敲擊`dp`。結果會發生什么?Vim會刪除括號內的所有文字。你可以把這個新建的movements當作“參數”。
`onoremap`命令會告訴Vim當它在等待一個要附加在operator后面的movement的時候,如果這個movement是`p`的話,它會把它當作`i(`。所以當我們在運行`dp`的時候,就象是在對Vim說“delete parameters”,而Vim會把它理解為“在括號內刪除”。
我們現在可以立馬對所有的operators使用這個新建的映射。再次在緩沖區中輸入上面的文字(或者直接把之前修改恢復一下)。
~~~
return person.get_pets(type="cat", fluffy_only=True)
~~~
把光標放到單詞“cat”上,然后敲擊`cp`。這次又會發生什么?Vim會刪除括號中的所有文字,不過這一次刪除之后Vim會處于插入模式,這是因為你使用的是“change”,而不是“delete”。
再看一個示例。執行下面的命令:
~~~
:onoremap b /return<cr>
~~~
現在把下面的文字輸入到緩沖區:
~~~
def count(i):
i += 1
print i
return foo
~~~
把光標放到第二行的`i`上,然后按下`db`。會發生生么?Vim把整個函數體中直到`return`上面的內容都刪除了,`return`就是上面的映射使用Vim的通用查找得到的結果。
當你想搞清楚怎么定義一個新的operator-pending movement的時候,你可以從下面幾個步驟來思考:
1. 在光標所在的位置開始。
2. 進入可視模式(charwise)。
3. ... 把映射的按鍵放到這里 ...
4. 所有你想包含在movement中的文字都會被選中。
你所要做的工作就是在第三步中填上合適的按鍵。
## 改變開始位置
你可能已經從上面所學的東西中意識到一個了問題。如果我們定義的movements都是從光標所在的位置開始的話,那么這就會限制我們做一些我們想使用movement來做的事情。
但是Vim并不會限制你去做你想做的事情,所以對于這個問題肯定有解決辦法。執行下面的命令:
~~~
:onoremap in( :<c-u>normal! f(vi(<cr>
~~~
這個命令看起來有些復雜,不過我們還是先試試它能干什么。將下面的文字輸入緩沖區:
~~~
print foo(bar)
~~~
把光標放到單詞`print`上面,然后敲擊`cin(`。Vim會刪除括號內的內容然后進入插入模式,并且光標會停留在括號的中間。
你可以將這個映射理解為“在下一個括號內(inside next parentheses)”。它會對當前行光標所在位置的下一個括號內的文本執行operator。
我們再創建一個“在上一個括號內(inside last parentheses)”的movement進行對照。(在這里使用“前一個(previous)“可能更準確,但這會覆蓋“段落(paragraph)”movement)
~~~
:onoremap il( :<c-u>normal! F)vi(<cr>
~~~
先試試確保這個命令可以工作。
那么這些映射是怎么工作的呢?首先,`<c-u>`比較特殊,可以先不用管(你只需要相信我這個東西可以讓這個映射在任何情況下都能正常工作)。如果我們刪除它的話,這個映射會變成這個樣子:
~~~
:normal! F)vi(<cr>
~~~
`:normal!`會在后面的章節談到,現在你只需要知道它可以在常用模式下模擬按下按鍵。例如,運行`:normal! dddd`會刪除兩行,就像按下`dddd`。映射后面的`<cr>`是用來執行`:normal!`命令的。
那么現在我們可以認為這個映射的關鍵是運行下面這些按鍵組成的命令:
~~~
F)vi(
~~~
This is fairly simple: 這個命令很容易理解:
* `F)`: 向后移動到最近的`)`字符。
* `vi(`: 進入可視模式選擇括號內的所有內容。
這個movement結束在在可視模式下選擇中我們想操作的文本,然后Vim會對選中的文本執行操作,就像通常情況一樣。
## 一般規則
下面兩條規則可以讓你可以很直觀的以多種方式創建operator-pending映射:
* 如果你的operator-pending映射以在可視模式下選中文本結束,Vim會操作這些文本。
* 否則,Vim會操作從光標的原始位置到一個新位置之間的文本。
## 練習
為"around next parentheses"和"around last parentheses"創建operator-pending映射
為打括號創建類似的in/around next/last的mappings。
閱讀`:help omap-info`,看看你可不可以搞清楚`<c-u>`是干啥的。
- 前言
- 鳴謝
- 預備知識
- 打印信息
- 設置選項
- 基本映射
- 模式映射
- 精確映射
- Leaders
- 編輯你的Vimrc文件
- Abbreviations
- 更多的Mappings
- 鍛煉你的手指
- 本地緩沖區的選項設置和映射
- 自動命令
- 本地緩沖區縮寫
- 自動命令組
- Operator-Pending映射
- 更多Operator-Pending映射
- 狀態條
- 負責任的編碼
- 變量
- 變量作用域
- 條件語句
- 比較
- 函數
- 函數參數
- 數字
- 字符串
- 字符串函數
- Execute命令
- Normal命令
- 執行normal!
- 基本的正則表達式
- 實例研究:Grep 運算符(Operator),第一部分
- 實例研究:Grep運算符(Operator),第二部分
- 實例研究:Grep運算符(Operator),第三部分
- 列表
- 循環
- 字典
- 切換
- 函數式編程
- 路徑
- 創建一個完整的插件
- 舊社會下的插件配置方式
- 新希望:用Pathogen配置插件
- 檢測文件類型
- 基本語法高亮
- 高級語法高亮
- 更高級的語法高亮
- 基本折疊
- 高級折疊
- 段移動原理
- Potion段移動
- 外部命令
- 自動加載
- 文檔
- 發布
- 還剩下什么?