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 "")
   (cmake "")
   (css "")
   (elisp "")
   (go "")
   (gomod "")
   (dockerfile "")
   (html "")
   (javascript "" "master" "src")
   (json "")
   (make "")
   (markdown "")
   (python "")
   (toml "")
   (tsx "" "master" "tsx/src")
   (typescript "" "master" "typescript/src")
   (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.