不管你们信不信,现在有很多人迷恋这个30多年历史的VI编辑器(最好的克隆和改进版本VIM也已经有15岁了).
他们不是守旧派,跟不上时代潮流——VI用户的社区正在不断增长着,我自己用VI已经2年了(在有了10年编程经验之后),我的很多朋友也都开始使用VI了,有趣的是,有很VI用户在VI出现前还没有出生。
当然,VI/VIM编辑模式比其它任何编辑嚣都出众肯定有原因的,你不必非得是Unix高手才能用它,相反,VIM可以免费在任何平台下使用,并且它也可以作为其它主流IDE的插件使用,现在让我来澄清几个误解,并用一些真实例子说明为什么它是极好的编辑器。
你第一次被VI/VIM难住,可能是对必须先用”i”才能开始编辑感觉震惊和厌恶,记不住使用”hjkl”来移动光标方向,并且需要按”a”才能在光标后面追加内容.因为你可能已经习惯使用其它编辑嚣,并且方向键在插入模式管用(90%情况下是这样的,如果系统配置正确的话),你可能除特别需要,保持在插入模式而不会返回到正常模式. 你可能会花20分钟在插入模式下,并且会抱怨:”我到底可怎么记住现在正在插入模式下还是正常模式下?”
很显然,这是一个完全错误的使用VI/VIM的方式,正确方式是,你不会在意模式,你会一直在正常模式下,只有当需要插入或修改字符时才会进入插入模式,编辑完成之后马上按<Esc>返回到正常模式.因此,如何记住当前模式问题并不存在.当你在编辑文字的时候,不要在插入模式去接听电话,而应该退出插入模式,接听电话,或者返回的时候按<Esc>进入正常模式.不要把插入模式当成一种状态.
让我来解释下这其中的哲学.
VI/VIM中的命令是可以组合使用的,比如”d”代表删除,”e”代表”移到单词末尾”,而”de”的功能就是删除从当前光标位置至单词结尾间的字符(有点像Ctrl-Shift-Right, Left, Del 快捷键在其它编辑器中实现的功能)
这样的好处之一是,”.”命令可以重复上次执行完成的组合命令(不包括移动命令), 执行完”dw”后,”.”会重复执行”dw”命令, 你可以移动光标,然后再按”.”会快速地删除当前光标处的下一个单词,这样让人感到难以置信的强大.
现在我们来看下插入模式. 一些命令(比如i,a,s等)可以让你进入插入模式键入文本直到按<Esc>, 说到这些命令, 整条命令也包括你在”i”命令和<Esc>之间键入的所有字符.
比如”iHello<Esc>”, 会在当前光标处插入”Hello”字符,而现在”.”命令可以在当前光标处重复插入”Hello”, 现在你应该能够明白强大之处了吧, 但还有更强大的, “A”会将光标移到当前行末尾并进入编辑模式, 因此, 当按<Esc>结束输入后,你可以按”.”在任何位置的行末插入相同的字符.
另外一个更加强大的例子是: “ce”命令, 由”c”和”e”组合而成,”c”(修改)命令会删除指定范围内的文本并进入插入模式,与”d”(删除)命令一样,但唯一不同的是它会进入插入模式而不是停留在正常模式. 这样的好处是你在这条命令之后所键入的文本同样也会作为这条命令的一部分. 因此如果你输入”ceHello<Esc>”, 将会替换当前光标位置到行末的内容为”Hello”, 而”.”命令同样也会重复这个运作.
动作(光标移动命令)也可以更加复杂, 有很多各种进入插入模式的命令(“o”会在当前行下插入新一行,”O”会在上面插入新一行,”S”会删除到行末的内容,等等…所有这些命令都会进入插入模式), 因此你可以想象,使用”.”可以创建重复执行多么强大的编辑命令.
让我们来一个示例. 比如你已经在你的头文件中声明了三个新函数, 然后你需要在模块里实现它们. 你复制下面文本内容到你的实现文件里:
编程差不多都这样开始,不是吗?
现在你必须删除这些分号,并且添加一个空的函数体. 在上图光标处,你可以输入”A”直接将光标移到行末并进入编辑模式:
按"A"之后,注意进入插入后光标的位置
现在你使用<backspace>键删除分号:
删除很简单
然后 键入<return>{<return>}<return>,添加函数体:
插入跟其它编辑嚣一样
最后,按下<Esc>返回到正常模式下:
现在我们返回到正常模式下
现在你得重复以上步骤修改另外两个函数。怎么做呢?很简, 首先按”j”移动下移一下光标,然后 点”.” 复制上一次执行的命令(”A”,删除分号,插入文本), 如果你按”j.j.”, 两次,你会得到如下结果:
j.j. 命令之后
VI的命令架构是关键,<backspace>和正常的输入都将作为命令的一部分, 并且命令是完全可以重复执行的。回想一下,日常编辑工作中有多少是重复的操作?
VI/VIM对正则表达式的支持很好,很多编辑器都支持查找、替换等操作可以使用正则表达式,但是只有VI(据我所知)可以更加高级地使用正则表达式,比如执行一次正则查找,然后替换”begin”第二次出现的行的包括”proc”的下一行,或者任何你能想到的复杂操作。
这不是贬低正则表达式,或者VI/VIM的正则表达式支持,VI的主要强大之处,当你习惯使用它之后依赖的强大之处 是它的基本编辑模式:
复杂表达式中的函数调用
如你所看到的,光标处是函数调用开始的位置,现在想象我们想要展开它并将它保存在一个内部变量中,首先要做的是选择这个调用函数,然后复制再将它移动到上面,输入变量名,然后再移动到上面输入函数声明。 在通过编辑模型中,你需要用Ctrl-Right 和左右键不断查找定位,在VIM里不需要这样。 “%” 会自动移动到相匹配的圆括号(或相似的分组字符), 但是如果你没有定位到这些特殊字符位置,它会一个字符一个字符地向右扫描,直到找到第一个,然后再去查找跟它匹配的字符。因此,在上面这种情况下,它会移动到右边的匹配圆括号。
我们知道”c”命令,可以删除字符(同样会把它复制到剪切版 译注:其它是VI里的BUFFER, 并不是系统剪切版,下同)并且进入插入模式,我们可以在上面这种情况下输入”c%”,然后我们将得到下面结果:
输入'c%' ("change match")之后
函数调用代码被放到了剪切版中了,然后我们现在可以输入变量名称了,输入两个字符不算太难,输入完变量名之后按<Esc>返回到正常模式,如下:
现在进入正常模式,你可以键入”O”在上面新建一行并进入插入模式,然后开始键入声明语句:
键入 "O" 之后,输入函数的声明 语句前半部分
现在,我们需要插入之前的函数表达式,由于它已经在剪切版里了,我们可以使用Ctrl-R,”在插入模式下插入粘贴(我承认它有点不好记,但它支持复合剪切版功能). 这将把我们之前声明的函数调用语句插入到当前位置”, 我们键入一个分号,然后 按<Esc> 返回到插入模式:
完成
好吧,我希望看过以上的解释和示例,你已经体会到VI/VIM的强大之处了。学习它是艰难的(如下),但如果你会看复一年地第天8小时甚至以上地编码,这将是继你学习打字之后的第二次最好的学习投入(你已经理解了,是吗?如果没有,不要怪VI,先学习它试试)。几个周的困难学习会让你一生受益,并且,至少不会有一个“哑巴助手” 把你烦得要死(译注: 记得微软office 97 的曲别针 吗?)
关键是,用VI时,你的键盘变成了一个有上百个按钮的超级文字输入专用手柄, 上面的每个键至少有两个功能, 上档和下档,因此你至少每次按键(不包括Shift键)可以实现200个功能。文字编辑命令非常强大,并且你甚至可以组合使用它们来得到最好的结果,当你输入一些字符时,它是普通的键盘,但当你回到正常模式下,它是一个文字录入设计最好的机器。
另一个简单例子, 这种只有VIM支持(使用了VIM的一个特别动作),假如你的光标在尖括号之间,就像在XML下经常遇到的:
Life at an XML tag...
怎样选择尖括号内的内容呢? 在其它编辑嚣中,你需要把手从现在舒适的位置移到到键盘的方向键区域,或者更糟糕,用鼠标, 无论怎样,这可能都是很痛苦的,尤其当使用笔记本电脑时。 但,在VIM里你怎么做呢?你只需要用”i”或”a”开头的文本对象动作命令, “i>”代表“当前尖括号内的区块”, 所以你可以用”di>”(“删除尖括号内的内容”)来删除上面情形下的尖括号内的全部内容:
你可以使用”(“或”)”代表当前括号的内容区块(或者”b”), “[" 或"]“,”{“或”}”, “w” 代表语法分隔的单词,或者”W”代表空格分隔的单词, 或者在它们前面加上前缀”i” 或”a”实现相应的插入或追加功能。
很多人对使用hjkl来代替方向键移动光标感到很诧异,原因可能是在当时出现VI的那个时代并没有方向键,而且当时的终端电脑的键盘上还特别为hjkl键加印上了方向提示。但这样设计带来的一个副作用就是移动光标方向的时候不必将双手移开主键盘区,这很不错。
(译注: 当Bill Joy编写VI的时候,用的是这台电脑,由于时代久远,当时这台电脑只有一个主键盘区(如图),并且它的hjkl键上还印有方向)
但无论如何,即使你最初使用hjkl, 一旦你完全掌握了VI/VIM之后,你可能根本不会再用”h”和”l”(左和右),很少使用”j”和”k”。 为什么呢? 因为有其它更强大的移动命令可以让你更快地将光标移动到你想到达的位置。 当在一行内移动时,我发现总会有一个移动命令可以将光标直接定位到我想要的地方,所以我会有那些移动命令:”f”后接着任何其它字符 会 定位到字符下次出现的位置,”%”用来匹配任何你想去的地方的模式,等等.. . 当在文件中导航时,有命令可以直接定位到屏幕的 顶部/中间/底部 的位置,”/“ 可以非常容易地输入想要查找的字符串,”]]” 可以在函数间导航 ,等等。
ADM3A的hjkl键
有些命令非常有用一旦你学会使用定会爱不释手,”H“,”M“,和”L”可以将光标直接定位到屏幕顶部、中间和底部。”zt”,”zz”和 “zb”会将光标保持在当前位置不变,滚动视图将它移动到屏幕顶部、中间或底部。“×” 会查找当前光标所在的单词的下一个出现位置(“#”向后查找,在键盘上的对称位置所以很好记),而且还有更多这样的命令。。。
这些都是比较夸张的说法,但这经常被提出来反对编辑过程中获得的对提高开发生产效率很重要的好处。我打赌这是错误的。
首先,有时候我的确必须要思考一个问题,而不需要去看代码,我骑上我的自行车出去骝了一小时,或两小时,如果天气好的话,这比呆在电脑前思考好多了。
或者,当我必须要分析一些困难的问题或设计一套方案时,我经常拿出一本笔记本(真的纸做的笔记本),一支笔,然后用它们来梳理我的思路。
我们可以打赌,除非一些特别情况,生产工作不得不在电脑前做。这是因为,大多数时候,你必须看着代码来思考或设计,而这包括在编辑器里浏览代码,而且,通常你的确正在继续键入或编辑。你可能刚思考了一分钟,然后 你花了另一分钟来编辑实现你刚刚所想到的,而当你编辑的时候,你想要一个最好的工具来工作。
舒服的编辑让你保持在那个“思考的领域”, 这个集中精神的状态让你有最大的生产效率,因为你掌握了一个功能强大的工具像一款文本编辑器, 而它其实从你的意识中消失了,你可以自由地集中精神于解决问题,你会下意识地去编辑实现你的想法。 通常的编辑方法是你查找定位,用Ctrl-Right, Ctrl-Right, Ctrl-Right, Ctrl-Right, Ctrl-Right 定位到你到的地方,然后你要将你的手移到鼠标上,打开菜单,选择一个选项,进入一连串的对话框然后点击“OK” 确认应用。 而在VI/VIM中,你所要做的只是简单按几个键,简单明了。
其它一些VI用也跟我分享了这些,所以我知道并不只我一个人有这种感受: 一旦你掌握了vi, 经常会有这种感觉,在30秒钟编辑之后,你脑中会响起一种持续敲击键盘声音的记忆, 当你在文本的各行、区块中穿梭,移动和编辑时,感觉就像这声音在你脑中响起,而这时候,你会有一种强大力量的感觉。
VI和VIM能够理解你的代码结构,这可以从许多命令中体现出来。像 在上面示例#3中提到的”aB”:选择当前”{“和”}”以及它所包含的内容(”a}”同样). 下面让我们把它与”>”操作符相结合,”<”是用来缩进一块区域的很有用的命令。代码如下图:
不恰当的缩进
你多长时间会碰到这种情况?是的,你可以粘贴自动再次缩进(在VIM只需要”]p”),但通常情况下你会忘记,或者你不是因为粘贴这段代码而导致的这种情况,而是因为你添加或删除而导致的。你只需要再缩进一下即可。在其它编辑嚣里,你要移动光标,选择,然后再按TAB键。而在VIM里不需要这样麻烦,只需要键入三个键:”>aB”(“缩进一个区块”):
我们甚至没有移动光标
很酷是吧?你没有移动光标或选择,你只是直接告诉VI我想怎样做,然后VI就这样做了。我相信正是这种“直接”编辑方式让你感觉到了力量并且让你进入并保持在你的状态中。
VI已经存在30多年了,而它现在戛然存在着。VIM,一个引进甚至比VI更多特性的VI的完全克隆,已经存在了15年了,可以在世界上差不多任何一个平台下运行。喜欢VI的人们已经找到一个在任何地方使用它的办法:在Eclipse里有VI的模拟插件,在许多Mac OS X apps 有VI的模拟插件,在IntelliJ IDEA里有VI的模拟插件,这些甚至Emacs都没有一个,而却有一款Emacs 的 VI模拟插件several, Viper, 我开发并且出售ViEmu,一个家庭插件套装,使VI可以在Visual Studio, SQL Server, Word 和Outlook中运行, Paul Graham 仍然用它来编写list和arc, Tim O’Reilly 也公开承认它是Vi用户,SlickEdit和Crisp也有VI模拟器…
当然,VI/VIM的社区并不是很多:许多计算机用户甚至不会熟练打字,并且VI的学习曲线又很陡峭,那些见过轻巧、简陋的编辑系统的人,因此VI/VIM编辑器肯定会继续存在很多年。实际上,用VI/VIM的键绑定功能可以让你更习惯使用VI并且在未来任何环境下都可用, 从旧的Unix操作系统到最新的流行IDE。
作为最后一个示例,即使看起来VI是关于一些神秘难以理解、让人看不懂的命令,但现在我们将会看到它的一些更加可视化的方面(事实上,它们是VIM的特性,而不是原始的VI). 其中之一:当”hlsearch”配置打开时(在VIM中默认是关闭的,但是可以使用”:set hlsearch”打开), 当你搜索一个字符时,所有匹配的结果在屏幕中都会高亮显示。假设你有以下html代码:
HTML代码
如果你按”*”,会查找当前光标下的单词(”div”),结果会是这样子:
强大的星号
正如你所看到的,光标移动了,而且不同地方的结果都被高亮了。
还有更多,我们知道像”d”和”c”这样的操作符会根据下一条命令执行,好的,如果我们想要可视化反馈,我们可以使用可视化模式:按”v”, 移动光标时你会看到从初始位置的区域到光标处会被高亮,然后接着按下操作符可以直接看到效果。搜索命令在这里同样适用。 如果你用”V”替代“v”, 会以行为单位高亮。 现在我们按下 “V”,然后 “k”(上):
按下 Vk之后
如你所见,这两行被高亮以示选中。假如我们想要选择直到div的闭合标签(如高亮显示),输入”N”(上个匹配结果):
按"N"之后
现在我们可以做任何我们想做的了,假如”gU”操作会让所有字符变为大写(然后返回到正常模式下):
华丽的大写
好吧,现在让我们来为VI/VIM的理解做下正确的解释:
有一件事是大家所一致认同的,并且也是正确的,这张图准确地说明了这一点:
事实是,学习VI/VIM是非常费时(几周到几月),并且第一次尝试是很不愉快的。我把这一点当作是为什么VI/VIM不是,并且将不可能是流行的编辑器的主要原因。相比其它编辑器,你需要付出相当多的努力去学习、记忆,然后将30条或更多的命令运用娴熟才会让你使用VI/VIM更有效率。由于这些命令都是些粗略的一键命令(纵使它们都有一些助记方法,甚至有些形式是用起来是一致的),这仍然不是一项简单的任务,简单的是认输并且返回使用熟悉的jedit或pico, UltraEdit或TextMate, 或者甚至emacs, 但是一旦你努力学习了,我知道没有人会想要再返回用那些编辑器,并且我知道有很多人说他们已经用VI超过了10年,并且他们已经习惯,并且在期待即使是最小的细节改进。
随便你想用还是不用,如果你觉得学习使用VI/VIM会白费力气,那就去学习Emacs, 或者继续用你的差劲的IDE。 无论如何,在任何情况下,不要再说”用VI的人都是些死脑筋“,我希望我已经成功地向你展示了为什么他们(我们)坚持使用VI/VIM, 并且你至少应该能够理解它的强大,即使你仍然偏向不使用它。
如果你想研究VI/VIM编辑器的更多功能,这里有一些有用的资料:
(特别感谢 Ivan Vecerina, Andrey Butov, Jose Gonzalvo, Mark Petrik Sosa, Aitor Garay and Woody Thrower 对这篇文章的草稿的评论)
(所有的截图是从 Visual Studio with ViEmu, 我的商业版VI插件, 以及 codekana, 我的下一个产品,提供更加强大的语法高亮功能)