Configuring Emacs 29.1 for Go Development
Now that I have installed Emacs 29.1, I needed to get it set up for Go development for a project. I was interested in taking advantage of both the new Tree-Sitter integration, and the new Eglot language server client. However, they were mildly tricky to set up! Here is what I did.
Configuring Tree-Sitter for Go
If you follow the excellent How to Get Started with Tree-Sitter instructions from Mickey Peterson, you will have a great head-start on getting Tree-Sitter working for most of your favorite languages (and probably Java, too). However, those instructions didn’t cover everything I needed for Go. When I tried running M-x go-ts-mode
, Emacs complained about a missing gomod
module. Baffling!
I couldn’t find any information in the Emacs documentation about where to find this missing module. I looked around on the net and found Camden Cheek’s tree-sitter-go-mod, and added that to my list of recipes. My treesit-language-source-alist
then looked like this:
(setq treesit-language-source-alist
'((bash "https://github.com/tree-sitter/tree-sitter-bash")
(cmake "https://github.com/uyha/tree-sitter-cmake")
(css "https://github.com/tree-sitter/tree-sitter-css")
(elisp "https://github.com/Wilfred/tree-sitter-elisp")
(go "https://github.com/tree-sitter/tree-sitter-go")
(gomod "https://github.com/camdencheek/tree-sitter-go-mod")
(dockerfile "https://github.com/camdencheek/tree-sitter-dockerfile")
(html "https://github.com/tree-sitter/tree-sitter-html")
(javascript "https://github.com/tree-sitter/tree-sitter-javascript" "master" "src")
(json "https://github.com/tree-sitter/tree-sitter-json")
(make "https://github.com/alemuller/tree-sitter-make")
(markdown "https://github.com/ikatyang/tree-sitter-markdown")
(python "https://github.com/tree-sitter/tree-sitter-python")
(toml "https://github.com/tree-sitter/tree-sitter-toml")
(tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src")
(typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")
(yaml "https://github.com/ikatyang/tree-sitter-yaml")))
Note that the package is named go-mod
but go-ts-mode
expects it to be named gomod
. I wish this were documented somewhere! In any case, I was then able to use M-x treesit-install-language-grammar
for both go
and gomod
. Finally, M-x go-ts-mode
worked!
After going through this process, I found Robert Enzmann’s post about automatically using Tree-Sitter. He has created the treesit-auto
package, now available on MELPA, that does most of this work for you. It is a much faster way of solving the gomod
mystery, so give it a shot!
Configuring Eglot for Go
I’d been using lsp-mode for ages, but with Emacs 29.1 including Eglot, I decided to make the switch.
In my Go project, I ran M-x eglot
and was immediately met with an error:
[eglot] Server reports (type=1): Error loading workspace folders (expected 1, got 0)
failed to load view for file:///path/to/my/project: err: go command required, not found: exec: "go": executable file not found in $PATH: stderr:
I’ve got Go installed in /usr/local/go
, and /usr/local/go/bin
is definitely in my exec-path
variable in Emacs. It looked like Eglot wasn’t propagating exec-path
down to its subprocesses. How annoying! I did a quick search through the list of Eglot-related variables and the Eglot documentation and no solution seemed immediately forthcoming.
So I took the cheap way out and made a symlink. In my shell, I ran:
sudo ln -sf /usr/local/go/bin/go /usr/local/bin/go
It is a dumb trick, and I am sure there is a better way to solve it. Do you know of one? Please comment and let me know!
What Else?
My exploration has revealed that there’s a lot of work left to do in the Emacs Tree-Sitter world. There are plenty of languages major modes that don’t yet have a ts-mode
equivalent, and plenty of others that still need a lot of work.
It’s too soon for me to say if this setup is preferrable to my previous configuration. But I am really looking forward to playing around with Eglot’s features and exploring the capabilities of Tree-Sitter.