VIM之魅(上)

本月,著名的文本编辑器 Vim 迎来了它的 二十大寿 。 凑巧本人最近正在折腾Vim的配置和插件,心头正痒之时逢此佳际,便再也按捺不住写博的冲动。 其实,为Vim撰文的念头早已有之,只是于今为烈。

Vim的全称Vi IMproved(早期名为Vi IMitation),顾名思义是Unix上流行编辑器 Vi 的模仿和改进版。 毫不夸张地说,自从接触计算机以来,见识过无数的应用软件,深得吾心者唯Vim一款而已。 有时用到兴处,不免心生感慨:这才是软件中的极品呢,识之而不荐之简直就是一种罪过啊。 想起Vim还是慈善软件(careware或charityware),而自己从未给可怜的乌干达孩子们捐过一分钱, 更觉有些羞惭。为了心中的负疚感,我也早该为Vim写点什么了。

谈及Vim的优点,开源、免费、小巧、成熟、跨平台、文档丰富、社区活跃等等固是不假, 但相较其真正的妙处,以上皆不足道。 事实上,这些因素直接影响的主要是软件的使用成本,而非使用价值。 真正卓越的软件,会让深谙其道的用户不惜代价地拥有,因为它最终将带来远超成本的回报。 TextMate (恰好也是一种文本编辑器)便是一例, 虽收费不菲,且仅能运行于Mac, 但仍然吸引了大量的用户。 不少人甚至为了能用上它而专门购买Mac机,正如其开发者所号召的那样: Buy a Mac,get TextMate!

用户对Vim向来毁誉不一:初见者往往嫌其平凡甚或简陋,初试者往往觉其古怪难用, 而熟用者则食髓知味(词虽暧昧,却极准确)并奉为极致。 为何同一产品的评价如此两极分化?Vim究竟有何魅力值得大书特书? 下面就此谈谈个人的一些见解,并分享一些心得。不当之处敬请指正,不足之处欢迎补充。

 

关于Vim的误解

首先澄清一些对Vim的常见误解。

  1. Vim太古老,与现代编辑器相比早已过时

的确,计算机领域日新月异,一个年届二十的软件算得上是高龄者了。 何况Vim的大部分精华传承自Vi,而后者已三十有五,更是垂垂老矣。 然从另一个角度看,一个软件在漫长时间的洗礼和无数后辈的冲击之下能够屹立不倒, 不正彰显出它的伟大吗?更令人称奇的是:时至今日,Vi/Vim的许多理念不仅没有落后, 反依旧保持领先。关于这一点,容我稍后再述。 此外,Vim本身也在不断地发展,就在一年前还发布了最新稳定版(7.3)。

  1. Vim是程序员(或geek)的玩意,一般人用不上

虽然Vim在程序员手中更能发挥威力,但编程绝非其唯一的用武之地。 除了IT人士,学生、教师、科研工作者、记者、文字工作者等等,凡常需文字编辑者均可考虑使用。

  1. Vim难学又难用,犯不着为区区一个编辑器而为难自己

相比一般的编辑器,Vim的学习曲线无疑陡峭得多,其用法更是异乎寻常。 但从长远来看,对于一个频繁处理文字的人来说,这点投资绝对是值得的。 “磨刀不误砍柴工”的道理谁都明白,可生活中愿意磨刀的人还真不多。 一个常见的例子是,许多经常打字的人宁肯用“二指禅”,也不愿练习盲打。 放着一本万利的事不做,偏去干无本微利的活,与其说是惰性太大,不如说是理性太少。 再说,Vim虽然命令丰富、功能强大,却并不因此而显得复杂(这当然得益于精巧和谐的设计)。 根据本人经验,十分钟便能入门,一周内即可基本熟练。 此时虽距精通尚远,但效率已远超一般编辑器了。 总的说来, 学用Vim最大的障碍并不在于其本身,而在于固有观念和习惯对人的束缚 。

  1. Vim只能用于编辑纯文本格式的文件,适用范围太窄

首先为纯文本格式正名。不得不说,人们实在太过倚重二进制格式了。 就拿最常用的Word来说,用户不妨自问一下: 有多少次是习惯性地打开Word编辑文档而实际上只用到了记事本(Notepad)的功能? 又有多少次只用到了写字板(WordPad)的功能? 即便用到了Word的某些高级功能,是否又为各种排版问题而大费周章? 第一种情况说明纯文本格式足矣,后两种情况可考虑用 标记语言 ( Markup Language )代替。 所谓标记语言,即是在文本中规定一些特殊的语法标记,从而将普通文本结构化。 最常见的标记语言是广泛用于互联网的HTML和XML(Word 2003也开始支持XML)。 此外,广泛运用于学术报告和科技论文的 LaTeX 也是一种标记语言,在处理排版、图表、文献等方面远胜Word,当然学习门槛也远比后者为高。 近年来, Textile 、 MarkDown 、 reStructuredText 等 轻量级标记语言 ( Lightweight Markup Language ) 开始流行。比起XML,它们更简洁、更直观,因而也更方便用纯文本编辑器生成。 本网站的以前博文是由基于XML的 DocBook 生成的, 从本文开始则采用reStructuredText。 之所以不用Word, 是因为它价格不菲(盗版也要花良心、安全、时间等成本)、 平台单一(仅运行于Windows)、格式封闭、体积较大、速度较慢、 不够安全(可能中毒)、欠缺稳定(有时崩溃)、难以用Vim编写(二进制格式)等等。 此外,Word的一大优点是“ 所见即所得 ”(WYSIWYG),但相应的缺点是“ 所得仅所见 ”。 由于内容与形式混成一体,既不利于维护,也不利于扩展。 作为对比,DocBook、LaTeX、reStructuredText等标记文本将内容与形式分离, 同一内容不仅可生成多种文件格式(如HTML、XML、PDF、ODF、RTF等),还能生成不同的样式风格; 反过来,同一样式可应用于不同的内容(Word也有模版,但弗如远甚)。

不仅类似Word的字处理器可以采用文本格式替代,类似Excel的电子表格同样如此。 (注:按说应用软件与文件格式本不应混为一谈,但由于二者关系紧密,为行文简洁本文暂不区分) 用XML结合XSLT技术,或者用CSV结合Vim插件,不仅可制作表格,还能统计数据。 如果需要轻量级数据库,不一定要用Access、SQLite或者MySQL,XML或 YAML 也许已经足够。 图形文件也不是非二进制格式不可的,不妨考虑 SVG 矢量图 或者 DOT语言 , 还可试试有趣的 ASCII Art 。 甚至声音文件也有文本形式的 ABC记谱法 。

相比二进制格式,文本格式的好处有很多:格式公开透明,适用各种平台和工具; 方便人工编辑、查看和搜索;利于脚本处理和版本控制; 不会因部分数据毁损而出现打不开文件的情形,等等。 这当然不是在劝说大家放弃使用以二进制文件为基础的应用软件, 毕竟后者更加易学、易用,界面也更美观,功能通常也更完备, 而是旨在说明:文本格式绝不是低级、原始或狭窄的代名词。 无论是私人的记事本、邮件、日记,还是网络的博客、论坛、维基, 或者报刊文章、论文书籍,文本格式皆可充任主力军。

醉翁之意不在酒,以上列举了纯文本的诸般优点,自然是为了给Vim更多一展身手的机会。 不过Vim对非文本文件也不是完全束手无策的。 例如,它能直接编辑zip、gzip、tar、bzip2等格式的压缩文件。 以前我一直用 KeePass 统一管理密码, 但总觉有些不便,在得知最新Vim已支持在线编辑加密文件(Blowfish算法)后, 开始有了改用Vim的打算。其实何止是压缩和加密文件,理论上对于一切已知算法的文件, Vim皆可在打开、编辑、保存之后保持原有的二进制格式。

 

Vim的理念

冗长的铺垫之后,终于迎来了本文的正题:Vim到底好在哪里? 这个问题的答案既是一言难尽,也可一字道尽,那就是——  。 手指随心而蹈之时,如奔雷闪电,快得无与伦比,快到不可理喻。 Vim何以如此之快?以在下之见,诀窍在于它秉承的理念: 减少使用鼠标、减少敲击键盘、减少手指移动、减少目光移动。

 

1. 减少使用鼠标

不可否认,鼠标是一项伟大的发明,直观、灵活、简便、易用。 但如同对二进制格式一样,人们对鼠标(或其他定点设备)也是过度依赖了。 大多时候,鼠标的方便是以降低效率为代价的。 在Windows下,一个常见的使用场景是:鼠标点击“开始”菜单,滑动 到某个应用后点开应用程序,在程序中继续使用鼠标操作各种菜单或工具栏。 很少人会这么做:通过键盘(Win+R)打开运行对话框,然后键入命令从而启动程序。 更少人愿意花功夫为常用的程序绑定自设的快捷键,并学习和使用程序自带的快捷键功能。 究竟有多少人不会使用除Ctrl-C(复制)和Ctrl-V(粘贴)以外的热键不得而知, 不过前不久Google的一位专家有一个惊人的发现, 九成美国互联网用户不知Ctrl-F有何功用 。

常识告诉我们,在使用电脑时,只有在眼、手、心三者合一的情况下才能达到最高效率, 而在频繁使用鼠标的过程中,用户的眼光在菜单、工具栏或按钮与程序主版之间来回地切换, 手指在键盘和鼠标之间不断地移动,注意力不时被分散,效率因此大打折扣。 在文本编辑中,鼠标的弊端愈加明显。以一个简单情形为例: 光标在某行的中间,用户希望把该行与下行对调。若用鼠标,则须先将其移至行头, 选定整行,然后拖放到下一行(碰上Notepad这类不支持拖放的编辑器就更费事了)。 鼠标稍有不灵,或眼神不济,或手指不稳,都可能导致操作失误。费眼、费手、费时、费神。 换成Vim用户,在正常模式下闭目输入 ddp 三字符即可,此时前者恐怕才刚刚摸到鼠标呢。 如果把任务换成:将当前行移至最末行,请非Vim用户再用鼠标拖放试试? 他只能祈祷最末行不要距离太远,尤其不要在滚动窗口之外。 Vim用户遇此则毫无难色,一套连环四击( ddGp )便完事大吉。

Vim注重键盘的基因来自Vi,作为Unix下的一个典型应用,后者完全不支持鼠标。 这可以看成一种历史局限,但也正是这种局限迫使设计者把键盘利用到极致。 请看下图——

/upimg/allimg/111130/2355001C4-0.gif

图中的键盘(包括上下)总共95种按键,仅1种(“”键)未被征用,利用率高达99%。 即便如此,也远未穷尽Vim的命令。 另一参考图–在我的相册中。 更详尽些,依然只是冰山一角。

 

2. 减少敲击键盘

在Word下,前述交换两行文字的任务也可不用鼠标完成:先按Home键,再依次按Shift键、 End键、Ctrl-X、下方向键、Ctrl-V。只是共计八键,比Vim多了一倍有余。 论起精减Vim(Vi)键击次数的功臣,当首推其独树一帜的 多模式(multi-mode) 特征。 据我所知,编辑器中除号称Windows下TextMate的 E Text Editor 支持multi-edit模式外, 其他皆无明确的模式概念。 关于模式,常有两种误解。 一是以为Vim只有两种或三种模式,而实际上它有六种基本模式和六种衍生模式。 二是以为其他编辑器是单模式。其实,任何编辑器至少有两种模式:一种是 插入模式,一种是命令模式。 每当用户按住如Ctrl、Alt、Fn、Win、Command等修饰键(modifier key)时, 实际是进入了命令模式,一旦松开修饰键,便回到插入模式。由于此过程转瞬即逝, 用户往往并无模式的观念,故有人称之为 准模式(quasimode) 。 Vim也有准模式,只是并非主流。 因此, Vim与非Vi类编辑器之间的区别不在于有无模式,而在于模式能否持续 。 模式不能持续带来的一个问题是,一旦需要对文本进行连续调整时,会频繁求助修饰键 (用鼠标只会更慢)。Vim则不然,一旦通过Esc键切换到命令模式后便一直保持, 直到用户主动推出。其间所有命令不再需要多余的修饰键,自然节省了键击次数。 这颇为类似Caps Lock键的功用,即一旦开启便转为大写字母,不再需要Shift键的修饰。

修饰键的另一局限是,每键只能修饰一个普通键,这为命令的设计和使用带来了困难。 与Vim齐名的编辑器Emacs同样以功能强大、命令繁多而闻名,但由于没有显式模式, 键盘上的普通字符根本不够用,只好经常采用多个修饰键组合的命令,以致于有人戏称Emacs是 ”E sc- M eta- A lt- C trl- S hift”的缩写。 模式让Vim摆脱了修饰键的羁绊,大大扩展了命令的设计空间, 这也是Vim的命令虽多却简洁易记的根本原因。

模式是Vim初学者碰到的最早也是最大的障碍,一次次的哔哔声更令人或茫然、或沮丧。 很多人因此知难而退,殊不知翻过此山后,前面将是一马平川,任君驰骋 (参见趣味的 学习曲线图 )。 一切特别的别扭之后通常都隐藏着某种特别的自然,要克服模式的障碍,除了勤加练习外, 更重要的是理解其设计理念。模式的奥妙不用外寻,尽在其名之中。此话何解? 前面提到命令模式,那是为了方便Vim与其他编辑器对比,其实Vim相应的术语是 普通模式(normal mode)。“普通”二字可不普通,这意味着对编辑器的彻底颠覆——

在一般编辑器中,插入模式是“普通”的,命令模式是“特殊”的;在Vi类编辑器中,命令模式是“普通”的,插入模式是“特殊”的。

这启示我们,使用Vi类编辑器的一个诀窍是: 让普通模式成为常态,让插入模式成为暂态 。 具体地说,打开Vim便默认进入普通模式,需要添加文字时才切换到插入模式, 一旦完成立刻返回普通模式。这就避免了用户时常错判当前模式的问题—— 当他在把脑中的思想转化为文字时,应当是插入模式; 当他正在酝酿思考、修改文字或跳转页面时,应当是普通模式。 养成习惯后自然成为下意识,不必从光标、状态栏或哔哔声来判断当前模式, 这才是更高效的用法。

进一步考察Vi的模式哲学,会发现它具有天然的合理性。除了打字员,一般人 在编辑文档时大部分时间都是用于思考、修改、浏览的,只有少部分时间在 输入全新的内容。这点对程序员而言尤其正确,设计代码、修改代码、 浏览代码的时间总是大大多于编写代码的时间。 对文字创作者而言同样成立,世上有多少人能做到文思泉涌、下笔千言、 倚马可待且一字不易呢?再天才的作家不也讲究反复推敲吗? 对那些文字“借鉴”者来说就更重要了, Ctrl-C Ctrl-V 之后, 剩下的不都是些拼拼凑凑、改头换面的活儿吗?

光有模式哲学是不够的,还得靠强大的命令体系支撑。如果在普通模式下 不能高效地完成各种任务,那么让其成为常态也是没多大意义的。 好在Vim的命令丰富而不失简洁、强大而不失灵活,常人凡能想到的编辑浏览动作, Vim都有相应的命令,并且通常不止一种。

除模式之外,避免重复动作是Vim节省按键次数的另一“法宝”。 最基本的拷贝粘贴自不必说,Vim还能自动将一些改动的文字保存在寄存器 (register,相当于剪贴板)中,以供日后粘贴之用, 更可让用户将复制内容放入指定的寄存器中。

在进行文字搜索时, ; 可重复上次行内搜索, , 可反向重复上次行内搜索, n 可重复上次全局搜索, N 可反向重复上次全局搜索。 使用可视化模式(visual mode)时, gv 可恢复上次进入该模式时选定的区域。

还有更多:键入 . (小数点),便能重复上次在普通模式下的编辑命令,何其方便; 键入 @: , 便能重复上次在命令行模式(command line mode)下的编辑命令,何其自然 ( 注:Vim中 @ 代表回放, : 是命令行模式的切换键); 用 q 命令启动宏(macro),更能录制一系列按键动作,可随时无限次重放,何其强大。

Vim不仅能帮用户重复一次操作,还可重复多次。 在普通模式下,数字前缀可指定命令的重复次数。 如 dd 代表删除1行文字, 10dd 则将删除10行。 在命令行模式下,可对指定范围和匹配模式的行进行统一处理。 如 20,100g/the/d 表示删除第20行到第100行之间包含 the 字串的所有行。 在可视化模式下,也能对所选区域进行统一操作。 如 Vr* 将当前行的所有字符全部变成星号。

若对Vim进行适当配置,节约键击的方式更是五花八门。 比如,按Tab键便能在插入模式、命令行模式下自动完成单词, 参考的范围有当前打开的所有文件、指定的字库、程序的关键词、函数库、文件的路径等等。 利用 map 功能可以建立各种模式下的键盘映射,定义自认为更合理、更简洁的命令和缩写。 如果经常把 the 写成 teh , 可设置 abbreviate 进行自动纠正。 如此等等,不胜枚举。

狂热的Vimer都以少敲按键为荣,正如 vimgolf.com 上所说:Real Vim ninjas count every keystroke(真正的Vim忍者会数每个按键)。 普通用户倒也不必如此,不过一定要明白一件事:当你经常重复某些编辑动作的时候, 很可能一个的美妙命令正擦肩而过。假如当真无此命令,Vim也授予了你自创的权力。 每当我在Vim下的指法开始凌乱,甚至忍不住去碰鼠标的时候, 或者频繁在插入模式下修改内容的时候,总会感到Vim之神在一旁坏笑: shame on you!(译成时兴的中文网语是:你弱爆了!)

 

3. 减少手指移动

Vim不仅提倡少用鼠标、少敲键盘,还提倡少动手指。 显而易见,在按键次数相同的情况下,手指的移动距离越小,效率自然越高。

模式的存在使得Vim的命令不太依赖修饰键,多由字母键组成。 用户的手指无疑更青睐后者,不仅更熟悉,移动距离和扭动角度也更小。 反观Emacs,用户频繁用小指按修饰键,会产生所谓的 Emacs小指问题 , 以致于有人恨不能用脚踏板来代替修饰键(别说, 还真有 ),以解救受苦受难的小指。

除模式之外,最令Vim初学者感到不习惯的恐怕要数方向键的用法了。 在Vim的正常模式下,一般不用方向键来移动光标,取而代之的是 H(左)、J(下)、K(上)、L(右)键。 事出有因,Bill Joy当年开发Vi时所用的ADM3A键盘 ( 见图 ) 没有专门的方向键,而与H、J、K、L诸键合一。 这似乎又是历史局限带来的福利,事实证明这是Vi类编辑器高效的又一大要素。 由于四键分布在右手主键(即J键)附近,远比按方向键方便。考虑到方向键的使用频率, 如此设计大大减少了手指的移动距离。Vi这一标志性的风格,也为一些应用软件 (如mutt、Nethack)和一些网站(如Gmail、Greader)所借鉴。

Vim初学者另一个抱怨是,用来切换到普通模式的Esc键地处偏远,与Emacs用户同病相怜。 这似乎有违前面所说的原则。不过如果仔细看看ADM3A键盘就能理解了:上面 的Esc键在现代键盘的Tab键处。解决的办法有很多,我的做法是修改系统设置, 将Esc键与Caps Lock键对换(后者于我全无用处,还占到风水宝地)。

Vim有不少叠字母命令,如 yy 、 dd 、 gg 、 zz 、 ZZ 、 << 、 >> 、 、 ” 、 [[ 、 ]] 、 @@ 等等。 很明显,同样键入两个字母,当二者相同时手指的移动距离最小,也最省心。

 

4. 减少目光移动

要提高编辑效率,不仅要经济用手,还要经济用眼。 目光频繁地搜寻或切换不仅本身消耗时间,更对思路的连贯性造成干扰,导致工作效率降低。 Vim针对用户频繁的编辑或浏览的需求,提供了周到的服务,能最大限度地 减少目光搜寻时间和目光转移次数。

同样由于历史原因,Vi当初是用于终端执行的程序,没有多窗口,虽可用 Ctrl-Z 或 命令 :stop 切换到其他程序,但终究不便。因此,设计者千方百计地减少用户 离开当前窗口的机会,从而减少用户的目光和注意力的转移。

避免离开编辑窗口最自然的一个方法是,在编辑环境下完成尽可能多的任务。 例如,为了减少到终端的切换,Vim除了能编辑本地文件外,还能通过FTP、RCP、SCP、HTTP 等协议直接编辑远程文件。 又如,Vim本身的命令虽然不少,但主要是编辑方面的功能。 为弥补这一不足,Vim提供了外部命令的接口,如可通过设置 makeprg 变量 来指定make程序,设置 grepprg 变量来指定grep程序,设置 helpprg 变量 来指定帮助程序。Vim更能直接执行shell命令,必要时还可读取外部命令的输出结果。 如果安装 Conque Shell 插件,甚至可以在Vim中直接运行(模拟)终端本身。

顺带提一下,虽然有人认为Vim算不得真正意义上的IDE(集成开发环境),在这方面不如 Emacs那般强大,但开发人员所需要的多文件浏览、全局搜索、代码大纲(outline)、 语法高亮、自动补全(autocomplete)、代码片段(snippet)、自动格式化、语法检验、 文本比较、编译、运行、调试、单元测试、与SCM等工具集成等功能,在Vim内部均可完成。 考虑到它无敌的编辑效率、灵活的配置、强大的脚本支持 (包括原生的Vimscript以及外来的Perl、Python、Ruby等)以及相比 一般IDE在启动速度、内存占用等方面的优势,完全称得上是开发神器。

不少人对Vim朴素得近乎寒碜的界面耿耿于心,殊不知那些花哨的界面、时髦的效果 都是吸引目光、分散注意力的元凶。在我的个人配置中,Vim是全屏显示的,且既无 菜单,也无工具条,更无按钮,连滚动条都禁用,几乎称得上是零界面了。 窃以为这才是最好的界面,所有的服务都默默藏于幕后,不占用一寸屏幕资源, 不消耗一丝目光,却能在所需之时应键而出。在能自动识别人类意念的软件被发明之前, 实在很难找到比这更好的人机交互方式了。

为减少目光的移动,Vim在Vi之上新增了折叠(fold)功能,可把次要或暂不关心的文本 隐藏起来。根据实际需求,用户可选择具体的折叠方式,可手动折叠,也可按缩进、 语法、标记或比较(diff)来折叠,还可按自定义的表达式来折叠。

不少人都说Vim难学,但他们很可能忽略了一件事:Vim的在线帮助极为详尽且极为便利。 用户对于任何有疑问的命令或主题,键入 :h <关键词> 即可,其中关键词部分支持 通配符。如果连命令或主题都不清楚,可试试 :helpgrep 命令。假如连帮助本身 也不会用,那就敲 :help help 吧。 总之,用户完全不必在使用Vim时查找其他的参考书籍或电子文档, 他们的目光又少了一个离开的理由。