简单聊聊Vim中的自定义快捷键

摘要:

  1. Vim中几个Map命令的区别
  2. 分享几个自定义的快捷键

前言

平常在Vim中自定义快捷键,使用的都是map命令,但最近发现自定义快捷键命令还有好多,如noremapnmapvmap等等。所以就想写一篇关于Vim中自定义快捷键的文章,来总结一些Vim中的自定义快捷键的命令和他们的命名方式。

与自定义快捷键相关的四个系列命令

map系列命令

这个命令的声明如下: :map {lhs} {rhs}。这个命令就是将{lhs}代表的按键映射成{rhs}所代表的按键。例如map L $就是将$键映射成L。此外需要注意的是map命令定义的快捷键是可以嵌套的,例如下面这样的命令:

map L $
map Y yL

就是将Y按键映射成了y$按键。

noremap系列命令

这个命令的声明如下: :no[remap] {lhs} {rhs},顾名思义,就是不可以重新映射的命令。这个命令和map命令类似,不过它所定义的命令不可以被重新映射,例如下面的例子:

map L $
map Y yL

此时我们映射的Y按键的效果就不会和y$按键的效果相同了。此命令的主要作用是为了防止按键重新定义时出现冲突,所以一般推荐使用此命令来映射快捷键。

unmap系列命令

unmap,顾名思义,就是用来取消所在模式下快捷键的定义(关于模式我们下一小结会将)。

mapclear系命令

mapclear,清除所在模式下定义的所有快捷键。

自定义快捷键相关的六种模式

在Vim中,共有六种模式,不同的定义快捷键的命令生效的模式不同,这六种模式如下:

  • Normal Mode: 即Vim的普通模式,我们打开Vim后进入的第一个模式即此模式。
  • Visual Mode: 即Vim的Visual模式,我们在选中了一定的文本之后(通过v或者V命令)即进入此模式。
  • Select Mode: 这种模式和Visual模式相似,不过输入的文本都会替换选中的文本。在普通模式下,通过鼠标选中或者使用gH命令都可以进入此模式。
  • Operator-pending Mode: 当我们输入一个操作符后(例如,dyc等等),就会进入此模式。
  • Insert Mode: 即Vim的插入模式,普通模式下我们输入i(或者s,a等等)就会进入此模式。
  • Command-line Mode: 命令行模式,我们在普通模式下输入:或者/等就会进入此模式。

命令模式对应表

下表表示了每个自定义快捷键的命令和其对应的生效模式,需要注意的是Lang-Arg并不是一种新的模式,而是表示了这样一种情况。当我们键入一个字符的时候,它是缓冲区中文本的一部分,而不是一个Vim命令。上面这句话我翻译自Vim文档,我感觉自己也没有很是搞懂,所以还是把原文贴出了吧(参见:help language-mapping):

Generally: Whenever a character is to be typed that is part of the text in the buffer, not a Vim command character. “Lang-Arg” isn’t really another mode, it’s just used here for this situation.

map系命令 noremap系命令 unmap系命令 mapclear系命令 生效模式
:map :noremap :unmap :mapc[lear] Normal, Visual, Select, Operator-pending
:nmap :nnoremap :nunmap :nmapc[lear] Normal
:vmap :vnoremap :vunmap :vmapc[lear] Visual and Select
:smap :snoremap :sunmap :smapc[lear] Select
:xmap :xnoremap :xunmap :xmapc[lear] Visual
:omap :onoremap :ounmap :omapc[lear] Operator-pending
:map! :noremap! :unmap! :mapc[lear]! Insert and Command-line
:imap :inoremap :iunmap :imapc[lear] Insert
:lmap :lnoremap :lunmap :lmapc[lear] Insert, Command-line, Lang-Arg
:cmap :cnoremap :cunmap :cmapc[lear] Command-line

通过观察上面这些命令的前缀,我们可以发现,命令前缀和生效的模式有关。例如,v表示Visual和Select模式,s表示Select模式,c表示Command-line模式,等等。

分享两个我自己定义的快捷键

Ok,扯了那么多和自定义快捷键相关的东西,接下来我和大家分享几个我自定义的快捷键吧,感觉用起来很爽,希望对大家有帮助。

Tab键映射成搜索

搜索无疑是一个使用频率非常高的快捷键,但在原始的Vim中使用的却是/或者?,当要使用搜索功能的时候,我的右手要离开HomeRow(就是爱上对方过后就哭了那一行),然后使用中指或者食指去按/,感觉虽然也可以用右手小拇指去按/,但实在是太费劲。

所以我就把/映射成了<Tab><Tab>键在普通模式下基本用不到,同时左手小拇指又非常容易按到,感觉一下子方便了许多。映射命令如下:

" 映射/为<Tab>
noremap <Tab> /

大家可以看到,我这里使用的是noremap映射的(防止以后再来映射和<Tab>键相关的组合键时出现错误),同时,这个命令生效的模式是NormalVisualSelectOperator-pending。这样我不仅可以在普通模式下搜索,也可以在选择文本(Visual),删除文本(通过d命令)时进行搜索。

后来我才发现,<Tab><C-i>的keycode是一样的,无法分别映射,所以将<Tab>映射为搜索按键会影响到<C-i>的功能,所以还是先删除掉吧。

快速定位当前文件

这条映射是我在《VIM 实用技巧》中看到的,感觉很好用,特意来分享给大家。此映射命令如下:

" 将%:h映射为%%,%:h的功能是显示当前缓冲区文件的相对路径
cnoremap <expr> %% getcmdtype() == ':' ? expand('%:h').'/' : '%%'

这条命令比较复杂,首先cnoremap表示在命令行模式下进行映射,<expr>表示将映射命令的右边的参数当做一个表达式来对待(详见: :help :map-<expr>)。

%%就是我们定义的快捷键,getcmdtype() == ':' ? expand('%:h').'/' : '%%'就是我们要执行的表达式,此命令的含义就是每当我们在命令行模式下输入%%,就会得到表达式getcmdtype() == ':' ? expand('%:h').'/' : '%%'运算的结果。

接着我们再来分析一下这个表达式,getcmdtype() == ':' ? expand('%:h').'/' : '%%'

首先来看调用的两个函数,getcmdtype表示获取当前命令行模式的类型,:表示是Ex-Mode,就是在普通模式下输入:进入的模式,此外其他的返回结果参见:help getcmdtype()expand()函数表示对通配符进行扩展,其中传入的参数为%:h%表示当前缓冲区文件,:h相当于一个函数,传入一个文件参数,返回文件所在的文件夹(相当于Python中的os.path.dirname()),我们可以看到expand('%:h')函数的功能就是返回当前缓冲区文件所在的路径。

整体来看这个表达式的话,就是一个三元运算符,如果当前模式是Ex-Mode的话,返回当前缓冲区文件所在的文件夹,否则的话返回%%

有待考证和完善之处

写文章之前,我觉得我应该已经了解了Vim的map相关的命令,但是写完以后,发现还是有很多疑问,写到最后发现还有新东西自己没有涉及,这里先记录下来,以待以后完善:

  1. map的递归定义的用法。我看到:help :map文档中说,**This allows for nested and recursive use of mappings.**也就是说map可以进行递归定义的,只是不知道怎么用,递归出口在哪?
  2. map命令还有一个map-<expr>的用法,这次还没有将,以后加上。
  3. 关于文档中Lang-arg还不是很懂。
2017年03月26日 / 17:19