VIM到底香不香?

VIM到底香不香?

今天说一个古老的话题,VIM作为一个编辑器,香么?

初见

Stack Overflow上有两个问题常年高居热门榜,那就是"我要怎么在VIM内编辑"、"我要怎么才能退出VIM"。
这也是我初次使用VIM的感受,linux无UI的黑框框对新手小白已经很不友好了,这破玩意儿编辑器用起来也这么反人类,是闹哪样的?就不能好好的,开箱即用,打开就能编辑,最多加一个保存,一个撤销复用功能,然后用exit或者ctrl+c退出,不就完了么?

“吾不笑别人,单笑乌班图无谋,红帽少智......”(狗头)

最诡异的莫过于,你嗤之以鼻的东西,网上冲浪见到的大佬们都觉得香。错的是我,还是世界?

认识VIM

话不多说,接入正题,如何正确的使用VIM?这部分就是想从一个VIM中级使用者的角度,缓缓揭开VIM的使用真相。

1. 历史与基本原则

理解了VIM的使用原则,是使用的第一步,之后遇到新的快捷键,也会很快上手。

首先明确一点,VIM的使用前提是全键盘操作,上古时代,没有视窗操作系统,操作全凭手打,这是VIM诞生的背景,使用者能盲打是提升VIM使用效率的第一步。对于个人而言,如果不适应无鼠标的工作,那么VIM的存在会很膈应,使用哲学上就是和个人习惯相悖的。

要认识现在,先了解过去,一起看看VIM和它的祖爷爷们的历史:

  • 1966年,QED(Quick EDitor)编辑器诞生,那个时候没有显示屏作为显示终端,所谓的终端就是把一行信息打印到纸上的打印机,所以QED诞生的时候,就是一个行编辑器,操作时,需要手动指定更新内容和范围;
  • 1969年,当时大名鼎鼎的AT&T内诞生了基于QED的ED编辑器,
  • 1976年,em(Editor for Mortals)诞生;
  • 同年,加州大学伯克利分校的研发人员在em基础上开发出了ex(Extended);EX是最后一代行编辑器,
  • 再后一年,VI(visual interface)诞生,vi最大的变化就是可视化的编辑,摒弃了过去的行编辑模式,人们终于可以在终端上看到整个文本了,
  • 这之后,编辑器届的发展一度很喧嚣,针对VI的改进版本层出不穷,直到1991年,VIM的第一个版本才正式发布,VIM的取名源自Vi IMproved。目前VIM已经发布到第八个正式版本,也就是VIM 8。

我们今天使用的一些命令,都可以看到它祖辈们的影子,比如hjkl用来移动光标,比如ex目前都还是内置的行编辑命令,命令行模式也被叫做ex模式,不经意间透露出“忆往昔峥嵘岁月稠”的沧桑,那是计算机萌芽期留下来的活化石。也从侧面反映,今天VIM的样子,是经历过数十年码农的悉心调教后,长成的模样,每一个使用细节的背后,必然有其设计的理由,试图理解这里面的逻辑,也会别有洞天。可以记住这句话:VIM能以与思考同步的速度编辑文本。

除了上面列的几点,祖辈们给VIM留下的最大的特点是:编辑器的模式

所有新手小白对于VIM的愤怒,都来自于对模式的不了解。 ——鲁迅

打开文件,默认是普通模式,我们只能读文件,不能插入新内容,要直接写文件,需要切换模式,分离读写操作,是一个好习惯,任何层次上都是。这个模式下,我们要学会的是如何更好的移动光标(w,b,z,g,f,F,/,?,$,^,%),不过不代表普通模式下不能改变文件,我们有x,d,p等命令来完成删除、复制等操作。

我们惯常使用的编辑模式,对应到VIM上,叫插入模式,普通模式下a,i,c,s等按键,可以达到切换到插入模式的效果,插入模式只能进行简单的编辑操作。这个模式下,按键是用来处理输入的,也没有太多快捷键,但是某些场景下可以与其它模式进行联动,加快输入的速度。

再接下来,是可视模式,视窗操作系统下,我们要选取一块区域的时候,可以滑动鼠标进行,在VIM上,可视模式,就是用来做这个事情的,将选取的部分高亮,为下一步的处理做准备。通常按v可以进入,或者shift+v进入行选择模式,ctrl-v进入多列选择模式。可视模式下,普通模式的快捷键大多有效,比如选中以后y一下,就可以复制选中内容,按下esc,然后p一下,就可以快速复制,又或者我们可以通过w,b,$,^,e等光标移动命令,调整选中区。

最后是命令行模式,也就是前面提到的ex模式,我们在普通模式下输入冒号就可以进入,之前stack overflow上对于怎么退出的问题,就是要在命令行模式下操作的,在这个模式下,常见的可以进行文件、窗口操作,甚至可以运行系统命令行。

展示一张网上找来的VIM快捷键键位图:

要学习所有快捷键是需要花时间在实践种掌握的,这里就不赘述了。建议看一些VIM相关的文档和书籍,再慢慢摸索。

2. 一些技巧

VIM作为历史悠久的编辑工具,在使用上,是有一些准则和窍门的。

技巧1 不要自我重复

.命令在VIM中表示,重复之前的一次编辑操作,在这个命令的基础上,利用移动+重放的模式可以为我们节省很多重复操作。
举一个例子:
有html文件如下,我们现在要把所有括号内的内容置空,可以怎么做?

(text1),(text2),(text3)

常规操作:
a进入插入模式,然后找到内容,一个个删除;
重读操作多次,麻烦。如果有鼠标的话,可能会双击选中,然后删除,然后重复三次,其实效率也不高。

推荐操作:

  1. 首先f+(,表示在行内查找左括号;
  2. 然后回车,找到第一个,按d+i+(d表示删除,i表示include,(表示括号,组合在一起表示:把括号内的内容删除;
  3. 按';'寻找下一个左括号;
  4. 然后按'.',重复之前的编辑操作,这时,第二个括号内的内容就会删除,
  5. 重复3,4步骤,即可快速重复之前的编辑操作;

可以发现,第二种方式里,我们把移动光标、编辑两个操作分离了,移动光标可以通过查找逻辑来完成,编辑操作只需要执行一次,然后后续只要执行重放逻辑就好了。你甚至不需要切换到插入模式。这样的效率比之前要高很多。

可以再来一个例子,例如,把之前括号内的内容都替换为"good job",步骤如下:

  1. f+t,查找字母t;
  2. c+w,删除单词并进入插入模式,
  3. 输入“good job”
  4. esc退出插入模式
  5. ;查找下一个
  6. 按'.'实现重放
  7. 重复5,6,直到全部改完

这种模式可以总结为:用一个键移动,用另一个键执行。或者可以叫术语“.”范式。

技巧2 选择最优的修改方式

我们在编辑文本的时候,要达到同样的效果,可以有很多种方式,从结果上看,他们都是等价的,这种时候,要如何选择呢?

评估某种修改方式是不是最优,首先可以比较按键次数,按键次数越少,效率越高,然而平局时,怎么选择呢?

举个例子,如下所示文本,假设光标停留在最后一个h上,而我们想要删除的单词是nigh:

The end is nigh

方式1:db反向删除,剩下一个字母h,再用x删除

方式2:正向删除,b回到单词开头,然后dw删除单词

方式3: 删除整个单词daw,这个命令组合可以理解成delete a word

三种方式的按键次数都是三次,效果都是删除一个单词,那么哪种更优呢?

这个时候我们可以看修改命令的可重复性,可重复性好的命令,有机会和.范式结合,大幅提高效率;细心的会注意到,第三种方式操作完以后,不光删除了整个单词,同时也连带着删除了单词前面的空格,光标停留在了s上,而前两种方式光标则停留在了空格上。试想一下,我们在操作完以后想要继续删除is,只有第三种方式可以无缝复用起来。

所以,评判修改方式的优劣,一看效率,二看可复用性。可以养成选择可复用性好的编辑操作的习惯。

技巧3 认识文本对象

文本对象(text object)是VIM里面非常有用的概念,文本对象的操作可以针对单词、句子、段落这种大范围的文本内容显著提高执行效率。
通常,VIM的命令执行模式如下:
[number]<command>[text object or motion]
其中number表示作用的文本对象数量,command表示执行的具体命令,比如dp(删除、复制),之后跟的表示具体的文本对象,比如单词、句子、段落。
我们使用文本对象的时候,通常是一个限定词+一个范围词结合使用。

  • 限定词有ai两种,分别表示一个和`之内
  • 范围词有很多,比如下表所示
字母 w s p t <或者>
含义 单词 句子 段落 标签 一组尖括号包围的文本

还有很多,比如{[(等等,都可以以此类推。限定词和范围词组合起来,比如aw就是一个单词,i{表示一组大括号内部的文本。

这个有什么用处呢?
我们可以看下下面这个html,我们想要删除span这个tag内的文字:
<span>this is a span</span>
可以通过dit来完成,如果删除后,想立刻进入插入模式,则可以使用cit

又比如,我们要删除函数内的大段内容,如下所示,可以通过a{i{来实现:

技巧4 寄存器

我们在复制内容的时候,有时候想要保留多一些复制栈,但是系统的剪贴板的深度只有1,第二次复制的时候,会把前一次复制的内容覆盖掉。

VIM通过寄存器,解决了这个问题,默认寄存器每次会被覆盖,但是其他寄存器不会被轻易更改。
普通模式下,输入:reg然后回车,可以看到当前的寄存器变量:

通常,我们删除、复制(d\c\x\y)执行操作后,受影响的文本会进入默认寄存器"",我们复制的时候,可以通过命令行模式指定复制到或者剪贴到特定的寄存器上。

各个模式下,如何调用寄存器的值:

  • 普通模式: "{register name}
  • 命令模式: <ctrl+r> + "寄存器名称
  • 插入模式: <ctrl+r> + 寄存器名称

VIM内,内置了以下几种寄存器:

  • 无名寄存器,也是默认寄存器,引用方式:""
  • 字母寄存器,引用方式:"a - "z 或"A - "Z
  • 数字寄存器,引用方式:"0 (数字0)- "9
  • 复制专用寄存器,引用方式:"0 (数字0)
  • 黑洞寄存器,引用方式:"_
  • 系统寄存器,引用方式:"+"*
  • 表达式寄存器,引用方式:"=,所有寄存器里最特殊的一个,用于计算表达式。
  • 其他,"% 当前文件名,包含文件路径。"/ 上次查找的内容。". 上次插入的内容。

3. 插件

VIM如果没有插件,完成度只有百分之50,结合各种插件,才能发挥全部的能力。篇幅有限,这里就不多介绍了。
常见比较好用的插件有ycmctagsnerdTree等。

争议终结

选择IDE还是VIM?

我个人觉得这种问题没有太大意思,考虑自己的开发环境来匹配最优解即可,现代IDE已经进化的很智能,和作为编辑器的VIM相比,不是一个维度的东西,是无法进行比较的。VIM的优势在于编辑的速度,思考、手、编辑指令之间高度同步,在你高度专注的时候,相比时不时的切换到鼠标上来进行选择和点击,你会更钟情于无鼠标办公,一秒钟的切换成本都是无法忍受的,体验过就理解这么说一点都不夸张。VIM在编辑这件事情上很纯粹。不过做项目不仅仅等于编辑代码,我们还有很多其他的工作,这是IDE擅长的领域。

而对于Linux重度使用者来说,VI/VIM通常是系统自带的编辑工具,这类人群使用VIM是刚需,即使现代IDE很多已支持远程编辑,但是如果能用VIM解决,何必再舍近求远、脱裤子放屁呢?

作为一个工具控,我现在觉得VIM很香。

发表评论