Writing Go in Emacs
Using the right tools plays a big role in getting your job done efficiently. In the case of programming Go, most of your time will be spent in an editor. It is therefore key that your editor doesn’t get in your way and, optimally, assists you wherever it can.
In this article, I will talk about go-mode for Emacs, its history and features, as well as useful extensions to it.
Even though this article is targeted at Emacs users, parts of it, mainly the feature list, might be of interest to users of other editors as well, to see what’s possible and to adopt some of the ideas. You will want to skip the History and Obtaining it sections though.
History of go-mode ¶
Go has been including a mode for Emacs for a long time now. Until recently, however, it was rather fragile. It regularly messed up indentation or syntax highlighting, for quite some time it could completely lock up your editor and it didn’t feel really integrated in Emacs, lacking support for functions like `beginning-of-defun`. It also didn’t include a lot of extra features.
All in all, it was better than having to use nano, but not by much.
All that changed around February this year, when I rewrote the mode from scratch. I took special care to build it on top of a solid foundation, making use of Emacs’s parsing facilities, as opposed to the previous version of the mode, which implemented its own parser. Apart from generally bug-free behavior, this also allowed building a lot of functions on top of it.
Obtaining it ¶
There are two ways of obtaining go-mode and both are very similar. The first way is using the one that comes with the Go distribution itself, the second way is to get it from GitHub, where I push all new changes before they find their way into the Go repository.
When using the one that comes bundled with Go, be sure to use the one that comes with tip, the development version of Go. The current release, 1.0.3, includes the old, outdated version of go-mode.
If using go-mode from Go tip, put both
go-mode-load.el into a directory of your choice, add it to
Emacs’s load paths via
(add-to-list 'load-path "/place/where/you/put/it")
and require it via
This will install autoload entries and associate
*.go files with go-mode.
If using go-mode from the git repository, the procedure is similar, but requires an additional step to generate the
go-mode-load.el file. From within Emacs, run
M-x update-file-autoloads, point it at the
go-mode.el file and tell
it to generate a
go-mode-load.el file. From that point on the procedure is the same as before.
For Emacs, a programming mode is often about more than just indentation and syntax highlighting. Integration with the tools of the language is often key, easy navigation of code, even crossing package boundaries, is appreciated and some people even rely on on-the-fly syntax checking.
go-mode, either directly or by using the work of others, offers all of this and more.
We’ll discover how to read documentation, format and navigate code, how to use Go’s own pastebin, how to get syntax checking, autocompletion and snippets.
Reading documentation ¶
godoc function, you can invoke the identically named Go tool from within Emacs and read package
documentation in a view-mode buffer. Additional feature: You can tab complete import paths.
Formatting code ¶
Maybe one of the most important tools of Go is gofmt, which automatically formats your code to the one true coding style, used by every Go developer.
In Emacs, there are two ways to use gofmt. One way is to invoke gofmt manually with the identically named function
gofmt, which will patch the current buffer according to gofmt. The other way is to use a before-save-hook to run
gofmt every time you save a Go buffer. Enabling that hook is as easy as doing
(add-hook 'before-save-hook 'gofmt-before-save)
If you have used this hook before and complained about your cursor jumping around, don’t worry: This has been fixed in the new go-mode. At the very most, your cursor will be placed on the beginning of the current line, if it had to be reformatted.
Managing imports ¶
On a first glance, managing imports in Go doesn’t seem like much of a deal. You either add import statements at the top of your file or you remove them. But when rapidly developing a new application, this can cause a lot of jumping around. Did you just realize that you forgot to import the fmt package? Previously, this meant going to the beginning of the buffer, advancing to the block of import statements (if it existed yet), going to its end and adding your new import. And when you realized you didn’t need it after all, you had to repeat the same procedure to remove it again.
The new go-mode has three functions for working with imports:
go-import-add, bound to
C-c C-a by default, will prompt you for an import path (again supporting tab completion) and
insert it in the import block, creating it if necessary. If an import already existed but was commented, it will be
If prefixed with
C-u, it will ask you for an alias, too. An annoying procedure of moving around and mental context
switching has just been reduced to a keystroke.
Instead of offering a function for removing a single import, go-mode will detect all unused imports and delete them (or
comment them) once you run
go-remove-unused-imports. It is not bound to a key by default, but you can bind it yourself
if you want to. Personally I have bound it to
(add-hook 'go-mode-hook (lambda () (local-set-key (kbd "C-c C-r") 'go-remove-unused-imports)))
If you decide you want to look at your imports or edit them manually, go-goto-imports will take you to them automatically, placing your cursor after the last import. It isn’t bound to a key, either, mainly because I couldn’t come up with a good default that didn’t violate Emacs guidelines. But you can bind it manually, just like before:
(add-hook 'go-mode-hook (lambda () (local-set-key (kbd "C-c i") 'go-goto-imports)))
Navigating code ¶
Also important for efficient programming is quick navigation of code.
go-goto-imports was only the tip of the iceberg.
C-M-e), two core Emacs functions for navigating
between functions. Additionally, functions such as
mark-defun rely on these two functions.
If that isn’t enough, you can also use Imenu to jump to specific function or type declarations.
Even if you long for a feature that’s usually only provided by IDEs, or by making use of etags, namely jumping to the declaration of a symbol under your cursor, go-mode got you covered.
go-mode integrates with godef, an amazing little tool written by Roger Peppe. godef is able to parse your code, and the code of other packages, and the code of the Go standard library, and can tell you what exactly the symbol you’re looking at means and where it has been defined.
go-mode makes use of this to provide the two functions
godef-describe will tell you
what you’re looking at, while
godef-jump will take you to its definition. And yes, this works across files, packages
and into the standard library, without needing any tags. And it has almost no measurable delay.
godef-describe is bound to
C-c C-d and
godef-jump is bound to
C-c C-j. If you want to, you can bind
M-., which is the default key for
find-tag, something you might already be using for other programming languages:
(add-hook 'go-mode-hook (lambda () (local-set-key (kbd \"M-.\") 'godef-jump)))
There are two important notes:
Update (2013-03-19): The godef features in go-mode are now part of the Go repository. As of writing this article, the godef functions haven’t reached the Go repository yet. They are only available in the git version. This will hopefully change in the next couple of days.
You will obviously need to install godef, which is as easy as doing
go get code.google.com/p/rog-go/exp/cmd/godef.
Interacting with the Playground ¶
Go has its own pastebin, called the Playground. When asking for help with code, or sharing solutions to those who need help, it is often expected to use the Playground, especially because it can execute code.
It makes sense that go-mode integrates with the Playground. It offers
go-play-region to send the
current buffer or region to the Playground and store a link in your kill ring.
It can also directly download a paste from the Playground into Emacs, by using
On-the-fly syntax checking ¶
FlyMake is Emacs’s solution to on-the-fly syntax checking. Many programming modes offer support for it (some more easily than others).
In the case of Go, Doug MacEachern wrote goflymake, which consists of a small Go binary and some elisp to integrate it with Emacs. Because Go compiles blazingly fast, using goflymake doesn’t cause any performance penalties. Personally I am letting FlyMake compile my Go buffers every time I insert a newline. More conservative settings would compile after a certain amount of idle time, or when saving the buffer.
gocode, written by nsf, provides the kind of autocompletion that you might know from IDEs. It provides context-sensitive autocompletion and works across a variety of editors, including Emacs. The project’s README includes detailed installation instructions.
Note: it suggests using auto-complete-mode and mentions company-mode as an alternative. Personally I recommend trying company-mode first. auto-complete-mode isn’t as lightweight and can be harder to configure.
Some people like them, some think they’re useless: Snippets. Short words that, upon pressing TAB, turn into longer words, sentences or code constructs. One of the more popular implementations of snippets for Emacs is YASnippet, and it is YASnippet that I wrote a small number of Go snippets for.
Finding unchecked errors with go-errcheck ¶
Last but not least, there’s go-errcheck, offering Emacs integration for errcheck. errcheck is a tool written by Kamil Kisiel for finding and reporting unchecked errors in your Go code.
go-errcheck offers the
go-errcheck function, which will run errcheck on the current package and report errors in a
compilation buffer. Additionally, it supports setting errcheck flags on a default and per-package basis.
I hope I was able to give you a good overview of the features that you can enjoy while writing Go code in Emacs. If I forgot any cool packages, or if you have suggestions or comments, please leave me a message. Check the contact page to find ways of contacting me.