Vimscript Operator-Pending映射

2018-02-24 16:02 更新

這一章我們將來探索Vim映射系統(tǒng)中另外一個神奇的部分:“Operator-Pending映射”。開始之前,我們先解釋下這里面的幾個詞含義。

一個Operator(操作)就是一個命令,你可以在這個命令的后面輸入一個Movement(移動)命令,然后Vim開始對文本執(zhí)行前面的操作命令,這個操作命令會從你當(dāng)前所在的位置開始執(zhí)行,一直到這個移動命令會把你帶到的位置結(jié)束。

常用到的Operator有dyc。例如:

按鍵   操作       移動
----   --------   -------------
dw     刪除       到下一個單詞
ci(    修改       在括號內(nèi)
yt,    復(fù)制       到逗號

Movement映射

Vim允許你創(chuàng)建任何新的movements,這些movements可以跟所有命令一起工作。執(zhí)行下面的命令:

:onoremap p i(

在緩沖區(qū)中輸入下面的文字:

return person.get_pets(type="cat", fluffy_only=True)

把光標(biāo)放到單詞“cat”上,然后敲擊dp。結(jié)果會發(fā)生什么?Vim會刪除括號內(nèi)的所有文字。你可以把這個新建的movements當(dāng)作“參數(shù)”。

onoremap命令會告訴Vim當(dāng)它在等待一個要附加在operator后面的movement的時候,如果這個movement是p的話,它會把它當(dāng)作i(。所以當(dāng)我們在運行dp的時候,就象是在對Vim說“delete parameters”,而Vim會把它理解為“在括號內(nèi)刪除”。

我們現(xiàn)在可以立馬對所有的operators使用這個新建的映射。再次在緩沖區(qū)中輸入上面的文字(或者直接把之前修改恢復(fù)一下)。

return person.get_pets(type="cat", fluffy_only=True)

把光標(biāo)放到單詞“cat”上,然后敲擊cp。這次又會發(fā)生什么?Vim會刪除括號中的所有文字,不過這一次刪除之后Vim會處于插入模式,這是因為你使用的是“change”,而不是“delete”。

再看一個示例。執(zhí)行下面的命令:

:onoremap b /return<cr>

現(xiàn)在把下面的文字輸入到緩沖區(qū):

def count(i):
    i += 1
    print i

    return foo

把光標(biāo)放到第二行的i上,然后按下db。會發(fā)生生么?Vim把整個函數(shù)體中直到return上面的內(nèi)容都刪除了,return就是上面的映射使用Vim的通用查找得到的結(jié)果。

當(dāng)你想搞清楚怎么定義一個新的operator-pending movement的時候,你可以從下面幾個步驟來思考:

  1. 在光標(biāo)所在的位置開始。
  2. 進入可視模式(charwise)。
  3. ... 把映射的按鍵放到這里 ...
  4. 所有你想包含在movement中的文字都會被選中。

你所要做的工作就是在第三步中填上合適的按鍵。

改變開始位置

你可能已經(jīng)從上面所學(xué)的東西中意識到一個了問題。如果我們定義的movements都是從光標(biāo)所在的位置開始的話,那么這就會限制我們做一些我們想使用movement來做的事情。

但是Vim并不會限制你去做你想做的事情,所以對于這個問題肯定有解決辦法。執(zhí)行下面的命令:

:onoremap in( :<c-u>normal! f(vi(<cr>

這個命令看起來有些復(fù)雜,不過我們還是先試試它能干什么。將下面的文字輸入緩沖區(qū):

print foo(bar)

把光標(biāo)放到單詞print上面,然后敲擊cin(。Vim會刪除括號內(nèi)的內(nèi)容然后進入插入模式,并且光標(biāo)會停留在括號的中間。

你可以將這個映射理解為“在下一個括號內(nèi)(inside next parentheses)”。它會對當(dāng)前行光標(biāo)所在位置的下一個括號內(nèi)的文本執(zhí)行operator。

我們再創(chuàng)建一個“在上一個括號內(nèi)(inside last parentheses)”的movement進行對照。(在這里使用“前一個(previous)“可能更準(zhǔn)確,但這會覆蓋“段落(paragraph)”movement)

:onoremap il( :<c-u>normal! F)vi(<cr>

先試試確保這個命令可以工作。

那么這些映射是怎么工作的呢?首先,<c-u>比較特殊,可以先不用管(你只需要相信我這個東西可以讓這個映射在任何情況下都能正常工作)。如果我們刪除它的話,這個映射會變成這個樣子:

:normal! F)vi(<cr>

:normal!會在后面的章節(jié)談到,現(xiàn)在你只需要知道它可以在常用模式下模擬按下按鍵。例如,運行:normal! dddd會刪除兩行,就像按下dddd。映射后面的<cr>是用來執(zhí)行:normal!命令的。

那么現(xiàn)在我們可以認(rèn)為這個映射的關(guān)鍵是運行下面這些按鍵組成的命令:

F)vi(

This is fairly simple: 這個命令很容易理解:

  • F): 向后移動到最近的)字符。
  • vi(: 進入可視模式選擇括號內(nèi)的所有內(nèi)容。

這個movement結(jié)束在在可視模式下選擇中我們想操作的文本,然后Vim會對選中的文本執(zhí)行操作,就像通常情況一樣。

一般規(guī)則

下面兩條規(guī)則可以讓你可以很直觀的以多種方式創(chuàng)建operator-pending映射:

  • 如果你的operator-pending映射以在可視模式下選中文本結(jié)束,Vim會操作這些文本。
  • 否則,Vim會操作從光標(biāo)的原始位置到一個新位置之間的文本。

練習(xí)

為"around next parentheses"和"around last parentheses"創(chuàng)建operator-pending映射

為打括號創(chuàng)建類似的in/around next/last的mappings。

閱讀:help omap-info,看看你可不可以搞清楚<c-u>是干啥的。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號