准备好,下面的内容会比较难以理解。
目前为止,我们已经使用`map`、`nmap`、`vmap`以及`imap`创建了实用的按键映射。 他们很方便,但是有个缺点。运行下面的命令:
~~~
:nmap - dd
:nmap \ -
~~~
试试按下`\`(在normal模式)。有什么现象?
当你按下`\`时,Vim会解释其为`-`。但是我们又映射了`-`!Vim会继续解析`-`为`dd`, 即它会删除整行。
你使用那些命令创建的映射可能会被Vim解释成 _其它_ 的映射。乍一听这像是一个优点, 但实际上这很变态。解释原因之前,我们先用如下命令删除那些映射:
~~~
:nunmap -
:nunmap \
~~~
## 递归
运行命令:
~~~
:nmap dd O<esc>jddk
~~~
上面的命令看上去像是要映射`dd`为:
* 在当前行之前添加新行
* 退出insert模式
* 向下移动一行
* 删除当前行
* 向上移动到新加的行
貌似这个映射的作用是“清除当前行”。但你可以试试。
当你按下`dd`后,Vim就不动了。按下`<c-c>`才可以继续,但是你的文件中会多出许多 空行!想想发生了什么?
这个映射实际上是 _递归_ 的!当你按下`dd`后,Vim解释为:
* `dd`存在映射,执行映射的内容。
* 新建一行。
* 退出insert模式。
* 向下移动一行。
* `dd`存在映射,执行映射的内容。
* 新建一行。
* 退出insert模式。
* 向下移动一行。
* `dd`存在映射,执行映射的内容。然后一直这样。
这个映射永远不会结束!删除这个可怕的映射再继续:
~~~
:nunmap dd
~~~
## 负面影响
`*map`系列命令的一个缺点就是存在递归的危险。另外一个是如果你安装一个插件,插件 映射了同一个按键为不同的行为,两者冲突,有一个映射就无效了。
当安装一个新的插件时,可能你不会使用或记住每一个其创建的映射。即使你记住了,你还得 回看下你的`~/.vimrc`文件以确保你自定义的映射与插件创建的没有冲突。
这导致插件安装变得乏味,易于出错。肯定有个解决办法。
## 非递归映射
Vim提供另一组映射命令,这些命令创建的映射在运行时 _不会_ 进行递归。运行命令:
~~~
:nmap x dd
:nnoremap \ x
~~~
按下`\`看看有什么现象。
当你按下`\`时,Vim忽略了`x`的映射,仅按照`x`的默认操作执行。即删除当前光标下的字符 而不是删除整行。
每一个`*map`系列的命令都有个对应的`*noremap`命令,包括:`noremap`/`nnoremap`、 `vnoremap`和`inoremap`。这些命令将不递归解释映射的内容。
该何时使用这些非递归的映射命令呢?
答案是: **任何时候** 。
**是的,没开玩笑, _任何时候_ 。**
在安装插件或添加新的自定义映射时使用`*map`系列命令纯属是给自己 _找_ 麻烦。 多敲几个字符以确保这个问题不会发生,救自己于火海。
## 练习
将之前章节中添加到`~/.vimrc`文件中的映射命令全部换成非递归版本。
读帮助文档`:help unmap`。
- 前言
- 鸣谢
- 预备知识
- 打印信息
- 设置选项
- 基本映射
- 模式映射
- 精确映射
- Leaders
- 编辑你的Vimrc文件
- Abbreviations
- 更多的Mappings
- 锻炼你的手指
- 本地缓冲区的选项设置和映射
- 自动命令
- 本地缓冲区缩写
- 自动命令组
- Operator-Pending映射
- 更多Operator-Pending映射
- 状态条
- 负责任的编码
- 变量
- 变量作用域
- 条件语句
- 比较
- 函数
- 函数参数
- 数字
- 字符串
- 字符串函数
- Execute命令
- Normal命令
- 执行normal!
- 基本的正则表达式
- 实例研究:Grep 运算符(Operator),第一部分
- 实例研究:Grep运算符(Operator),第二部分
- 实例研究:Grep运算符(Operator),第三部分
- 列表
- 循环
- 字典
- 切换
- 函数式编程
- 路径
- 创建一个完整的插件
- 旧社会下的插件配置方式
- 新希望:用Pathogen配置插件
- 检测文件类型
- 基本语法高亮
- 高级语法高亮
- 更高级的语法高亮
- 基本折叠
- 高级折叠
- 段移动原理
- Potion段移动
- 外部命令
- 自动加载
- 文档
- 发布
- 还剩下什么?