Emacs 与 C/C++ 代码自动补全
基于 Emacs 的 company 模式并配合 semantic 文法分析器,实现 Emacs 的 C/C++ 代码自动补全。
关于 Emacs 的代码自动补全
代码自动补全的功能,对于使用 Emacs 写代码的程序员而言其重要性不言而喻的,但是搜了一些所谓的 “Emacs 完美的 C++ 自动补全” 的文章,丝毫也没有感觉到美,反而只是让我不断的追忆 MS 的 Visual Stdio (.net) 的 C/C++ 代码自动补全功能,所以干脆就只当没这回事。一个本性就有些懒惰的人,最好不要面对太多容易令自己失望的东西。
"在 Emacs 下用 C/C++ 编程" 较为详细地讲述了使用 Emacs 内置的 hippie-expand 模式并配合 semantic 来解决 C/C++ 代码自动补全问题。在我知道 company-mode 项目之前,个解决方案或许是最好的选择了。实际上,我不满意 hippie-expand + semantic 组合,主要是因为配置有些麻烦,并且补全的界面也有些丑陋。
Company-mode 是什么
Company-mode (Complete anything-mode)是 Emacs 的代码自动补全扩展包,它的主要工作是配合许许多多的处理后端来实现比较方便并且清晰的代码补全。可以在一份简短的视频中获得对 company-mode 的直观认识。
要使用 company-mode 来解决 Emacs 的 C/C++ 代码自动补全问题,可选择的处理后端(tag 工具)有 etags、gtags 和 semantic。由于我之前从未用过这些工具,所以只好对比了一些资料并依赖直觉选择了 semantic,但愿未有选错
如果面对的问题是 c/c++ 之外的代码补全,那么 company-mode 扩展包中提供的那些后端或许可以满足大部分需求了,这意味着不用像 C/C++ 那样折腾。
安装所需要的软件包
炫耀一下我用的 gentoo 可以很方便地安装 company-mode 和 semantic(当然你也有足够的理由来炫耀你的系统):
$ echo "app-emacs/company-mode semantic" | sudo tee -a /etc/portage/package.use $ sudo emerge company-mode
由于开启了 company-mode 的 "semantic" USE 标识,会自动依赖安装 cedet(它包含 semantic)。
配置,配置……很容易令人厌倦
要在 Emacs 中生活的好,前提是得好好学习,天天配置。我这个 Emacs 世界的穷人,却每天都希望眼前不要出现那些括号套括号的代码,大有穷且益坚之势。
因为穷,所以也很容易感恩。Gentoo 在安装 emacs 的扩展包之后,会在 /usr/share/emacs/site-gentoo.el 文件中自动添加所安装扩展包的加载代码,因此我可以在自己的 .emacs 配置文件中省却类似以下的代码:
(load "/usr/share/emacs/site-lisp/cedet/common/cedet" nil t) (add-to-list 'load-path "/usr/share/emacs/site-lisp/company-mode") (autoload 'company-mode "company" nil t)
真好。
下面,先来配置一下 semantic,目的是让它可以帮助我们更好的分析出现在 Emacs 中的 C/C++ 代码,从中提取出那些有用的 tag。将下面代码写入个人的 .emacs 配置文件中。
(setq semanticdb-default-save-directory "~/.emacs.d/semanticdb") (semantic-load-enable-code-helpers)
上面的第 1 行代码是设定 semantic 生成的 tag 文件保存目录(请手动建立该目录)。如果不设置这个目录的话,据说 semantic 会将生成的 tag 文件放在当前的工作目录。第 2 行代码是设置 semantic 分析代码文法的方式,据说共有 5 种级别的分析方式,详见“在 Emacs 中使用 semantic”,对于 C/C++ 代码自动补全问题而言,选择 semantic-load-enable-code-helpers 没错。
配置完 semantic 之后,紧接着就是配置 company-mode 了,配置代码只有一行:
(setq company-idle-delay t)
这行代码是告诉 company-mode 扩展包,在弹出自动补全窗口之时莫要犹豫。如果不是很苛求自动补全窗口的弹出速度(假如你不认为 1 秒种有多么长),这行配置代码完全可以不需要的。
这令人厌倦的配置工作终于做完了,好累
体验一下 company-mode
现在,可以用 emacs 编辑一份 C 程序源文件,内容大致如下:
#include <stdio.h> typedef struct tagPoint { double x; double y; double z; } Point; int main (void) { Point *pt = (Point *) malloc (sizeof (Point)); pt->x = 0.0; pt->y = 0.0; pt->z = 0.0; return 0; }
在打开 C 文件之后,需要使用 “M-x company-mode" 命令开启 company-mode,这样自动补全才可以工作。下面看看我在编辑代码过程中的截图:
感觉很舒服。所以再花点时间进一步配置一下。
只针对 C/C++ 的配置
因为只是想在 C/C++ 代码编辑过程中启用 company-mode 和 semantic,所以前面所讲的配置虽然可以工作,但是有点铺张浪费。可以利用 Emacs 的 hook 函数,将上述配置代码插入 C/C++ 编辑模式中。这样,只有在使用 Emacs 编辑 C/C++ 源文件时,有关 company-mode 和 semantic 的配置才会生效。
现在请冷酷将前面的配置代码从 .emacs 文件中清除掉,换上下面稍微有点复杂的配置。
(add-hook 'c-mode-hook (lambda () (setq semanticdb-default-save-directory "~/.emacs.d/semanticdb") (semantic-load-enable-code-helpers) (setq company-idle-delay t) (company-mode)))
上述配置是针对 C 语言的模式。如果你是用 C++ 模式,那么就将 c-mode-hook 替换为 c++-mode-hook 吧。
上述配置代码的作用是定义了一个匿名的 elisp 函数(lambda 函数),然后这个函数插入到 c-mode-hook 的函数列表中。当 Emacs 编辑 C 文件时,便会自动调用那个 lambda 函数,从而 semantic 和 company-mode 的一些设置代码开始工作,最后并自动启用 company 模式。
2009年8月29日 22:55
评论无效?
2009年8月29日 22:55
@transtone: 还是更喜欢yasnippet,直接emerge就行。
2009年8月30日 00:09
谢谢推荐,我个试试
2009年9月01日 22:57
为什么我这不能正常工作? Mac 和 Gentoo 都不行,你那个 mode 为啥叫 company-semantic?我这里都是 company,哪里做错了吗?
2009年9月02日 02:11
@ leafduo:
$ > eix -e company-mode
[I] app-emacs/company-mode
Available versions: (~)0.4.2 (~)0.4.3 {semantic}
Installed versions: 0.4.3(03:16:51 PM 08/28/2009)(semantic -ropemacs)
Homepage: http://nschum.de/src/emacs/company-mode/
Description: In-buffer completion front-end
你的 gentoo 有没有打开 "~x86" 的限制?
2009年9月02日 02:38
只对 company-mode 开了 ~amd64
2009年9月03日 03:40
原来是在这里,前天在订阅的gentoo planet里看到这篇文章,果然很好用,没想到今天找输入法问题找到老窝了
2009年11月29日 06:26
为什么我照着你的配置,将你提供的C文件拷贝过去可以自动补全,
但是新建的其他C文件有的可以补全,有的没有一点反应,搞了一下午了,摸不着门道。:(
2009年11月29日 07:05
有的时候不是没有反应,而是 semantic 可能在分析你所使用的某个库的头文件,企图从中提出一些“关键词”。我这里在写 opengl 程序时,曾经遇到过这样的weti。
2010年1月30日 08:40
hi~我配置完了之后,company在.el里头很好用...可是在.cpp里头就不好用了...几乎不能用了
不知道你遇到过这样的问题没有...我怀疑是
semantic有问题。。。
请赐教。。