自从
开始对Emacs感兴趣,而不是仅局限于用
SLIME同Common Lisp偶尔亲热一下而已后,俺便断断续续读起号称Emacs初学者必备的
羚羊书第三版。一边读,一边笨手笨脚地使用Emacs。几周下来,虽然还要不时翻书,好歹开始习惯那些和Vim迥异的组合键。用C-f, C-n, C-p, M-d什么的也慢慢变成下意识的反应。俺的~/目录下也累积了50多兆各式扩展,模式,和配置文件。当然当然,作为初学者,俺坚持不用自己的key binding,除了把过气的/C-x/C-u映射到undo上以外。毕竟对缺省配置的极度熟悉有助于自己在不同的机器上使用Emacs。可移植性不仅是对程序的要求,也是对人的要求。总的来说,Emacs确实好用。扩展比郭敬明抄袭的文字都多,功能比黎叔吹的牛B还强。用于Common Lisp开发的SLIME,用于Ruby开发的Ruby Mode, 用于Java开发的JDE, 开发工具集合CEDET,让操作文件和缓冲方便之极的ECB。。。不过俺还是有些怀念Vim的方便,时不时用Vim编写点小东西。毕竟Vim区分编辑模式和控制模式,使得组合键简短。
![]() |
图片来自
John Dierdorf
|
使用Emacs编写程序的过程中遇到几个问题。后来在网上找到了答案。下面是整理出的答案。既然俺作为初学者曾为这些简单的问题而花上几个小时,也许这些答案能让其它初学者节省一点时间。
第一个问题是自动匹配完成代码。俺用惯了Eclipse,所以习惯于完
int foo(){的时候,编辑器自动添上配对的
}
。又比如编写Ruby代码的时候,当俺写完
def foo 的时候,编辑器会自动添加上
end
。刚开始我在Google上用诸如emacs auto completion这类的字眼搜索,总是出来一大堆不相干的信息。后来读ruby-mode的说明,才明白Emacs把自动匹配完成的功能归在electric mode里面。这点明白了,在Google上搜索就知道用什么关键词了。使用时,记着在语言mode加载的时候同时加载electric mode就行了。比如说下面的代码在ruby-mode加载时加上ruby-electric-mode:
(add-hook 'ruby-mode-hook
(lambda()
(require 'ruby-electric)
(ruby-electric-mode t)
))
第二个问题是自动缩进。在Eclipse的Java编辑器里,按下回车键会导致光标移到下一行,然后自动缩进到正确的位置。在俺看来,这是自然的行为。既然我在写程序,当然希望每一行都从正确的地方开始。编辑器应该帮我料理一切与写码无关的杂事。可惜Emacs(Vim一样)的缺省行为是光标移到下一行第一列。当我们完成一条表达式或statement后,改行自动缩进。这让俺非常不舒服,因为我容量小得可怜的大脑不得不分出1/7的空间去挂念缩进正确与否。后来俺知道了/C-j的功能正是回车然后缩进,相当于先ENTER,再TAB。但哪怕思考用/C-j还是回车都让俺举得大脑不堪重负(是的,卧春,卧室达春绿)。如果用set-global-key吧,又容易与有些模式下的/C-j冲突。把这段代码加到Emacs的配置文件解决了问题:
(mapcar
(lambda (mode)
(let ((mode-hook (intern (concat (symbol-name mode) "-hook")))
(mode-map (intern (concat (symbol-name mode) "-map"))))
(add-hook mode-hook
`(lambda nil
(local-set-key
(kbd "RET")
(or (lookup-key ,mode-map "/C-j")
(lookup-key global-map "/C-j"))))))) '(c-mode c++-mode cperl-mode emacs-lisp-mode java-mode html-mode lisp-mode ruby-mode sh-mode))
这段代码对一列语言中的每一个创建一组mode-map(其实就是Lisp里的一个Pair类型)。如果在创建的mode-map或者global-map里找到了/C-j的定义,就把它替换成回车。这样做的好处是我们只需要替换自己关心的语言模式。其它情况下/C-j不受影响。比较有意思的是,我开始犯了初级错误,以为add-hook里的匿名函数是个closure(其实不是,因为那个匿名函数前面有个单引号),于是进一步以为(lookup-key ,mode-map "/C-j")里的那个逗号没有必要存在。结果自然得到Lisp里的NullPointerException,void-variable。一不小心,就可耻了一把。
第三个问题是格式化整个文件。Eclipse下面CTRL+SHIFT+F就解决问题了。Vim下面gg=G也顺利搞定。Emacs下面得C-x h TAB。怎么敲速度都上不去。
有了下面这段代码,事情就好办多了:
(defun iwb ()
"indent whole buffer"
(interactive)
(delete-trailing-whitespace)
(indent-region (point-min) (point-max) nil))
M-x iwb 格式化整个文件。如果还嫌不够,把iwb映射到自己喜欢的组合键上就行了。