gocode——VIM 和 Emacs 的 golang 代码自动补全

虽然 golang 自身提供了 VIM 的语法高亮之类的脚本,但 autocompletion 并没有官方解决方案。无意之中发现 gocode 这个支持 VIM 和 Emacs 的 autocompletion daemon。

这里有个Flash 动画演示,展示了 gocode 的强大。我得说,用过之后,感觉速度确实够快。

下面是来自官方的部分介绍:

用于 Go 编程语言的自动补全守护进程

Gocode 是可以整合在如 vim 和 emacs 这样的代码编辑器中的辅助工具。它提供了一系列的高级功能,包括:

  • 上下文敏感的自动补全

(译注:残念,还真是“一”系列啊!好吧,但是说实话单就这一个功能就很好用了。)

由于使用 client/server 架构的缓存形式,所以被称为守护进程。这使得自动补全非常快。通常,在缓存生效的情况下自动补全时间在 30ms,一般不会察觉这个延迟。

gocode 的文档对安装说得很是详细,我这里仅对 VIM 做个简单的说明。另外,由于 golang 的 pkg 还不够稳定,不同版本可能会出现编译错误。实际上在我安装过程中,还是 fix 了 gocode 的兼容问题,才顺利安装的。下面会做详细说明。

首先,我假设你已经安装好了 go,设置好了 $GOBIN,并将其加入了 $PATH中。使用 8g -V 查看 go 版本,确保版本是【8g version weekly.2011-03-15 7807】。版本不同,在一些 go 的 pkg 的命名、方法等都会有不同。这可能会引起你在编译 gocode 时报错。

从 github 上获取 gocode 代码:

git clone git://github.com/nsf/gocode.git

进入 gocode 目录,编译并安装:

cd gocode&make install

在我的编译过程中,出现如下错误:

mikespook@mikespook-desktop:~/Desktop/gocode$ make install
8g -o _go_.8 gocode.go autocompletefile.go package.go autocompletecontext.go server.go rpc.go decl.go apropos.go scope.go ripper.go config.go declcache.go os_posix.go
autocompletefile.go:230: undefined: ast.TypeCaseClause
autocompletefile.go:232: undefined: ast.TypeCaseClause
autocompletefile.go:246: typechecking loop
make: *** [_go_.8] 错误 1

这是由于 go/ast 中的 TypeCaseClause 已经改名为 CaseClause。用下面的 patch 即可解决这个问题:

diff --git a/autocompletefile.go b/autocompletefile.go
index e08e161..c0c83c4 100644
--- a/autocompletefile.go
+++ b/autocompletefile.go
@@ -227,17 +227,17 @@ func (f *AutoCompleteFile) processTypeSwitchStmt(a *ast.TypeSwitchStmt) {
                }
        }
 
-       var lastCursorAfter *ast.TypeCaseClause
+       var lastCursorAfter *ast.CaseClause
        for _, s := range a.Body.List {
-               if cc := s.(*ast.TypeCaseClause); f.cursor > f.fset.Position(cc.Colon).Offset {
+               if cc := s.(*ast.CaseClause); f.cursor > f.fset.Position(cc.Colon).Offset {
                        lastCursorAfter = cc
                }
        }
 
        if lastCursorAfter != nil {
                if tv != nil {
-                       if lastCursorAfter.Types != nil && len(lastCursorAfter.Types) == 1 {
-                               tv.Type = lastCursorAfter.Types[0]
+                       if lastCursorAfter.List != nil && len(lastCursorAfter.List) == 1 {
+                               tv.Type = lastCursorAfter.List[0]
                                tv.Value = nil
                        }
                        f.scope.addNamedDecl(tv)

完成后,安装程序会自动将编译好的 gocode 可执行文件复制到 $GOBIN 目录中。所以请务必确保 $GOBIN 设置正确。

对于 VIM 来说:

首先确保 $GOROOT/misc/vim 中的 Go VIM 脚本正确安装配置。可参考我的 vim 配置:https://bitbucket.org/mikespook/foobar/src/b7dbcbdbf3dd/vim/

然后安装 gocode 的 vim 脚本,可以简单执行 gocode 提供的 shell 脚本:

cd gocode/vim && ./update.bash

实际上,这个脚本做了以下工作:

#!/usr/bin/env bash
mkdir -p ~/.vim/{autoload,ftplugin}
cp autoload/gocomplete.vim ~/.vim/autoload
cp ftplugin/go.vim ~/.vim/ftplugin

确保 vim 启用了 filetype 插件,.vimrc 中应当有:

filetype plugin on

好了,用 现在可以呼出 go 语言的自动补全了。

我为了方便,将 Ctrl+Space 映射为自动补全快捷键:

imap <C-Space> <C-x><C-o>

由于我不用 Emacs,所以 Emacs 党请绕道官方文档吧……;)

【最新更新】

根据作者提供的线索,使用 golang 的 weekly 版本是不需要打补丁的。所以,正确的 golang 安装版本是【3b4e9c85b643 weekly/weekly.2011-03-15】

hg up -r weekly
hg id

在 7787 版本 CaseClause 才与 TypeCaseClause 合并到一起,成为 CaseClause。

Join the Conversation

4 Comments

Leave a comment

Your email address will not be published. Required fields are marked *