更多的操作符等待映射

操作符和移动的思想是 Vim 最重要的概念之一,而且这也是 Vim 如此效率的最大原因之一。 我们将加强练习定义新的移动,因为扩展这种强大的思想使 Vim 更加强大。

比方说你正在 Markdown 里编辑一些文本。如果你之前没有使用过 Markdown,也不用担心,这里只是出于很简单的目的。 键入以下文本到文件中:

Topic One
=========

This is some text about topic one.

It has multiple paragraphs.

Topic Two
=========

This is some text about topic two.  It has only one paragraph.

这些以 = 字符为下划线的行会被 Markdown 当成标题来处理。 让我们创建一些映射,能使我们移动到标题。运行以下命令:

:onoremap ih :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>

这个映射相当的复杂,把你的光标放在某个段落中(非标题上),然后键入 cih。 Vim 会删除所在段落的标题,然后进入插入模式(“更改内部标题”)。

这里使用了一些之前完全没见过的东西,就让我们单独看看每一部分。 映射的第一部分,:onoremap ih 就是以前见过的映射命令,那我们就略过。 而 <c-u> 我们还是再次忽略。

现在我们看看这行中余下的内容:

:execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>

Normal 命令

:normal 命令会装载一个字符集,并且会执行它们在普通模式下做的任何行为。 我们会在后面的章节中讲到更详细的细节,但是我们已经见过好几次了,所以这次最少浅尝下滋味。 运行命令:

:normal gg

Vim 会让你移动到文件的顶部。现在运行命令:

:normal >>

Vim 会缩进当前行

到目前为止,不要担心映射中在 normal 后面的 !。我们马上就会讲到。

Execute 命令

execute 命令装载一段 Vimscript 字符串(我们会在以后涉及更多细节),并且作为一个命令来执行。 运行命令:

:execute "write"

Vim 会保存文件,就像你键入了 :write<cr>。现在运行命令:

:execute "normal! gg"

Vim 会运行 :normal! gg,就像我们刚刚看到的,它会让你移动到文件的顶部。 但是当我们只需要运行 normal! 命令本身时,为什么还要这么麻烦?

看看以下命令,然后猜猜它会做什么:

:normal! gg/a<cr>

看起来它会:

运行它。Vim 会移动到文件顶部,但并没有任何其他的!

问题出在 normal! 并不能识别“特殊字符”,比如 <cr>。 有很多方法可以避免这个问题,但是最简单、也是最易读的就是 execute

execute 看到需要运行的字符串时,它会在运行之前把所有找到的特殊字符替换掉。 在上面的例子中,\r 是一种转义字符,意思是“回车”。 双反斜杠也是一种转义字符,它会把一个反斜杠放入字符串中。

如果我们运行这个来替换之前的映射,并看看结果,我们可以发现映射将会执行:

:normal! ?^==\+$<cr>:nohlsearch<cr>kvg_
                ^^^^           ^^^^
                 ||             ||
这些是**正真的**回车键,而**不是**“左尖括号”、“c”、“r”、和“右尖括号”这四个字符。

那么现在 normal 会执行这些字符,就和我们在普通模式中输入他们一样。 让我们以回车来分割它们,并看看他们做了些什么:

?^==\+$
:nohlsearch
kvg_

第一部分,?^==\+$ 反向搜索包括了两个或更多等号并且不含其他内容的所有行。 这会让光标停留在等号行的第一个字符处。

我们进行反向搜索是因为当你想要“更改内部标题”,而光标正在一段文本中时,你可能是想更改这个段落的标题,而不是下一个。

第二部分是 :nohlsearch 命令。这只是简单的清除刚刚的搜索高亮,所以这并不会分散注意力。

最后一部分是三个普通模式命令组成的序列:

结论

这是很繁重的工作,刚刚我们已经看过了映射的每一部分。概括来说:

在继续之前,让我们再看一个映射。运行以下命令:

:onoremap ah :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rg_vk0"<cr>

试试把光标放到一段文本上,并键入 cah。这次 Vim 不仅会删除标题文本,而且会删除表示标题的等号行。 你可以把这个移动看作是“包围这个段落的标题”。

这个映射有什么不同呢?让我们并排来比较:

:onoremap ih :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>
:onoremap ah :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rg_vk0"<cr>

和之前的映射比,唯一的不同就是结尾,这关系到我们要操作什么文本:

inside heading: kvg_
around heading: g_vk0

既然映射的其他部分都是是相同的,那么我们就仍然从在等号行的第一个字符处开始。从这开始:

结果是文本和等号行都被可视化选择了,而且 Vim 会对它们进行操作。

练习

Markdown 也可以用 - 字符来划定标题。调整这些映射的正则表达式使其能处理每种标题。 你也许会想看看 :help pattern-overview。记住正则表达式是在字符串里的,那么反斜杠必须要转义。

确保仅仅在恰当的缓冲中映射它们,并且把他们归类到组,这样就不会在每次载入执行时创建重复的映射。

阅读 :help normal

阅读 :help execute

阅读 :help expr-quote 看看在字符串中可以使用些什么转义序列。

创建一个“进入下一个电子邮件地址”的操作符等待映射,这样你可以说“更改下一个电子邮件地址”。 [email protected] 是个不错的候选按键。你大概会想用 /...一些正则表达式..<cr> 来实现这个映射。

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