vim_thumb

Learning Vimscript The Hard Way — (5) Strict Mapping/严格映射

严格模式

准备好,下面的内容有点绕(wild)。

到现在,我们已经用 map, nmap, vmap imap 来创建一些节省时间的键盘映射了。这些东西的确有效,不过它们还有些不足。运行下面的命令:

:nmap – dd :nmap \ –

现在试试按一下 \(在常规模式下)。发生了什么呢?

当你按下 \ 的时候,Vim 发现了映射,然后说:“我应该转而执行一个 (减号)”。但是我们已经将  (减号)映射去干别的事情了!Vim 看到了,然后说:“哦,我现在应该运行 dd”,然后它就把当前行删掉了。

当你用这些命令映射键的时候,Vim 就会将其他的映射考虑在内(take into account)。这乍听起来好像不错,但实际上却非常邪恶。让我们来谈谈为什么,但是在这之前先让我们把原来的映射删掉:

:nunmap – :nunmap \

递归

运行下面这个命令:

:nmap dd O<esc>jddk

第一眼看下去,这会将 dd 映射到(下面的步骤):

  • 在当前行之前插入一个空行(并且进入插入模式);
  • 退出插入模式;
  • 移动回下一行【也就是开始那行】;
  • 删除当前行;
  • 移动到刚才插入的那个空行;

事实上这应当“清空当前行”。试一下。

当你按下 dd 之后,Vim 会卡死。如果你按下 <c-c> 你会让 Vim 恢复过来(get Vim back),但同时会有一大堆的空行进入了你的文件!到底发生了些什么?

这个映射其实是一个递归!当你按下 dd 的时候,Vim 说:

  • dd 已经映射了,因此执行映射(的动作):
    • 开一个空行
    • 退出插入模式
    • dd 已经映射了,因此执行映射(的动作):
      • 开一个空行
      • 退出插入模式
      • dd 已经映射了,因此执行映射(的动作)。如此类推

这个映射可以一直不停地跑下去!快去把这个糟糕的映射用下面这个命令删掉:

:nunmap dd

副作用

*map 命令有一个副作用就是递归的危险。另一个就是如果你安装了一个插件,这个插件映射了它们用到的一些键,他们的行为就会改变。

当你安装一个新的 Vim 插件,你很可能(There is a good chance)不会用到并且记住它创建的所有映射。就算你会,你也不得不回头通读你的 ~/.vimrc 文件来确定你的自定义映射里面没有使用插件里面映射过的键。

这会使得安装插件变得极度繁琐并且容易出错(error-prone)。一定有更好的方法。

无递归映射

Vim 提供了另外一套映射命令,在执行中不会考虑其中的映射【不检查里面的键的映射】。运行下面的命令:

:nmap x dd :nnoremap \ x

现在按一下 \ 然后看看发生了些什么。

当你按下 \ Vim 忽略了 x 的映射然后做默认情况下 x 所做的东西。它没有删掉当前的行,而仅仅是删掉了当前的字符。

每个 map 命令都有一个对应的 noremap 配套命令可以忽略其他的映射:noremap, nnoremap, vnoremap inoremap

我们什么时候才该用到这些无递归的版本而不是他们的原版命令呢?

【答案是】应该总是这么做

不,很严肃地说,一定要这样

使用一个裸露的的 *map 就是作死 (asking for pain),当你以后安装一个插件或者增加新的自定义映射的时候【你就知道了】。为了避免自找麻烦,多写几个字来确保它不会发生。

练习

将你现在在此前章节中加到 ~/.vimrc 里面的映射全部转换成无递归版本。


【转载请附】愿以此功德,回向 >>

原文链接:https://www.huangwenchao.com.cn/2014/10/vimscript-hard-5.html【Learning Vimscript The Hard Way — (5) Strict Mapping/严格映射】

发表评论

电子邮件地址不会被公开。 必填项已用*标注