操作符等待映射

在这一章节中,我们要探索另一个 Vim 映射系统中的无底洞:“操作符等待映射”。 让我们抽出身先弄明白它的字面含义。

一个操作符是一种命令,它会等待你输入一个移动命令, 然后对当前位置和移动后的位置之间的文本做一些操作。

dyc 就是些操作符。例如:

按键   操作符     移动
----   --------   -------------
dw     删除       到下一个单词
ci(    修改       括号中
yt,    复制       逗号之前

移动映射

Vim 可以创建新的移动,并可以和所有现存的命令配合使用。 运行以下命令:

:onoremap p i(

现在键入以下文本:

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

把光标放在“cat”单词上,然后键入 dp。发生了什么?Vim 会删除所以括号中的文本。 你可以把这个新的移动看作是“修改参数”。

onoremap 命令告诉 Vim 在等待给操作符的移动命令时,如果是 p,应该把它当做 i( 来处理。 当我们输入 dp,它就像是在说“删除参数”,而 Vim 会翻译成“删除括号中的内容”。

我们可以配合所有操作符来使用这个新映射。输入和之前一样的文本(或者仅仅撤销修改):

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

把光标放在“cat”单词上,然后键入 cp。发生了什么? Vim 删除了括号中所有的文本,但是这次停留在了插入模式,因为是“替换”而不是“删除”。

让我们看看另一个例子。运行以下命令:

:onoremap b /return<cr>

现在输入以下文本:

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

    return foo

把光标放在第二行的 i 上,然后按下 db。发生了什么? Vim 删除了函数中直到 return 为止的全部内容,而 return 正是映射通过 Vim 的普通搜索找到的。

当你尝试思考如何定义一个新的操作符等待移动命令时,不妨像下面这样思考:

  1. 在光标所在处开始。
  2. 进入可视模式(字符模式)。
  3. ... 这里是映射按键 ...
  4. 所有你想包含的文本现在都应该被选中了。

你要做的是在第三步中填入合适的按键。

更改开始位置

你也许已经发现目前学习的内容中有个问题。 那就是我们的移动总是必须在当前光标处开始,这就限制了我们能做的事。

Vim 并不会限制你能做什么,所以当然有方法来避免这个问题。运行以下命令:

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

这也许看上去有点吓人,但是让我们试试看。输入以下文本:

print foo(bar)

把光标放在 print 单词上的某处,然后键入 cin(。 Vim 会删除括号中的内容,然后使你处于插入模式,并且在括号中间。

你可以把这个映射看作是“进入下个括号”,它会在本行下一对括号中的文本上执行操作符。

让我们创建一个相对的“进入上个括号”(它会覆盖“段落”的移动)映射。运行以下命令:

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

你可以自己输入一些文本来试试,并确保它能正常工作。

那么这些映射是如何工作的?首先,<c-u> 是比较特殊的,你可以先不考虑 —— 只要相信为了让映射在所有的情况下都能正常工作,它就必需在这。 如果我们去除了它,就只剩下了:

:normal! F)vi(<cr>

:normal 是我们在后面的章节中会讲到的东西, 但现在只要知道这是一个用来模拟在普通模式下按下按键的命令就行了。 例如,运行 :normal! dddd 会删除两行,就像按下了 dddd。 映射最后的 <cr> 是用来执行 :normal! 命令的。

那么现在我们知道了这个映射本质上只是运行了最后一部分按键:

F)vi(

这就相当的简单了:

我们以想要操作的文本被可视化选中为结束,Vim 就会像往常一样对它执行操作。

基本规则

想要理清楚创建操作符等待映射的众多方式就要谨记以下两条规则:

练习

创建“包围下个括号”和“包围上个括号”的操作符等待映射。

为花括号创建相似的进入(包围)下个(上个)的映射。

阅读 :help omap-info,看看你能否推测出在这个例子中 <c-u> 的作用。

原文地址:http://learnvimscriptthehardway.stevelosh.com/chapters/15.html