如果你要花大量的时间键入文本, 写程序或编写HTML脚本, 你可以通过有效地使用一个好的编辑器来替你节省时间. 本文将引导你如果快速地完成你的编辑工作, 并且减少你的错误.
本文将以开放源码软件Vim(Vi IMproved)为例向你展示如何进行有效的编辑, 但这里提到的原则对其它的编辑器也是一样, 选择合适的编辑器是进行高效的编辑的第一步, 关于哪个编辑器最好的争论已经数不胜数, 本文不打算对此再说些什么. 如果你还不知道用什么编辑器或者觉得你现在使用的编辑差强人意 , 试一下Vim, 保你满意.
第一部分: 编辑一个文件
1. 快速移动
文本编辑的多数时间都花费在浏览, 检查错误或者找出你要进行编辑工作的正确位置, 输入新的内容或改变已有的内容倒在其次. 在文本中随意漫游是非常常见的操作. 所以高效编辑的第一要义是学习如何能够在文本中快速移动, 准确定位.
通常情况下, 你知道要查找的内容, 或者查看所有的文本行只是为了找出某个单词或者短语. 你可以使用查找命令"/pattern"查找文本, 但有几点要注意的:
- 如果你已经找到了一个单词并且想找出这个单词还在其它哪些地方出现, 可以使用"*"命令, 它查找下一个匹配的目标.
- 如果你设置了'incsearch'选项, Vim将会以反白显示出第一个被找出的匹配. 这能在你还在/命令下敲入关键字时就快速地显示出来(类似于emacs的递增查找功能)
- 如果你设置了'hlsearch'选项, Vim将会高亮显示所有查找到的匹配, 这种策略可以让你对要查找的内容有一个概括的了解, 如果你在程序代码中使用这一功能, 它能显示出所有引用某个变量的地方. 你不需要移动光标就可以看到所有符合条件的匹配(同一屏幕上可以看到不至一个地方被匹配).
在一些结构规范的文本中还有其它一些更方便的小技巧进行快速移动, Vim内嵌了方便C程序(以及与C语言很相象的C++和Java)的命令
- 使用"%"命令可以从一个打开的括号跳转到与它成对匹配的另一个括号处, 还可以从一个预处理指令"#if"跳转到与之匹对的"#endif". 其实"%"命令能跳转到好几种文本元素的'另一半'去. 这对检查你的() 和 {}是否正确匹对非常方便.
- 使用"[{"跳转到当前代码块的开头(代码块是用"{}"括起来的程序段).
- 使用"gd"可以跳转到当前光标所在的单词(变量)的局部定义处. 当然, 还有很多其它的技巧. 关键是你要知道有这样的命令. 你也许会说你不可能学习所有的命令. -- 共有几百个不同的移动命令, 一些很简单, 还有一些是智能化的 -- 不过它可能要花费你数周的时间学习使用它们. 当然, 你不必全部掌握, 只要有你自己的一套办法, 并且能处理你所要进行的操作.
有三个步骤可以使你学到你需要的技巧.
- 当你编辑文件的时侯, 留意一下你经常要重复进行的操作是什么. 或者你花大部分时间都在干些什么.
- 想一想有没有一个编辑命令可以替你做最让你头痛的事. 读在线文档, 问一个朋友, 或者看一下别人是怎么做的.
- 练习使用这些命令, 直到你的手指可以不加思索地运用自如
举个例子来说明到底怎样做:
- 你在写C程序的时侯, 你经常要花时间找到一个函数的定义. 现在你使用的是 "*"命令查找这个函数名都在哪些地方出现过, 但在你到达真正的目标之前, 可能还有符合你的查找条件的很多个匹配(如注释中出现的或该函数在其它地方被调用) 骚扰你. 你可能会想一定有一种捷径可以一步到位.
- 浏览一下参考手册你就会发现有个地方提到tag. 文档指出如何使用这一功能跳转到函数的定义处. 这正是你要的东东!
- 你已经知道如何生成一个tags文件(ctags *.[ch]或etags *.[ch]), 使用ctags 程序就可生成Vim所要的tags文件. 接下来你练习使用CTRL-]命令. 为了更方便地使用这一功能, 你还可以往你的makefile文件里加入自动生成tags 文件的命令.
当你使用这面的三个原则时要当心:
- "我想使用这些命令, 但我没时间去看文档中的一些新命令". 如果你还这样想, 那么你可能还处于计算机的石器时代(就是说你比较菜啦). 有些人做什么都用notepad, 他们可能觉得别人用更短的时间完成相同的工作是不可思议的事.
- 不要重复做相同的事. 如果你经常要去找一个你常用的命令, 你就没时间专注于你手头上的事的. 只要找到耗费你太多时间的操作, 练习使用这些操作对应的快捷命令, 直到你可以不加思索地使用它们. 这样你才可能把精力集中在你要编辑的文本上面.
下面是一些多数人都会遇到的常见问题的解决方案的建议. 你可以以此为例, 学习使用上面的三个原则.
2. 不要两次键入同样的东西
我们键入的文本都是一个有限的集合. 甚至使用了有限的短语和句子. 尤其是计算机程序. 显然, 你不必两次键入这些相同的东西.
最常见的事是你要把一个词改为另一个, 如果你要将整个文件里所有地方出现的这个词都换为另一个, 你可以考虑使用":s"命令, 如果你要有选择地进行更改, 而且最好在看了上下文之后再决定, 你可以使用 "*" 命令查找这个词的另一个匹配, 如果你决定要改, 那么使用"cw"使用改变这些词, 然后再用"n"命令到下一个匹配处使用"."重复上一个命令. "."命令重复上一次改变. 一个改变, 是指插入或删除或替换一些文本. 可以对这些操作进行重复是一种功能强大的机制. 如果你用它来组织你的编辑操作, 很多以往必需手工做的修改就只需要简单地使用"."命令. 要特别注意在重复上一次修改操作之前你有没有做其它事, 夹在中间的有些操作可能会改变"."命令实际重复的内容. 使用"m"命令标注文本的一个位置地很有用. 它可以让你在作了重复的修改之后回到你上次停留的地方.
一些函数名和变量名很难正确地键入, 比如"XpmCreatePixmapFromData", 没有一个样本看着或不看它的帮助是很难的(至少是很烦的). Vim有一个补全机制可以让这种事变成小菜一碟. 它会在文件里查找你要键入的文本, 找到相近的匹配就直接插入, 而且, 它还在你的include文件里递归查找. 你可以键入"XpmCr", 接着按下CTRL-N键, Vim会把它扩充为"XpmCreatePixmapFromData", 这样的功能还来的不光是为你节省了时间, 它还减少了你手工键入时出错的机会, 而且, 你的编译器也不会产生那么的警告错误了.
如果你要重复键入一个短语或一个句子, 也有一种快捷的方法. Vim有一种记录宏的机制. 你键入"qa"开始把一段宏记录入寄存器变量'a'中. 按下来你可以象平常一样键入你要的操作, 只是这些操作都会被Vim记录进它命名为'a'的宏中 , 再次再下"q"键, 就结束了宏'a'的录制. 当你要重复执行你刚才记录的那些操作时只要使用"@a"命令. 共有26个可用的寄存器供你记录宏.
使用宏你可以重复多个不同的操作. 而不仅仅是插入文本了. 如果你要进行某种重复的操作, 记着要用这一招呀.
使用宏要注意宏只是机械地重复你刚才键入的动作, 当你在文件里移动时要小心. 你用宏重复时和你当初录制时要操作的文本对象可能不一样. 你录制宏时向右移 4个字符可能对它当前的环境来说是正常工作. 但当你回放这些宏时, 它工作的文本环境可能需要移动5个字符.
当你要录制的操作比较复杂时, 要想一次就全部通过也不是一件容易的事, 此时你可以写一段宏或脚本. 这对于使你的程序模板化非常有用. 比如, 一个函数头 , 你可以把这项功能定制得如你所愿的智能化.
3. 错误修复
打字时出现错误是在所难免的事, 办法只有一个, 就是尽快纠正它. 编辑器可以帮你自动做这一工作. 但是你要事先告诉它怎么才算错, 正确的又是什么.
对常人来说, 常犯的错误都是同一个错误. 你的手指就是不听使唤. 这可以通过缩写功能来纠正. 一些例子是:
:abbr Lnuix Linux
:abbr accross across
:abbr hte the 你一键入完错误的词编辑器就会用正确的词来替代它.
同样的机制也可被用来以少数几个字符代替键入一个长的词. 特别是一些你很难正确拼写出来的词. 这样也避免了你犯错误的机会. 例:
:abbr pn pinguin
:abbr MS Mandrake Software 不过, 副作用就是编辑器总是试图把它所知道的缩写扩展为整个单词, 如果你真想键入MS, 反倒成了一个难题. 所以尽量使用没有歧义的缩写.
Vim有一套优秀的语法高亮机制找到你的文本中存在的错误. 程序员尤其是这一功能的最大受益人.
语法高亮用特殊的颜色来显示注释. 这听起来好象没什么, 但一旦你使用了这项功能你就会发现好处多多. 你可以快速发现哪些部分应该是一个注释. 但是并没有被语法高亮指出来. 对程序员来说, 忘记注释的结束标记*/是很正常的事. 这在只有黑白两色的文本中可不是一件省油的事.
没有正确匹对的括号也可被语法高亮指出. 一个没有被正确匹对的括号")"会被一个亮红色的背景特别指出. 你可以使用 "%"命令看一看它应该跟谁匹配, 然后在正确的位置补上一个"("或")"
其它的一些常见错误也可被语法高亮功能协助你检查出来, 如#included < stdio.h>. 在黑与白的世界中它们对错难分. 但语法高亮可以帮你快速分辨出雌雄真假.
一个更复杂的例子: 对于英语文本来说, 可以有一个长长的可用单词的列表, 不包括在其中的单词都被视为一个错误, 使用一个语法文件, 你可以把所有没有出现在该文件列表中的单词用语法高亮功能标出来. 用一个特殊的宏你就可以往这个单词清单里加入新的生词. 加入后它们就不再被视为一个错误了. 这种功能以往只能在单词分析器中. 在Vim中使用简单的脚本就可实现, 而且, 你可以按自己的需要来定制这一功能. 比如, 你可以只检查程序中的注释.
第二部分: 编辑多个文件
4. 经常需要编辑不止一个文件
人们往往都不是只编辑一个文件. 通常有多个相关的文件. 可能要在单个地编辑文件后一次编辑几个文件. 或者同时编辑几个文件. 要进行高效的编辑就要充分利用编辑器一次编辑多个文件的功能.
前面提到的tag机制可被用于在多个文件间跳转. 通常的方法是为你正在做的项目生成一个tag文件. 之后就可以在这个项目的多个文件之间自由跳转, 发现函数定义, 结构, 类型定义typedef, 等等. 比起你单个地搜索这些文件, 可以大大节省你的时间; 浏览一个项目之前第一要作的事就是为它创建一个tags文件.
另一个强大的机制是在一个项目中找出一个名字在多个文件中的不同地方, 使用 ":grep"命令. Vim产生所有匹配的清单, 并且跳转到第一个匹配处. "cn"命令可以使你跳转到它的下一个匹配处. 这对于你要改变一个函数的参数来说非常有用.
被#include包含的文件含有丰富的信息, 但是要找出你想要的东西却要耗费大量的时间. Vim可以处理#include所包含的文件. 并且可以在其中查找你要找的东西. 经常的需求是查看一个函数的原型. 将光标定位在你要查看其原型的函数名上, 然后按下"[I"命令, Vim将会显示include文件中匹配这个函数名的一个清单. 如果你要看它的上下文信息, 可以跳转到它的声明处. 一个简单的命令可以用来检查你是否包含了正确的头文件.
Vim中可以把一个文本区分为几个不同的部分, 然后分别编辑各个部分, 编辑完成后你可以比较两个或多个文件的内容, 或在它们之间copy/paste文本内容. 有很多命令可以打开或关闭窗口, 或在它们之间跳转. 临时地隐藏文件. 等等. 再用上面的三个法则来练习你要掌握的新的命令.
多个窗口有多种用途. 预览标签机制是一个很好的例证. 它会打开一个特殊的预览窗口, 并且使光标仍然停留在你当前所在的位置. 在预览窗口中的文本列出了当前光标所在处的函数的声明(有些可能不是声明) 将当前光标移动到另一个函数名上, 停留几秒钟, 预览窗口中的内容就会变成是关于新函数名的声明.
5. 协同作业
编辑器是用来编辑文本的, e-mail程序是用来收发email的, 操作系统是用来运行用户程序的. 每个程序都有它自己的业务范围. 将这些程序的功能组合起来就可产生强大的处理能力.
一个简例: 在一个清单中选择一些结构化的文本并且将它排序"!sort". 外部程序 "sort"处理真正的排序工作. 就这么简单, 排序功能可以被集成进一个编辑器中. 但是, 如果你看一个"man sort", 你就会发现它有众多可用的选项. 它有一个高度优化的算法来执行排序工作. 你难道要在你的编辑器里写一个同样强大的排序程序吗? 或者其它的流过滤程序? 那将会使你的编辑器变得十分臃肿.
Unix的哲学是使用独立的小程序, 每个小程序做一项专门的任务, 并且把它作好, 将它们的工作整合到一起来完成一个复杂的任务. 不幸的是, 多数编辑器并不能与其它程序一起协同工作, 比如你不能替换Netscape里的e-mail编辑器. 另一种做法是把所有的功能都包括到一个程序中去. 在编辑器领域, emacs是这方面的一个典范(有人甚至说它是一个能编辑文本的操作系统)
Vim的做法是将这些分散的小程序整合起来, 但这样做也并不容易, 目前来说可以在MS的Developer Studio和Sniff中使用Vim编辑器, 一些e-mail程序也支持外挂的编辑器, 象Mutt, 就可以使用Vim. 与Sun的Workshop集成也可以正常工作. 在这方面Vim还有待在将来进一步提高. 直到我们找到一个比所有这些加起来还好的系统.
6. 文本是结构化的
可能你经常要打交道的文本都有一些内在的结构. 只是不被当前可用的命令所支持而以, 你可能不得不要回头建立你自己的宏和脚本来操作这些文本. 这样做显然有些复杂.
最简单的一件事就是加速你的 编辑-编译-修改 的周期. Vim有它自己的":make" 命令, 该命令编译你的程序项目, 捕获编译的错误/警告并允许你直接跳转到引起这一错误/警告的程序行上去. 如果你有一个另类的编译器, 它输出的错误信息可能对Vim来说是不可识别的. 不要紧, 更改你的'errorformat'选项, 这一选项告诉 Vim你的编译器将生成何种格式的错误信息, 以便于它能识别. 比如如何找到出错的文件名, 出错的行号, 既然它已经能与gcc产生的复杂的错误信息格式一同工作, 可以想见, 它也对付多数其它编译器产生的错误信息.
有时为一种特殊格式的文件作出调整也只是设置一些选项, 写一些宏, 如要跳转到 manual 帮助文档, 你可以写一个宏来获取当前当前所在的词, 清除当前的缓冲区并且读入相应的帮助页, 这对于查看交叉索引是一种简捷有效的办法.
使用上面的三项原则你就可以对付任何形式的结构化文本. 只要想一下你要对文件做些什么, 找出编辑命令, 练习使用它. 就象听起来一样简单. 唯一的事就是你必须真正去做它.
第三部分:
7. 养成习惯
学习驾车当然要花费心思, 但这足以成为你继续骑自行车的理由吗? 不, 你意识到你 需要投入时间学习一项技巧. 文本编辑与此同理. 你需要学习新的命令和技巧.
另一方面, 你也不必学习一个编辑器所提供的所有命令. 那样只会浪费你的时间. 绝大多数人只需要学习其中的10-20%的命令就足以应付它们的工作了. 但是对每个人来说, 适合自己的命令集各各不同, 这需要你不时地回顾以往所做的事, 看看是不是可以自动完成一些重复的工作. 如果你只进行了一次某项特殊的操作, 并且没指望将来还要进行类似的操作, 就不要试着去琢磨它了. 但是, 你也许能预见到在几个小时以内你就要重复进行同样的操作. 那么去文档里面搜索出你希望的"瑞士军刀" 或者要写一个宏来完成它. 如果任务过于复杂, 比如处理特殊类型的文本, 你可以到新闻组里看看是不是已经有人解决了与你相似的问题.
决定性的步骤是最后一步, 可能你发现了一个重复操作的解决方案, 几个星期后你却又忘记了. 那样没用. 你要不断地重复练习你的解决方案直到你的手指可以条件反射地自动完成, 从而达到你所期望的境界. 不要一次尝试太多的东西 , 一次做一件事并多做几次会好得多. 对于不经常的操作, 最好记下你的处理步骤以备将来不时之需. 不管怎样, 只要目标明确. 你就能找到让你的编辑变得更加高效的办法.
最后要提醒你的一点是人们往往还是会对上面提及的建议视而不见: 我还是经常看到人们花费半天的时间在屏幕上用两个手指上滚下翻. 真替他们感到费劲. 用十个指头操作也并不会让他们更快一点, 而且这样做也最容易让人心生厌烦. 每天使用一个计算机程序一个小时, 也只需要几个星期的时间练习这样的操作.
结束语
本文的由来是受Stephen R. Covey的名作"The 7 habits of highly effective people"启发. 我向我知道的每个人推荐它去解决个人的或专业的问题. 也许有些读者会说这是来自于Scott Adams 的"Seven years of highly defective people"一书(同样喷血推荐). 参见http://www.vim.org/iccf/click1.html的 "recommended books and CDs".
关于作者
Bram Moolenaar 是Vim的主要作者. 他写了Vim的核心功能并且负责甄选其它作者的代码. 他作为一名技术人员毕业于Delft技术大学, 现在他主要从事软件业. 但他也知道如何使用电烙铁. 他是荷兰ICCF的创建者和出纳. 这是一个帮助乌干达孤儿的组织. 他作为一个系统建筑师为自由软件工作, 但实际上他为Vim花费了大量的心血.