严格映射
准备好迎接即将到来的疯狂吧。
到目前为止,我们已经用 map
、nmap
、vmap
、以及imap
创建按键映射来节省时间。
这些命令能正常工作,但是都有一个缺点。
运行以下命令:
:nmap - dd
:nmap \ -
现在试试按下 \
(在普通模式中)。看看发生了什么?
当按下 \
键时,Vim 匹配到映射,然后说:“我应该改为运行-
键”。
但是,-
又被映射到做其他的事情了!
Vim 又匹配到了,然后说“哦,我现在必须去运行dd
”,所以就把当前行删除了。
当用这些命令来映射按键时,Vim 也会把其他映射考虑在内。 乍一听起来好像挺不错,但实际上是非常的糟糕的。 让我们来看看这是为什么,但首先删除这些映射吧,运行以下命令:
:nunmap -
:nunmap \
递归
运行命令:
:nmap dd O<esc>jddk
乍一看,它似乎会把 dd
映射为:
- 在当前行上面新建一行
- 退出插入模式
- 向下移动一行
- 删除当前行
- 向上移动到刚刚创建的空行
其实就是“清除当前行内容”。现在试试看。
当按下 dd
后,Vim 就会卡住。
可以通过按 <c-c>
来让 Vim 恢复原样,但是文件中会多出来一大堆空行!到底发生了什么?
这个映射实际上是递归的!当按下 dd
后,Vim 会认为:
dd
被映射了,那么执行映射。- 新建一行。
- 退出插入模式。
- 向下移动一行。
dd
被映射了,那么执行映射。- 新建一行。
- 退出插入模式。
- 向下移动一行。
dd
被映射了,那么执行映射,以此类推。
映射过程永远不会结束!赶紧把这个可怕的命令删除吧,运行以下命令:
:nunmap dd
副作用
这些 *map
命令的一个缺点就是递归的威胁。
另一个就是映射的行为可能会被其他插件中的映射所改变。
当安装一个新的 Vim 插件时,很可能你并不会用到或者记住它创建的所有映射。
即使能做到,也不得不去 ~/.vimrc
文件中看一遍,以确认自定义的映射没有用到插件中映射过的按键。
这会让安装插件变得枯燥无味,并且极易出错。一定会有其他更好的办法。
非递归映射
Vim 提供了另外一个映射命令的合集,当它们在执行操作时,并不会把其他映射考虑在内。 运行命令:
:nmap x dd
:nnoremap \ x
现在按下 \
键,看看会发生什么。
当按下 \
键,Vim 会忽略 x
的映射,并且会执行 x
的默认操作。
它会删除当前字符,而不是删除当前行。
每个 *map
命令都有一个 *noremap
配对命令来忽略其他映射:noremap
、nnoremap
、vnoremap
、以及 inoremap
。
什么时候应该使用这些非递归版本而不是普通版本。
任何时候
是的,很认真的说,任何时候。**
用原始的 *map
命令只会在以后安装插件或者增加新的映射时自讨苦吃。
就不要自找麻烦了,输入一些额外的字符来确保那永远不会发生。
练习
把所有之前添加到 ~/.vimrc
文件中的映射转换成前面提到的非递归版本。
阅读 :help unmap
。
原文地址:http://learnvimscriptthehardway.stevelosh.com/chapters/05.html