I’ve been Emacs user since around ~2014, I used to maintain my own Emacs config and publish it (I also would flash custom roms on my android phones). With time, I yearned more for stability. So I switched to an Emacs framework: Centaur Emacs. This allowed me to continue using Emacs without having to worry about a broken config, as it was well maintained.
With time, I realized I was adding a lot more on top of Centaur Emacs as my own config. So again, I switched to Doom Emacs, which supported a lot more modules than Centaur and also saw more community contributions (chicken-egg problem). Today let’s go (pun! hehe) over the additional config I have written over the defaults provided by Doom Emacs for Go development.
Do you see the pattern here? While one perspective is that Emacs always requires tinkering. The more realistic perspective is that Emacs is all about customization, even when using a framework like Doom Emacs, users can always modify it to their requirements and preferences.
Go in Doom Emacs Link to heading
Doom Emacs comes with pre-built modules for Go, to enable it all we need to do is add the following to your doom/init.el
file:
(go +lsp)
The README in the Go modules folder, lists the pre-requisites to be installed. It also recommends using gopls
. gopls is the official Go language server developed by the Go team.
LSP is an editor agnostic protocol, which allows editors to be linked to language servers and utilize them for features such as syntax checks, code-navigation, linting and so on. Before editors used to implement each of these functionalities from scratch for different languages/frameworks, with LSP, they could simply make RPC calls to the language server installed on the users system.
To install gopls
, we can simply use go install
:
go install golang.org/x/tools/gopls@latest
This is already a fully usable setup. This will provide all the functionality you expect from a modern editor (code completion, code navigation, syntax checking, linting). But we can fine tune some things to make it better for Go development.
Format Buffer Link to heading
Go projects follow gofmt
for formatting. So it’d be nice if we could get Emacs to auto-format before saving. Both gopls
and Emacs’s lsp-mode support buffer formatting via the lsp-format-buffer
command. Doom Emacs abstracts this for us behind the +format/buffer-or-region
command.
Either of these commands can be used or we could also add the +format-buffer-h
command to the before-save-hook
hook, so it automatically does this before saving. The simplest option is to add to the following to ~/.doom.d/init.el
:
(format +onsave)
This automatically formats buffers before saving. _Note: This applies for all major modes and not just Go.
Organize Imports Link to heading
To organize imports one could manually run lsp-organize-imports
. I prefer running this automatically as a hook just before saving a file. To do this, add the following to your ~/.doom.d/config.el
:
(add-hook 'go-mode-hook #'lsp-deferred)
;; Make sure you don't have other goimports hooks enabled.
(defun lsp-go-install-save-hooks ()
(add-hook 'before-save-hook #'lsp-organize-imports t t))
(add-hook 'go-mode-hook #'lsp-go-install-save-hooks)
Gofumpt Link to heading
I prefer using gofumpt over the standard gofmt, if you do so too, then you can simply ask lsp to use gofumpt by adding this to your ~/.doom.d/config.el
:
|
|
Analyzers Link to heading
By default, gopls
doesn’t enable all analyzers. You can find the list of analyzers and their default values here. Some of the analyzers I manually enable are:
- fieldalignment: find structs that would use less memory if their fields were sorted
- nilness: check for redundant or impossible nil comparisons
- shadow: check for possible unintended shadowing of variables
- unusedparams: check for unused parameters of functions
- unusedwrite: checks for unused writes
- useany: check for constraints that could be simplified to “any”
- unusedvariable: check for unused variables
To enable these, we add the following to ~/.doom.d/config.el
:
(after! lsp-mode
(setq lsp-go-analyses '((fieldalignment . t)
(nilness . t)
(shadow . t)
(unusedparams . t)
(unusedwrite . t)
(useany . t)
(unusedvariable . t)))
)
Tree-sitter Link to heading
Emacs generally uses regular expressions for parsing languages, this is slow and inaccurate at times. Tree-sitter is a parser generator tool and an incremental parsing library. It was also merged into Emacs 29. To use tree-sitter in Emacs, first add the following to ~/.doom.d/config.el
file’s :tools
section:
tree-sitter
Also modify Go to use tree-sitter by modifying ~/.doom.d/config.el
:
(go +lsp +tree-sitter)
Summary Link to heading
That’s it! Not much configuration over the default doom setup. Certain changes I would be looking forward to:
- Some of the analyzer being set to default true, so we can skip them.
- Since tree-sitter is merged into Emacs, we shouldn’t be required to enable it anymore.
- elgot, which is an alternative for lsp-mode also got merged into Emacs, curious how this will all play out.
This is post 003 of #100DaysToOffload.