How I Setup Go With Vim
Tags: go, vim
Published: 2021-05-20 08:53:56

---
title: How I Setup Go With Vim
published: true
date: 20/05/2021
tags: Go, vim
canonical_url: https://www.rockyourcode.com/how-i-setup-go-with-vim/
cover_image: https://www.rockyourcode.com/static/img/2021-05-20-gopher.png
---

> Language Server Support for Go in Vim

Last month I found a [reddit thread about how to setup Vim for Go development][reddit].

The [author][preslav] uses coc.nvim, a heavy-weight plugin with external dependencies. coc.nvim ("Conqueror of Completion") offers powerful features, but you'll need to install Node.js.  
If you prefer a more lightweight option that also work with plain Vim, this blog post might be for you.

Today I'm going to share my setup:

- works with Vim and NeoVim
- minimal external dependencies ([gopls][gopls])
- auto-completion support

## Prerequisites

You should have [a working installation of Go on your computer][goinstall].

Install [gopls][gopls], the official language server:

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

## Vim Setup

Vim needs a plugin for the [Language Server Protocol][lsp].

I use **[prabirshrestha/vim-lsp][vim-lsp]**, an asynchronous implementation that works both in Vim 8 and NeoVim. The plugin uses VimL and thus has no external dependencies.

Install with [native package support][nativepackage] or a plugin manager of your choice. Example:

```bash
cd ~/vim/pack
git submodule init
git submodule add https://github.com/prabirshrestha/vim-lsp.git
git add .gitmodules vim/pack/prabirshrestha/vim-lsp
git commit
```

(I'm happy with [vim-packager][vimpackager], but configuring it requires a bit more effort and time. The native package manager works well since Vim 8, but is a bit clunky.)

Let's wire up the language server with Go.

Create a new file in your Vim folder (`~/vim/plugin/lsp.vim`) with the following content:

```bash
func! s:setup_ls(...) abort
    let l:servers = lsp#get_allowed_servers()

    # key mappings
    for l:server in l:servers
        let l:cap = lsp#get_server_capabilities(l:server)

        if has_key(l:cap, 'completionProvider')
            setlocal completefunc=lsp#complete
        endif

        if has_key(l:cap, 'hoverProvider')
            setlocal keywordprg=:LspHover
        endif

        if has_key(l:cap, 'codeActionProvider')
            nmap <silent><buffer>ga <plug>(lsp-code-action)
        endif

        if has_key(l:cap, 'definitionProvider')
            nmap <silent><buffer>gd <plug>(lsp-definition)
            nmap <silent><buffer>gk <plug>(lsp-peek-definition)
        endif
    endfor
endfunc

# register language server
augroup LSC
    autocmd!
    autocmd User lsp_setup call lsp#register_server({
                \ 'name': 'gopls',
                \ 'cmd': {_->['gopls']},
                \ 'allowlist': ['go']
                \})

    autocmd User lsp_server_init call <SID>setup_ls()
    autocmd BufEnter * call <SID>setup_ls()
augroup END

# disable diagnostics etc.
let g:lsp_diagnostics_enabled                = 0
let g:lsp_diagnostics_signs_enabled          = 0
let g:lsp_diagnostics_virtual_text_enabled   = 0
let g:lsp_diagnostics_highlights_enabled     = 0
let g:lsp_document_code_action_signs_enabled = 0
```

The first function creates key bindings if the language server runs. For example, hitting `ga` will give you "code actions". The most useful code action is auto-importing the necessary definitions. Code Actions are a feature I use a lot.

You can find a list of supported commands on the [vim-lsp GitHub page](https://github.com/prabirshrestha/vim-lsp#supported-commands).

### Auto-completion?

Vim already has auto-completion [out of the box][letvimdothetyping].

Here is an excerpt from some extra key mappings in my `~/.vimrc` ("stolen" from [bluz71](https://github.com/bluz71/dotfiles/blob/master/vim/custom/mappings.vim):

```vim
"-----------------------------
" completion mappings
"-----------------------------
"   t     - user defined completion (via completefunc setting)
inoremap <C-t>     <C-x><C-u>
```

Now, when I want the language server to kick in to complete my Go code, I smash `CTRL+T` on my keyboard.

## How to Format And Lint

The easiest way is to use the [gofmt][gofmt] tool from the command-line. For example,

```bash
gofmt -w .
```

The same goes for linting.

Install [golint][golint]:

```bash
go install golang.org/x/lint/golint@latest
```

Usage:

```bash
golint ./...
```

Alternatively, you can install [ALE][ale]. Here is an [example setup](https://bluz71.github.io/2017/05/21/vim-plugins-i-like.html#ale) which you can adjust for Go.


## Conclusion

I've showed you a lightweight setup for Go and Vim. The above plugins and settings have served me well.

There are languages where I'd recommend a dedicated IDE (Java), but for Go I haven't felt the need yet.

## Links

- [How to set up Vim for Go Development][preslav] (on [reddit][reddit])
- [Vim: So long Pathogen, hello native package loading][nativepackage]
- [Let Vim do the typing][letvimdothetyping]
- [vim-lsp][vim-lsp]

[reddit]: https://reddit.com/r/golang/comments/mon9ym/how_to_setup_vim_for_go_development/
[preslav]: https://pmihaylov.com/vim-for-go-development/
[gopls]: https://github.com/golang/tools/blob/master/gopls/README.md
[goinstall]: https://golang.org/doc/install
[vim-lsp]: https://github.com/prabirshrestha/vim-lsp
[nativepackage]: https://shapeshed.com/vim-packages/
[lsp]: https://github.com/Microsoft/language-server-protocol
[vimpackager]: https://www.rockyourcode.com/installing-and-managing-vim-plugins-with-vim-packager/
[gofmt]: https://golang.org/cmd/gofmt/
[golint]: https://pkg.go.dev/github.com/360EntSecGroup-Skylar/goreporter/linters/golint
[ale]: https://github.com/dense-analysis/ale
[letvimdothetyping]: https://georgebrock.github.io/talks/vim-completion/