GeekSocket Plug in and be Geekified

How to setup Emacs LSP Mode for Go

I use GNU Emacs as my editor, and I use it to write Go code as well. In this blog post I will be talking about basic setup of LSP Mode and gopls to work with Go code.

What is LSP Mode

Before we get to that, What is LSP?

The Language Server Protocol (LSP) defines the protocol used between an editor or IDE and a language server that provides language features like auto complete, go to definition, find all references etc. — Official page for Language Server Protocol

LSP makes it easy for developer tools like editors, IDEs to support different languages. A tool just have to support LSP, and then it can get all the benefits supported by a language’s server. The server and client (developer tool) communicate by passing JSON objects (JSON-RPC). A list of language servers available.

LSP Mode adds support for different language servers to Emacs. The lsp-mode package takes care of starting a correct language server, communicating with it, and for some languages it also supports installing the respective language server. The lsp-ui package provides the functionality of code lenses, showing the documentation or symbol signatures in small popups etc. There are other packages like lsp-java, lsp-pyright which add support for those languages or language servers to LSP Mode. You can find the list of all the supported language servers here.

Installing the language server for Go (gopls)

gopls is the official language server maintained by the Go team. It is pronounced as “Go please”. The Installation section from the documentation explains the process to get gopls. Run the following command from your home directory or any directory other than your GOPATH.

GO111MODULE=on go get golang.org/x/tools/gopls@latest

Make sure that your PATH variable has $GOPATH/bin in it. You can add the following lines to your ~/.bashrc to do so,

export GOPATH="$(go env GOPATH)"
export PATH="${PATH}:${GOPATH}/bin"

The go env GOPATH command returns the current value of the GOPATH variable. The default value is ~/go. If you have already set the GOPATH variable, then you can skip the first line from the above snippet.

On GNU/Linux (on Fedora at least), the GUI Emacs inherits values set in the ~/.bashrc. You might need to logout, login and then start Emacs for the new variables to show up. To check if Emacs can find gopls, press M-: (Alt + :) and run (executable-find "gopls"). It should show the path to the gopls binary in the minibuffer. If that shows nil in your case, you might need to set PATH using setenv function as well as update the value of exec-path. Take a look at Emacs: Set Environment Variables within Emacs for more details.

Installing the required Emacs packages

Before setting up LSP Mode, I was using go-mode to get highlighting and jump to definition for Go files. With Go Modules, go-mode’s jump to definition started having some issues (godef#114).

Following packages are required to setup LSP Mode. You can install them by running M-x package-install RET <package name> RET. You will also need to enable MELPA (snippet from my configuration).

Emacs configuration

The gopls documentation has a recommended configuration for Emacs which is available here. This is a snippet from my configuration (taken from the gopls documentation page),

;; Company mode
(setq company-idle-delay 0)
(setq company-minimum-prefix-length 1)

;; Go - lsp-mode
;; Set up before-save hooks to format buffer and add/delete imports.
(defun lsp-go-install-save-hooks ()
  (add-hook 'before-save-hook #'lsp-format-buffer t t)
  (add-hook 'before-save-hook #'lsp-organize-imports t t))
(add-hook 'go-mode-hook #'lsp-go-install-save-hooks)

;; Start LSP Mode and YASnippet mode
(add-hook 'go-mode-hook #'lsp-deferred)
(add-hook 'go-mode-hook #'yas-minor-mode)

Let’s take a look at each section now.

We are setting company-mode’s variables to show the completion popup, immediately after typing one character.

Then we are defining a function lsp-go-install-save-hooks which adds formatting related function to before-save-hook. This instructs Emacs to run these function before saving a buffer.

We are adding the lsp-go-install-save-hooks function to go-mode-hook. This function gets called when go-mode is activated in a buffer (opening a Go file activates go-mode).

At the end, we are calling lsp-deferred and activating yas-minor-mode when go-mode is activated. The lsp-deferred function takes care of starting the language server (gopls), setting up company-mode, lsp-ui etc.

Once you add the above configuration to your .emacs, run M-x eval-buffer.

Wondering about those #' before function names? Read about them in Get in the habit of using sharp quote by Artur Malabarba.

Testing it out

To test this setup, create a new directory and a main.go file in it. As soon as you open the file, you will see that the modeline has LSP[gopls:4096545]. This means LSP Mode has successfully started and connected to gopls process with PID 4096545. If you start typing now, the auto-completion should work 🎉

Some keybindings and functions

You can use M-. to jump to the definition of a symbol and M-, to get back. Run M-x lsp-find-references to get a list of places where the current symbol is used. The lsp-rename can be used to rename a symbol at all the places.

Checkout the Main features page of LSP Mode documentation to know what else is possible.


Comments

comments powered by Disqus