Go autocompletion daemon

727 views
Skip to first unread message

nsf

unread,
Jul 27, 2010, 7:40:08 AM7/27/10
to golang-nuts
Hello.

I think now it's a good time to introduce my project to public. Last
few weeks I was working on an autocompletion daemon for the Go
programming language. And currently it's semicomplete. It is certainly
in a usable state, but of course it contains bugs and probably will
not work for all cases. I didn't test it much and it is still in
development. Here is a features summary:

- Parses all gc compiler suite archived packages (.a files),
extracting type information. Currently is not able to parse numeric
constants (all const numbers are replaced by 0).

- Has complete type inference. Handles different expressions and
gives the resulting type. Currently doesn't parse binary
expressions, because they make sense only with strings and ints and
floats, etc. And those types don't have any children, therefore
they are out of interest for autocompletion.

Type inference supports complex variants like special handling for
range loops, type switch statements, etc.

- As it was said before, implemented as a daemon and a client. It
allows you to easily integrate that system in any kind of editor. I
have a fully working vim plugin and a proof-of-concept emacs elisp
script for auto-complete-mode.

As a result, caches everything, with warm cache on my PC (low end
core2duo 2ghz) gives autocompletion proposals in 50 milliseconds.

- Supports multifile packages. Automatically searches for files with
the same package clause in the directory of the currently edited
file. That support includes correct file/package namespace handling
issues.

For a quick live features overview see this demo:
(adobe flash, 3.6 mb, soundless screencast recorded by pyvnc2swf)
http://nsf.110mb.com/gocode-demo.swf

--= Source code =--

Project is hosted on the github, and called 'gocode':
http://github.com/nsf/gocode

--= Usage guide =--

Everything is pretty simple. Just 'make install' it and make sure it
is available on your PATH (vim plugin assumes that).

In order to install vim plugin you need to have vim scripts installed
from the Go source tree ($GOROOT/misc/vim). After that just run
'update.sh' script from the 'vim' dir in the gocode source tree. It
will work on mac and linux (installs vim plugin files in ~/.vim/...).
Make sure you have 'ft plugin on' and you're done! Use <C-x><C-o> for
omnicompletion.

Daemon is started automatically and it is panic-safe. Means if it dies
with a panic during autocompletion, it will drop its cache and
continue serving requests. On panic prints stack trace also. In order
to see a stack trace you may want to run it manually somewhere in the
terminal using this command: 'gocode -s'.

--= Dark corners =--

Of course it's not a super magic system and there are things that do
not work. For example in that case it will not autocomplete (# means
cursor position):

if myVar := NewObj(); myVar.# {
}

Because it adds myVar to a current scope only if the cursor is inside
the if block. It's a limitation of a current implementation. Maybe I
will workaround it somehow in future, but currently that is the way.
You can live with that I'm sure.

NOTE: I'm using the 'go/parser' for everything and even though it
handles errors very well it wasn't created for autocompletion parsing.
And there are actually few hacks in order to be more precise (for
example a function with cursor in it is being parsed separately from
other source code, because it may contain incomplete statements and
actually break parsing).

Also currently the package cache doesn't work properly. It means that
if gocode loads a package from an archive file, it stays forever in
the cache and never gets reloaded. As a workaround you can close
autocompletion server by invoking 'gocode close' command or simply
drop cache (which basically does the same) using 'gocode drop-cache'
command. The first is better, because the second results in RAM usage
growth.

The project itself is written in a hackerish style as it is just a
first autocompletion thing I've ever written and you can't make
anything right with the first try anyway.. So, the code is ugly.

--= Future work =--

I have plans to work on a refactoring system. It's easier to some
extent because it has a requirement of a correctly parsable source
code. And maybe less caching and less speed requirements pressure.
Refactoring system will include things like rename identifier, etc. I
haven't thought about it much yet.

Also I have plans to continue improving autocompletion, maybe with
your help.

P.S. I hope it will be useful for somebody like it is for me.

Kyle Consalus

unread,
Jul 27, 2010, 8:00:47 PM7/27/10
to nsf, golang-nuts
I haven't gotten a chance to try it out myself, but based on the video and your description..
that.. is.. awesome.

Thanks for making this and sharing it; I look forward to playing with it.

Liam O'Tootle

unread,
Jul 27, 2010, 11:49:20 PM7/27/10
to golang-nuts
I emailed the author directly to help resolve some config issues on my
end. I am posting the author's answers here in case they prove helpful
to others.

To install the vim scripts that ship with the Go distribution, read
$GOROOT/misc/vim/readme.txt
-Verify vim was able to detect the filetype correctly by typing ":set
filetype" in vim. It should print: "filetype=go"
-Verify filetype detection and plugins are enabled by typing
":filetype" in vim. It should print: "filetype detection:ON
plugin:ON ..."

If filetype detection and plugin are not enabled, add these to
~/.vimrc:
filetype on
filetype plugin on

Many thanks to the author for the work on this and for the help!


On Jul 27, 4:40 am, nsf <no.smile.f...@gmail.com> wrote:
> Hello.
>
> I think now it's a good time to introduce my project to public. Last
> few weeks I was working on an autocompletiondaemonfor the Go
> programming language. And currently it's semicomplete. It is certainly
> in a usable state, but of course it contains bugs and probably will
> not work for all cases. I didn't test it much and it is still in
> development. Here is a features summary:
>
>  - Parses all gc compiler suite archived packages (.a files),
>    extracting type information. Currently is not able to parse numeric
>    constants (all const numbers are replaced by 0).
>
>  - Has complete type inference. Handles different expressions and
>    gives the resulting type. Currently doesn't parse binary
>    expressions, because they make sense only with strings and ints and
>    floats, etc. And those types don't have any children, therefore
>    they are out of interest for autocompletion.
>
>    Type inference supports complex variants like special handling for
>    range loops, type switch statements, etc.
>
>  - As it was said before, implemented as adaemonand a client. It
>    allows you to easily integrate that system in any kind of editor. I
>    have a fully working vim plugin and a proof-of-concept emacs elisp
>    script for auto-complete-mode.
>
>    As a result, caches everything, with warm cache on my PC (low end
>    core2duo 2ghz) gives autocompletion proposals in 50 milliseconds.
>
>  - Supports multifile packages. Automatically searches for files with
>    the same package clause in the directory of the currently edited
>    file. That support includes correct file/package namespace handling
>    issues.
>
> For a quick live features overview see this demo:
> (adobe flash, 3.6 mb, soundless screencast recorded by pyvnc2swf)http://nsf.110mb.com/gocode-demo.swf
>
> --= Source code =--
>
> Project is hosted on the github, and called 'gocode':http://github.com/nsf/gocode
>
> --= Usage guide =--
>
> Everything is pretty simple. Just 'make install' it and make sure it
> is available on your PATH (vim plugin assumes that).
>
> In order to install vim plugin you need to have vim scripts installed
> from the Go source tree ($GOROOT/misc/vim). After that just run
> 'update.sh' script from the 'vim' dir in the gocode source tree. It
> will work on mac and linux (installs vim plugin files in ~/.vim/...).
> Make sure you have 'ft plugin on' and you're done! Use <C-x><C-o> for
> omnicompletion.
>
> Daemonis started automatically and it is panic-safe. Means if it dies

abiosoft

unread,
Jul 28, 2010, 7:28:04 AM7/28/10
to golang-nuts
just tested it and it works fine with vim. Great job
> (adobe flash, 3.6 mb, soundless screencast recorded by pyvnc2swf)http://nsf.110mb.com/gocode-demo.swf

nsf

unread,
Aug 9, 2010, 8:36:00 AM8/9/10
to golang-nuts
On Tue, 27 Jul 2010 17:40:08 +0600
nsf <no.smi...@gmail.com> wrote:

> Hello.
>
> I think now it's a good time to introduce my project to public. Last
> few weeks I was working on an autocompletion daemon for the Go
> programming language. And currently it's semicomplete. It is certainly
> in a usable state, but of course it contains bugs and probably will
> not work for all cases. I didn't test it much and it is still in
> development. Here is a features summary:

Hello. News for a project:

I did a complete refactoring for all of the code. The code was heavily
restructured.

Short changes summary:

- Autocompletion works faster. Typical autocompletion time should be
like 20-30ms. Was 40-50ms. Also I will add few more changes and
maybe it will be even more faster.

Autocompletion with cold cache is much faster too (somewhat 2x
faster). This gocode iteration uses goroutines for parsing multiple
files/packages in a concurrent fashion. GOMAXPROCS=2 or more may
affect performance a bit, like 20-30%.

- I did a proper (at least I think it is) scope handling. Now all the
predefined identifiers are really identifiers and you can redeclare
them and it all should be handled correctly.

- Autocompletion proposal without context includes predefined
identifiers (it will be possible to turn that off in future via
some kind of an option, because it is annoying sometimes).

- In the original post I've mentioned that cache for modules wasn't
implemented correctly. It's worth saying that it was implemented a
long time ago.

- Still a lot of things to be done.

Project link reminder:
http://github.com/nsf/gocode

Eric Fode

unread,
Aug 17, 2010, 4:42:15 PM8/17/10
to golang-nuts
I am getting errors when compiling gocode
gomake -C goremote
make[1]: Entering directory `/home/eric/gocode/goremote'
/home/eric/bin/8g -o _go_.8 goremote.go
goremote.go:24: cannot call non-function t.Name (type string)
goremote.go:30: cannot call non-function t.Sel.Name (type string)
goremote.go:30: cannot use t.Sel.Name() as type interface { } in
function argument
goremote.go:69: cannot call non-function name.Name (type string)
goremote.go:69: cannot use name.Name() as type interface { } in
function argument
goremote.go:164: cannot call non-function fun.Name.Name (type string)
goremote.go:164: cannot use fun.Name.Name() as type interface { } in
function argument
goremote.go:210: cannot call non-function fun.Name.Name (type string)
goremote.go:211: cannot call non-function fun.Name.Name (type string)
goremote.go:211: cannot use fun.Name.Name() as type interface { } in
function argument
goremote.go:211: too many errors
make[1]: *** [_go_.8] Error 1
make[1]: Leaving directory `/home/eric/gocode/goremote'
make: *** [goremote/goremote] Error 2


On Aug 9, 5:36 am, nsf <no.smile.f...@gmail.com> wrote:
> On Tue, 27 Jul 2010 17:40:08 +0600
>

nsf

unread,
Aug 17, 2010, 4:54:44 PM8/17/10
to golan...@googlegroups.com
On Tue, 17 Aug 2010 13:42:15 -0700 (PDT)
Eric Fode <eric...@gmail.com> wrote:

> I am getting errors when compiling gocode
> gomake -C goremote
> make[1]: Entering directory `/home/eric/gocode/goremote'
> /home/eric/bin/8g -o _go_.8 goremote.go
> goremote.go:24: cannot call non-function t.Name (type string)
> goremote.go:30: cannot call non-function t.Sel.Name (type string)
> goremote.go:30: cannot use t.Sel.Name() as type interface { } in
> function argument
> goremote.go:69: cannot call non-function name.Name (type string)
> goremote.go:69: cannot use name.Name() as type interface { } in
> function argument
> goremote.go:164: cannot call non-function fun.Name.Name (type string)
> goremote.go:164: cannot use fun.Name.Name() as type interface { } in
> function argument
> goremote.go:210: cannot call non-function fun.Name.Name (type string)
> goremote.go:211: cannot call non-function fun.Name.Name (type string)
> goremote.go:211: cannot use fun.Name.Name() as type interface { } in
> function argument
> goremote.go:211: too many errors
> make[1]: *** [_go_.8] Error 1
> make[1]: Leaving directory `/home/eric/gocode/goremote'
> make: *** [goremote/goremote] Error 2

Please use "release" branch of the go compiler. These errors will be
fixed when the next go release is here.

Fode

unread,
Aug 17, 2010, 5:31:27 PM8/17/10
to nsf, golan...@googlegroups.com
thanks

nsf

unread,
Aug 25, 2010, 6:38:30 AM8/25/10
to golang-nuts
On Tue, 27 Jul 2010 17:40:08 +0600
nsf <no.smi...@gmail.com> wrote:

> Hello.
>
> I think now it's a good time to introduce my project to public. Last
> few weeks I was working on an autocompletion daemon for the Go
> programming language. And currently it's semicomplete. It is certainly
> in a usable state, but of course it contains bugs and probably will
> not work for all cases. I didn't test it much and it is still in
> development.

Just a quick note regarding the latest Go release. I have merged my
branch with changes for that, but the gocode still requires you to have
all the environment variables. Probably in future this requirement will
be relaxed and the config variable will be added. Basically all gocode
needs to know is this path: $GOROOT/pkg/$GOOS_$GOARCH.

André Moraes

unread,
Aug 25, 2010, 10:58:51 AM8/25/10
to golang-nuts
I don't used your completion, but looks great!

Probably it's one of the things that will help Go adoption.

I will try it when I stop for lunch

Konstantin Levinski

unread,
Sep 6, 2010, 1:15:06 PM9/6/10
to golang-nuts
Good day,

I still have the same already mentioned problem with compiling gocode:
gomake -C goremote
make[1]: Entering directory `/home/yk/gocode2/goremote'
/home/yk/bin/8g -o _go_.8 goremote.go
goremote.go:24: must call t.*Ident·Name
goremote.go:30: must call t.Sel.*Ident·Name
goremote.go:30: cannot use t.Sel.*Ident·Name as type interface { } in
function argument
goremote.go:69: must call name.*Ident·Name
goremote.go:69: cannot use name.*Ident·Name as type interface { } in
function argument
...
etc

with release versions of everything. Another concern - when I pull
your git repo, makefiles mention Make.inc, while it should be Make.
($GOARCH)

I feel I am doing something wrong, but cannot see what exactly.

Care to give any tips?

Thank you,

Konstantin

nsf

unread,
Sep 6, 2010, 2:29:31 PM9/6/10
to golan...@googlegroups.com

You have an old version of the Go compiler.

1. Error message during compilation says that ast.Ident.Name must be a
function, but it was changed to be a variable in one of the latest go
releases. You have an old version of the Go compiler.

2. New Makefile system doesn't require you to set environment
variables, therefore the include file is 'Make.inc'. Again, you have an
old version of the go compiler.

But, in order to use gocode it requires you to have these environment
variables. I guess this requirement will be relaxed in the next Go
release probably and optional config variable will be added (just in
case).

Konstantin Levinski

unread,
Sep 7, 2010, 3:02:32 PM9/7/10
to golang-nuts
Sure, that was the case. Works wonderfully now, thank you!
I missed the hg pull/update part. Maybe minimal compatible compiler
version can be mentioned in readme somewhere, for people to check
their 8g -V.

Konstantin Levinski

unread,
Sep 7, 2010, 3:03:58 PM9/7/10
to golang-nuts
> You have an old version of the Go compiler.

nsf

unread,
Sep 8, 2010, 9:23:56 PM9/8/10
to golang-nuts
Hello, Go users.

Gocode project news. Finally the "renaming" part is semifinished. It of
course requires more testing, but I think it is in a pretty good shape
and probably will work for you. For example I was able to do a lot of
renames in the gocode source code itself. Also I've tested my gomandel
demo and gocode was able to rename each identifier in its code without
breaking compilation.

Ok, what is this all about? Gocode is an autocompletion/refactoring
daemon as you probably heard, but until now the "refactoring" part was
missing. And guess what.. Now it is available. Gocode is able to
rename any identifier in your code preserving semantic information. It
means that if you have a lot of 't' variables in your code, but you
want to rename only one of them, you can do that with gocode! The same
is true for almost any identifier in your code. The exception is:
foreign identifiers (those that came from external packages), you can't
rename them (yet).

Although you have to remember these things when using the 'rename'
function:

1. Gocode 'rename' feature requires that your code is semantically
corrent (e.g. compiles successfully). It doesn't do typechecks for
you. And I didn't want to pursue that, because there is an upcoming
'go/typechecker' library, probably I will be able to integrate that in
future to gocode.

2. Renaming can actually break your code, typical scenarios:
- Changing visibility of the entity by lowering case of the first
letter in its name.
- Changing a method name without changing the corresponding
interface method name.
- For example you have two vars in the same scope: "X" and "Y" if
you will rename "X" to "Y" there will be a conflict after
renaming.
It means that you still have to be careful. Typechecking code after
renaming sessions often using your compiler is a good idea.

3. Gocode uses simple searching mechanism in case if you have a
multifile package. It will scan the directory of a currently editted
file for all the *.go files which have the same package name and parse
them. As a result it won't work with complicated package schemes. For
example if you have one file called _linux.go and other _win32.go and
only one of them should be in the package at a time, gocode will fail.
I'm thinking about introducing the way to handle that, but currently I
have no idea how this may look like. If you have any suggestions - you
know my email.

4. Gocode may contain bugs. Therefore, please.. if you're using this
app, rely on some kind of a source control system (git, hg, svn, etc.)
or simply do backups. I don't want to be a person that is responsible
for your broken code.

--== Demo ==--

And of course I have a demo for you! The demo is rather short this
time. Take a look:

http://nsf.github.com/images/gocode-renaming-demo.swf (350kb)

--== Usage Guide ==--

I think it should be pretty straight forward. Just update your gocode
to the latest git and install as usual (according to README). Rename
vim plugin works that way: simply type ':GocodeRename' when the
cursor is on top of the identifier and the plugin will ask you for a
new name or will tell you that there is nothing to rename (in case if
it can't perform the operation, for example it is not possible to
rename predeclared identifiers for safety reasons).

Important NOTE!: Vim will only rename identifiers in those files that
are available as buffers. So.. if you want to rename an identifier for a
multifile package, you have to open all your package files at once
(e.g. "vim *.go").

If gocode is not able to rename a package local identifier in a
correctly compiled program, or renames it in a wrong way. It's a bug.
See project links below in order to do a bug report.

--== Other Notes ==--

I have to remind you that gocode client/server is editor independent.
The situation is that I am willing to maintain only the vim plugin,
because obviously I use vim. But it would be nice to see contributions
in that area, if you really want to add the support for your favorite
editor, contact me and I will tell what is required in order to do
this.

Hopefully I didn't forget to mention anything else.

--== Project Links ==--

GitHub page: http://github.com/nsf/gocode
Report bugs here: http://github.com/nsf/gocode/issues

P.S. I'm a really lazy testing person, so.. if you've noticed a bug,
please bug report it, I will fix it as soon as possible. Or you can
help me writing tests. :D

LeNsTR

unread,
Sep 9, 2010, 7:36:13 PM9/9/10
to nsf, golang-nuts
This is AWESOME!

Fabio Kaminski

unread,
Sep 10, 2010, 1:26:07 PM9/10/10
to LeNsTR, nsf, golang-nuts
a pity that theres nothing like it for emacs  :(

Anschel

unread,
Sep 11, 2010, 11:02:30 AM9/11/10
to golang-nuts
On Sep 10, 1:26 pm, Fabio Kaminski <fabiokamin...@gmail.com> wrote:
> a pity that theres nothing like it for emacs  :(

From what I understand the underlying autocompletion engine is editor-
agnostic. It's just a matter of someone (maybe you?) writing the
bindings.

nsf

unread,
Sep 11, 2010, 5:25:09 PM9/11/10
to golan...@googlegroups.com

True. It can be done in a day for emacs. As I've mentioned in the
announce message, I just don't want to do that, because I don't use
emacs. Gocode is a hobby project and the best way to pay me for it is a
contribution.

Gustavo Niemeyer

unread,
Sep 18, 2010, 12:22:56 AM9/18/10
to nsf, golan...@googlegroups.com

Hey nsf,

I was just talking today to a coworker about the productivity boosts from tools that display errors in the code on the fly (undefinded or unused variables and packages, etc), and then started imagining that gocode might get there at some point.

Do you already have something like this in your roadmap?

--
Gustavo Niemeyer
http://niemeyer.net

nsf

unread,
Sep 18, 2010, 12:45:30 AM9/18/10
to golan...@googlegroups.com
On Sat, 18 Sep 2010 01:22:56 -0300
Gustavo Niemeyer <gus...@niemeyer.net> wrote:

> Hey nsf,
>
> I was just talking today to a coworker about the productivity boosts from
> tools that display errors in the code on the fly (undefinded or unused
> variables and packages, etc), and then started imagining that gocode might
> get there at some point.
>
> Do you already have something like this in your roadmap?
>
> --
> Gustavo Niemeyer
> http://niemeyer.net

Hi.

Yes, I think it is possible. But currently I can add only syntax
checks. Because I believe Robert Griesemer works on a 'go/typechecker'
library and it will eventually be responsible for semantic checks (like
double declaration, unused variables, etc.). I can try to implement it
by myself using gocode as a base, but I think it's not worth it. I will
see how I can integrate the 'go/typechecker' into the gocode when it's
done.

So.. yes, I have plans like that. Especially I want to add optional
type check phase before and after renaming procedure in order to be
able to guarantee that the code will not be broken after renaming
operation.

Can't say when it will happen.

Reply all
Reply to author
Forward
0 new messages