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.
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.
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.
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).
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.
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 ๐
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 are not enabled on this site. The old comments might still be displayed. You can reply on one of the platforms listed in โPosted onโ list, or email me.