四月 22, 2006

Emacs Show - Editing

场景:一个同事在调Perl程序,通过注释程序的不同部分来定位问题所在。

问题:C/C++提供了/* */,用来注释大段代码,但是对于只有行注释的Shell脚本,Perl程序或者Emacs Lisp程序来说,这种调试方式似乎麻烦的很,特别是当行数较多的时候。

解决方案:Emacs,更准确的说——是各种语言的Mode,为用户提供了两条命令,快速注释和反注释选中的代码,他们是M-x comment-regionM-x uncomment-region。比如注释掉一个函数的操作序列通常是:

  1. C-M-h选中当前(即光标所在的)函数;
  2. M-x comment-region(在CC Mode里可以使用快捷键C-c C-c)注释掉整个函数。

你看,方便快捷,何乐而不为呢!如今Ruby越来越火,很多人提到的一个优点就是,它让程序员将精力完全集中在逻辑上,而不是实现的细节上。Ruby通过提供更高层的抽象实现了这一点。Emacs秉承同样的理念,程序员应该把更多的时间用在实现新功能或修改缺陷上,像在每行前面插入或删除井号(#,Perl、Shell等的行注释符)或分号(;,Emacs Lisp的行注释符)这样的活,还是交给程序来做吧。基于这样的理念,Emacs为用户提供了丰富的编辑操作。

在进行更多介绍之前,我们先解释上面例子中一些特殊符号的含义。C代表Control键,M代表Meta键(对于Windows键盘来说是Alt键),S代表Shift键;M-x的含义是先按住Meta键不放,再按x键,C-M-h的意思是同时按住Control键和Meta键不放,再按h键。使用Emacs时按Control键的机会非常多,但是对于中国人来说,Control键的位置似乎远了点,用小指按起来很累,我从同事那里学了一招——用手掌外侧去“压”Control键,这样,本来费力去按Control键的动作就转化成手轻轻向外侧翻的动作。如果你稍微留意的话,就会发现一个非常普遍的输入动作,左手按C-cC-x复制或剪切文本,右手握鼠标,定位光标后,左手再按C-v做粘贴。这是非常糟糕的编辑动作,是一个有追求的键盘手必须避免的。因为几乎每个人在按C-cC-xC-v时都要看一眼键盘,在把手从鼠标移回“j”键也要看键盘,结果,整个操作下来至少要看两次键盘,Cache狂miss啊,同胞们!更何况,在我们选择用手外侧这么优雅的动作去压Control键之后,就更不可能用一只手同时按C-cC-x了,在Emacs里,虽然它们不再代表复制和剪切,但同时按这两个键的机会还是很多的。因此,好习惯是右手按Control左手按cx,即使是对于M-x这种无伤大雅的击键,最好也养成右手按Meta左手按x的习惯。

Emacs的快捷键多如牛毛,对于熟练工来讲,它极大地提升了编辑效率,但对于初学者来说,则很难一下子记住那么多,没关系,我们一点一点来,先学习一些Emacs的基本概念

Point和Mark
Emacs里有两个特殊的位置。光标所在位置称为point,它可以通过Emacs Lisp函数(point)获得。有一点需要注意的,这个位置的概念与字符的位置概念是不一样,这里的位置指的是两个字符之间的位置,所以,所谓的光标位置,实际指的是光标前一个字符与当前字符之间的位置。理解了这里面的区别,就很清楚使用C-t交换两个字符位置时应该把光标放在哪里。比如我经常把label写成lable,这时,只要将光标停在le之间,然后按C-t就可以纠正拼写了。Mark是一个特殊的位置,Emacs通常为用户保存了一系列重要的位置,其中最新的一个称为当前Mark所在的位置,我们可以通过C-u C-Space将光标定位到当前Mark所在位置,还可以连续使用该快捷键回到前面任何一个保存的Mark位置。当然,这样的Mark通常是由一些命令自动设置的,比如粘贴(C-y)之后,光标通常定位在新文本的末尾,当我们想把光标移到原来的位置(即新文本的开头),就可以利用Mark,因为粘贴命令在操作前已经保存了一个Mark。用户也可以显示地申请一个Mark(C-Space),通常是为了选中某个区域(region)。
region
region就是选中的区域。选中一段文本的方式很简单,在你想选择的文本一端申请一个Mark,然后将光标移到另一端,这时Mark与Point之间的文本就称为选中的region。通常来讲,我们只能移动光标所在位置,所以当我们发现Mark错了位置时,只能放弃当前的选择,重新来过。Emacs知道用户经常会改变主意,所以提供了C-x C-x交换Point与Mark的位置,这样,我们就可以双向调整选中的区域。当我发现Emacs的这个功能时,就对自己说,这辈子就是它了,可见爱是多么冲动:-)。如果当前文本里存在一个选中的region,那么很多操作的行为会因此而发生改变,比如字符串替换。通常,它会替换从当前光标所在位置到文本末尾之间所有出现的字符串,但是当存在一个选中区域时,替换操作只发生在这个区域里。想想这有多方便吧,比如我想把一个函数里所有的变量i改名为index,那么只需用C-M-h选中这个函数,然后M-x replace-string。因为选中区域的操作非常频繁,所以我把调出输入法(无论是在Windows还是Linux上)的快捷键改为C-S-F9

好,我们现在可以学习一些Emacs为我们提供的便利工具了。很多编辑器都提供了整词查找和替换功能,是不是常方便?而Emacs不仅提供了更多的基于词的操作,还提供了基于句子,甚至基于函数的操作。各种各样的括号恐怕是最让程序员头疼的了,幸好很多编辑器都提供了括号匹配功能,而Emacs的括号匹配、光标移动以及region结合在一起,有意想不到的功效。让我们看看下面的一些例子吧。

Emacs里面的词指的是以空格或标点符号格开的字符和数字组成的序列。我们可以使用M-f向前(或M-b向后)将光标移动到相邻单词的边界,使用M-@将Mark设在下一个单词的边界处,而保持光标位置不变,M-d删除下一个单词,M-Backspace向后(backward)删除一个单词(不用再狂按Backspace了)。另外,当编写程序时,我们还可以使用C-M-a将光标定位到当前函数头,C-M-e到函数尾,用C-M-f选中当前函数。而C-M-nC-M-p则可以将光标定位在两个匹配的括号上。另外,Emacs也提供了相应的快捷键取代HomeEndPageUpPageDown,使得我们可以彻底抛弃这些键,以及方向键和鼠标。综合使用Emacs提供的丰富的光标移动操作,我们定位光标的速度将远远大于过去那种鼠标加方向键的模式。这些操作不仅可以用来移动光标,还可以用来选中区域。比如选择一对大括号包围的所有语句,只需在左大括号前申请一个Mark,然后用C-M-n将光标移动到对应的右大括号之后,这样,整个选择操作就完成了。

怎么样?有点动心了没有?

四月 17, 2006

Emacs Show -- Motivation

“工欲善其事,必先利其器”。用Emacs三年,略知其中滋味,希望与更多的程序员分享,也算为开源社区做点贡献吧。

学了Emacs才知道,输入(以及修改)程序也是有很多学问的。记得当初关于“软件蓝领”的争论焦点就是写程序是体力活还是脑力活,是否仅仅等于敲敲键盘。虽然到头来双方仍是自说自话,但似乎都同意“敲键盘是体力活”。大家对编辑器的期望无非也就是语法高亮、自动缩进,如果能有自动补全那就谢天谢地了。我周围的同事用的编辑器各种各样,有SourceInsight、SlickEdit、UltraEdit……,但用得最多的还是vi,甚至连新来的实习生都用vi,这让我很吃惊,我上学那会儿可都是用IDE的啊。即使这样,还是有很多同事对UltraEdit的列插入功能津津乐道,由此可见,很多编辑器对于编辑这个老本行做得还不够。大家使用SourceInsight和SlickEdit,也是用其代码浏览和定位功能,而其编辑功能并无出彩之处。

编辑是程序开发领域唯一的体力活吗?体力活意味着机械、单调、令人厌烦。我们选择干程序员这行,不就是想多动脑少动手吗?如果你把编辑当成体力活,那么肯定你的手指经常游走在方向键、Home、End、PageUp、PageDown、Delete和Backspace之间,偶尔(也许是很多时候)不得不借助鼠标,即使你也知道用鼠标对手腕的伤害要远远大于键盘。也许你觉得这没什么不好,难道不是每个程序员都这样吗?答案是:不是。Emacs用户将这种行为比喻为Cache Miss,可见其对效率的伤害程度。几乎每个人都会同意,输入速度取决于盲打的熟练程度,看键盘是非常忌讳的。然而,有多少人可以不看键盘就能找对上面提到的几个键呢?即使找对,恐怕手已移开半尺(鼠标就更远了),让食指回到"J"键上也不那么容易吧。当我们尚不清楚接下来该写什么的时候,这并不成问题,尽可以将每个动作做得轻松、优雅。但是当我们早已胸有成竹,只等下手时,还是这样编辑,不仅减缓速度,还会滋生急躁、甚至烦躁的情绪。试想以下操作我们通常是如何完成的:

  • 删除一个长达三屏(甚至更长)的函数;
  • 重新格式化一段没有做好缩进的代码;
  • 只在一个函数(或一块文本)里做字符串替换;
  • 选好一块很长(数屏)的文本后发现结尾处选对了,可是开头处要做一些调整。

我曾经为这些问题郁闷得不行,尤其是最后一个,简直暴跳如雷,因为除了重来,还能怎样呢?直到用了Emacs才发现,原来生活可以如此简单,写程序可以如此快乐。所以,尽管过了三年,我仍然为每一次击键兴奋不已,我所在的组共6人(包括我),经过我的鼓吹,有3名同事开始使用Emacs。

使用Emacs的好处有很多,我会在后续的blog里面重点介绍,但我认为最重要的是,它彻底改变了我对编辑的认识,从此以更严肃的态度对待它。正如高级语言取代汇编语言一样,那些只能区分单个字符的编辑器也该被丢弃,只有提供更高的抽象,以及基于这些抽象的操作,才能使开发过程更加高效。

我个人认为Emacs的强大之处可以在下面几个方面得到体现:

  • 对编辑操作的支持极其丰富,使得输入过程非常流畅,比如支持正反双向以一个字符、单词、句子、甚至段落为粒度移动光标,将光标快速定位到函数头尾、该行第一个非空格字符,双向调节选中区域,注释掉选中区域或去掉选中区域的注释(对于只支持行注释的语言,如Perl等,非常方便),等等,数不胜数;
  • 可定制性。每个人都有自己的偏好,有人喜欢语法高亮,有人不喜欢;有人喜欢4格缩进,有人喜欢GNU风格,还有人不希望缩进有tab键,只能用空格,等等。Emacs为此提供了极其灵活的定制功能,使其满足不同口味的人群。
  • 可扩展性。Emacs由两种语言实现——C和Emacs Lisp,除了少数基本操作和一部分对性能要求较高的函数外,绝大多数功能都是由Emacs Lisp实现,而Emacs本身就可以看作是一个Emacs Lisp程序运行环境,因此,任何人都可以使用Emacs Lisp实现自己所需的功能。同样是编辑,写程序和写文章的需求是不一样的,正是由于Emacs的这种开放性,使其可以满足绝大多数编辑需求,即使是那些非常古怪的要求,因为你总是可以写一段程序来完成它。不要因为看到Lisp就畏缩不前,它有很多美妙的语法特性是你在其它语言中看不到的,它让你惊呼,原来程序也可以这么写。
  • 在线帮助。没有比找不到帮助更让你泄气的了,而Emacs永远不会让这种事情发生。所以,你很难在市面上见到讲Emacs或Emacs Lisp的书,而网站只需http://www.emacswiki.org/一个足矣。
  • 与环境完美集成。这个环境当然是指GNU/Linux环境,在Windows上可以选择Cygwin。与版本控制系统的无缝连接,编译、调试、搜索,收发电子邮件,订阅新闻组,查看其它GNU/Linux系统命令帮助,等等。一种夸张的说法是有人就生活在Emacs里。:-)

学习Emacs的唯一难处是开始很难。原来一个美国同事说他从vi转到Emacs时有6个月啥也不能干。我想可能是夸张了点,一些基本操作还是很快就能上手,毕竟,你还是可以像使用notepad一样使用它。难的是改掉陋习,和记住多如牛毛的快捷键。需要彻底地洗脑,这是一个漫长的过程,要吾日三省吾身,多学习多温习多看帮助多练习。

我知道,仅凭一篇文章很难带来足够的动力,我会继续写几篇,展示Emacs的迷人之处,也希望它能成为每个中国程序员手中的利器。

四月 11, 2006

Cygwin Apache

Cygwin里面带有Apache 2,安装文档在/usr/share/doc/Cygwin/apache2-2.2.0.README,不过把它作为一个Windows服务运行要比exim和cron难多了,下面是一些调试的方法,仅供参考。

最不爽的是,启动服务(cygrunsrv -S httpd2)的错误信息永远只有一条,那就是"Win32 error 1062",不过log可以给出更多的答案。首先可以查看/var/log/httpd2.log,config文件里的语法错误一般显示在这里,而权限问题一般显示在/var/log/apache2/access_log或/var/log/apache2/error_log里面,我遇到的最诡异的问题是"No space left on device: Couldn't create accept lock or Cannot create SSLMutex",可我的硬盘空间多的是啊?!原来,这个问题跟硬盘空间没有关系,而跟IPC有关,详见这里。解决方法是运行ipcs -s | grep apache | gawk '{ print $2 }' | xargs -n 1 ipcrm -s然后重新启动就好了。初次接触IPC,不明白为什么,还需要深入研究。

四月 10, 2006

Dumbbell

My 6kg Dumbbell

昨天买了一副哑铃,每个6公斤,一共216元。在港汇买的,是可拆卸里面最小的一副,再重一点的我就拿不动了——就算舍得花钱买,也没力气搬回去。除了这种黑色风格的外,还有一种镀过的,不过上面的字是红色的,我觉得很难看。售货员却说还是那种贵一点,因为看起来漂亮,我嘴上没说,心想这人与人之间的审美标准怎么差距这么大呢?!

工作三年没咋运动,越来越觉得自己虚弱,上三层楼就开始喘了。哑铃锻炼起来很方便,能够锻炼到的部位也不少,适合我这种懒得往外跑的人。网上找了些帮助,“锻炼,从今天开始”。

四月 08, 2006

Firefox extension for Windows?

Reducing Your Memory Usage In Firefox中讲到一些Firefox的扩展有内存泄漏,连忙禁掉。不过SessionSaver不能用了有些遗憾,幸好Tab Mix Plus,不过打开页面的时候上面显示Install Now for Windows,立刻很反感,难道只能用在Windows上吗?那我的Linux怎么办?于是没装。

昨晚在家里装Web Developer,发现页面上显示Install Now for Linux,这才明白,应该是自动识别出操作系统,显示不同的文字,有些插件可能确实要区分Windows版本和Linux版本吧。但是,真的需要这样吗?不知道有多少人产生和我一样的困惑?如果真的想做得智能的话,干脆显示“Install Now”好了,所有的不同对用户来说都是透明的。“for Windows”、“for Linux”完全是画蛇添足嘛!

四月 07, 2006

Innovation

最近公司开始鼓吹创新,可惜我感觉有光说不练的嫌疑。

创新,只有从创新者的嘴里说出来才让人信服;创新,也只有在一定的土壤里才会发芽。英特尔开始宣扬创新,是一次从上至下的运动,起因大概是看Google红了眼。可是,想让高层领导承认,“咱们创新少,未必是员工技不如人”,还是很难的。

在我看来,英特尔的问题是太过小家子气。比如Google允许员工用20%时间做自己的项目,人家可没说这也不许做那也不许做,更没说不是创新就别拿出来丢人现眼了。人家的领导是无为而治。可在我所工作的地方,领导们为了创新忙得热火朝天,大会小会讲不算,还拿出奖品举办创新点子大赛,甚至承诺给予一定的资金和人力支持,实现最具创意的想法。然而,由几名裁判选出来的创意能否真的算是一种创意还很难说,某些创意在萌芽阶段往往被认为是疯狂的表现,无法得到人们的认可。所以,这种方式的致命之处不在于获奖创意未必能够成为现实,而是那些落选作品从此夭折,甚至没有机会证明自己。

真正阻碍员工创新的因素在老板的心里。难怪有人说,市场经济里的公司却在采用集权方式管理。无法摒弃的控制欲,听不得不同意见,在这样的环境下,怎么可能出现创新呢?创新应该是一种自下而上的行为,如果公司里只有老板谈创新,那一定是管理出了问题。

四月 06, 2006

Open Source Community

最近开始尝试两个新东西——VTune和Ruby,获得了完全不同的感受。

VTune是英特尔的软件产品,是一种软件性能分析工具,是英特尔除了编译器之外另一种重量级的软件开发工具。由于用户抱怨我们的软件性能不好,所以开始用它分析程序都把时间花在哪里。在使用过程中遇到一些问题,就到Google上去查,比如VTune "7.2" "Call Graph" "Data collection started",只能得到寥寥几条结果,试想,即使对于像我这种所谓“自己人”也很难使用,更何况对于一般用户呢?

忍了很久,终于开始学Ruby,光听说好,不自己亲自体验一下,总觉得言过其实。我是从Programming Ruby开始的,这本书的序和前言里都提到,在Ruby的发展过程中,社区的作用非常重要,Dave Thomas和Andy Hunt更是付出了巨大的精力写了这本书,将Ruby介绍给英语世界。

对比两者,有些东西值得我们思考,比如:用户参与度对于发展是至关重要的。另外,Ruby之父的一段话引起了我的共鸣:

Man is driven to create; I know I really love to create things. And while I'm not good at painting, drawing, or music, I can write software.

曾经很郁闷,感觉很多大牛都在业余时间玩点音乐,比如Richard Stallman,这些人一般都持有一种观点,开发软件和创作音乐一样,具有艺术成分。而我,除了软件,任何其它艺术形式都不擅长,甚至连爱好也谈不上,一度怀疑自己是不是真的喜欢写程序。看了上面这段话,心里舒服多了,至少,有人和我一样。:-)