图片来自 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映射到自己喜欢的组合键上就行了。