Vimscript编程指南

严格映射

=======

坚持住,事情会变得有点复杂的。

到现在为止,我们已经使用了map,nmap,vmap和imap来建立按键映射,用以节省时间。这个方法确实很有效,但是这个方法也存在问题。

运行下面的命令: nmap - dd nap \ -

现在在normal模式下,按下‘\’试试,发生了什么呢?

当你按下‘\’时,vim找到对应的映射,也即是相当于‘-’。但是我们已经把‘-’映射成了其他的功能!最终vim会根据‘-’的映射来操作,也即是‘dd’命令,所以它把当前行给删掉了。

当你用vim来建立映射时,vim会把映射的目标所对应的映射也考虑进来。这个功能看起来确实很不错,但是实际上是个很恶心的功能。我们后面会讨论这个问题。

递归映射

=======

运行下面的命令: nmap dd O<esc>jddk

你可能会认为这个命令会把dd映射成以下几步:

  • 在当前行的上方插入一个新行
  • 退出插入模式
  • 往下移动一行
  • 删除当前行
  • 移动到刚刚创建的那个空行

但是实际上,这个映射的功能是删除当前行。试试

当你按下‘dd’的时候,vim好想死掉了。这时候你按下Ctrl+c,vim会恢复运行,但是你的文件里会多了很多很多的空行!到底是怎么一回事呢?

  • dd被映射了,所以执行映射
    • 插入一个新行
    • 退出插入模式
    • 移动到下一行
    • dd被映射了,所以执行映射
      • 插入一个新行
      • 退出插入模式
      • 移动到下一行
      • dd被映射了,所以执行映射
      • .....

所以这样递归下去,这个映射是无法终止的。

副作用

=======

并不只是我们所学到的*map命令会有递归的风险,并且我们安装的其他的插件也会有这样的风险。

当你安装一个新的插件时,你可能不会使用也不会记住这个插件所使用的映射。如果你用了,那么你就需要你的~/.vimrc文件去看看你自己的映射按键没有被插件使用,同时还要保证插件使用的映射你自己没有使用。

这个问题会让插件安装比较麻烦,并且很容易出现问题。vim里肯定有更好的办法。

非递归映射

=======

vim提供了另外的一些建立映射的命令,它们不会进行递归的映射。试试下面的命令:

:nmap x dd :nnoremap \ x

现在试试按‘\’,看看会发生什么。

当你按下‘\’时,vim会把他映射成x的操作,并且忽视x的进一步映射。这次不再是删除当前行了,只会删除当前的字符。

所有的map命令都有对应的noremap命令来忽视递归的映射,它们分别是:nnoremap,vnoremap和inoremap。

什么时候使用非递归映射

=======

什么时候需要用这些映射命令的非递归版本来替代递归版本呢?答案是:一直都需要。

注意,是一直都需要!

使用最基本的nmap命令会让你在按照插件或者建立新的映射时非常的痛苦。为了省去不必要的麻烦,建议你还是多输入几个字符,保证不要出现因递归的映射带来的负效应。

练习

============

  • 把你的~/.vimrc文件里的所有的映射命令换成它们的非递归版本。