场景:一个同事在调Perl程序,通过注释程序的不同部分来定位问题所在。
问题:C/C++提供了/* */,用来注释大段代码,但是对于只有行注释的Shell脚本,Perl程序或者Emacs Lisp程序来说,这种调试方式似乎麻烦的很,特别是当行数较多的时候。
解决方案:Emacs,更准确的说——是各种语言的Mode,为用户提供了两条命令,快速注释和反注释选中的代码,他们是M-x comment-region和M-x uncomment-region。比如注释掉一个函数的操作序列通常是:
- C-M-h选中当前(即光标所在的)函数;
- 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-c或C-x复制或剪切文本,右手握鼠标,定位光标后,左手再按C-v做粘贴。这是非常糟糕的编辑动作,是一个有追求的键盘手必须避免的。因为几乎每个人在按C-c或C-x或C-v时都要看一眼键盘,在把手从鼠标移回“j”键也要看键盘,结果,整个操作下来至少要看两次键盘,Cache狂miss啊,同胞们!更何况,在我们选择用手外侧这么优雅的动作去压Control键之后,就更不可能用一只手同时按C-c或C-x了,在Emacs里,虽然它们不再代表复制和剪切,但同时按这两个键的机会还是很多的。因此,好习惯是右手按Control左手按c或x,即使是对于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-n和C-M-p则可以将光标定位在两个匹配的括号上。另外,Emacs也提供了相应的快捷键取代Home、End、PageUp和PageDown,使得我们可以彻底抛弃这些键,以及方向键和鼠标。综合使用Emacs提供的丰富的光标移动操作,我们定位光标的速度将远远大于过去那种鼠标加方向键的模式。这些操作不仅可以用来移动光标,还可以用来选中区域。比如选择一对大括号包围的所有语句,只需在左大括号前申请一个Mark,然后用C-M-n将光标移动到对应的右大括号之后,这样,整个选择操作就完成了。
怎么样?有点动心了没有?
good!
I like it!
对于中文键盘,Control的位置的确很不好,导致效率很低。我就把Control和没用的Window键都设成了Control,你可以把他们俩换一下,很容易左手盲打C-x和C-c。另外我还把那个不经常按的Capslock和常用的Escape换了。