A minimal implementation of Golang development plugin for Neovim
nvim-go
A minimal implementation of Golang development plugin written in Lua for Neovim.
Introduction
Neovim (from v0.5) embeds a built-in Language Server Protocol (LSP) client. And Debug Adapter Protocol (DAP) are also brought into Neovim as a general debugger. With the power of them, we are able to easily turn Neovim into a powerful editor.
nvim-go is designed to collaborate with them, provides sufficient features, and leverages community toolchains to get Golang development done.
Features
- Auto format with
:GoFormat(viagoimports,gofmt,gofumptandlsp) when saving. - Run linters with
:GoLint(viarevive) automatically. - Quickly test with
:GoTest,:GoTestFunc,:GoTestFileand:GoTestAll. Generate test with:GoAddTest. - Import packages with
:GoGetand:GoImport. - Modify struct tags with
:GoAddTags,:GoRemoveTags,:GoClearTags,:GoAddTagOptions,:GoRemoveTagOptionsand:GoClearTagOptions. - Generates JSON models with
:GoQuickType(viaquicktype). - Generate if err based on function return values with
:GoIfErr(viaiferr).
Recommended Features
This section can be regarded as a guide or common practice to develop with nvim-go, LSP (gopls) and DAP. If you are familiar with these tools or other equivalent, you may skip this chapter.
<Show/Hide the guide>
Language Server
Language server provides vital language features to make Golang development easy. We highly recommend you to use LSP client together with nvim-go.
- Setup
goplswith neovim/nvim-lspconfig. - Setup your favorite completion engine such as nvim-cmp.
- Setup and map the following methods based on what you need:
- Declaration:
vim.lsp.buf.declaration() - Definition:
vim.lsp.buf.definition()andvim.lsp.buf.type_definition() - Implementation:
vim.lsp.buf.implementation() - Hover:
vim.lsp.buf.hover() - Signature:
vim.lsp.buf.signature_help() - References:
vim.lsp.buf.reference() - Symbols:
vim.lsp.buf.documentsymbol()andvim.lsp.buf.workspacesymbol() - Rename:
vim.lsp.buf.rename() - Format:
vim.lsp.buf.format(), also works withGoFormat. - Diagnostic:
vim.diagnosticwill also show lint issues with Virtual Text, which runsgo/analysis. You may disableautolintif this works well with your project.
gopls, please refer to Debugger
Installation
Prerequisites:
- Neovim (>= 0.7)
- npm (for quicktype)
" dependencies
use('nvim-lua/plenary.nvim')
" nvim-go use('crispgm/nvim-go')
" (optional) if you enable nvim-notify use('rcarriga/nvim-notify')
" (recommend) LSP config use('neovim/nvim-lspconfig')
Finally, run :GoInstallBinaries after plugin installed.
Installquicktypewithyarnorpnpm:
nvim-go install quicktype with npm by default, you may replace it with yarn or pnpm.
require('go').config.update_tool('quicktype', function(tool)
tool.pkg_mgr = 'yarn'
end)
Usage
Setup
-- setup nvim-go
require('go').setup({})
-- setup lsp client require('lspconfig').gopls.setup({})
Defaults
require('go').setup({
-- notify: use nvim-notify
notify = false,
-- auto commands
auto_format = true,
auto_lint = true,
-- linters: revive, errcheck, staticcheck, golangci-lint
linter = 'revive',
-- linter_flags: e.g., {revive = {'-config', '/path/to/config.yml'}}
linter_flags = {},
-- lintpromptstyle: qf (quickfix), vt (virtual text)
lintpromptstyle = 'qf',
-- formatter: goimports, gofmt, gofumpt, lsp
formatter = 'goimports',
-- maintain cursor position after formatting loaded buffer
maintaincursorpos = false,
-- test flags: -count=1 will disable cache
test_flags = {'-v'},
test_timeout = '30s',
test_env = {},
-- show test result with popup window
test_popup = true,
testpopupauto_leave = false,
testpopupwidth = 80,
testpopupheight = 10,
-- test open
testopencmd = 'edit',
-- struct tags
tags_name = 'json',
tags_options = {'json=omitempty'},
tags_transform = 'snakecase',
tags_flags = {'-skip-unexported'},
-- quick type
quicktypeflags = {'--just-types'},
})
Manual
Display within Neovim with:
:help nvim-go
Advanced Configuration
Statusline Count
function! LintIssuesCount()
if exists('g:nvimgo#lintissues_count')
return g:nvimgo#lintissues_count
endif
endfunction
call airline#parts#definefunction('nvimgo', 'LintIssuesCount')
call airline#parts#definecondition('nvimgo', '&filetype == "go"')
let g:airlinesectionwarning = airline#section#createright(['nvimgo'])
function! LintIssuesCount()
if exists('g:nvimgo#lintissues_count') && &filetype == 'go'
return g:nvimgo#lintissues_count
endif
endfunction
let g:lightline = {
\ 'colorscheme': 'wombat',
\ 'active': {
\ 'left': [ [ 'mode', 'paste' ],
\ [ 'readonly', 'filename', 'modified', 'lintcount' ] ]
\ },
\ 'component_function': {
\ 'lintcount': 'LintIssuesCount'
\ },
\ }
require('hardline').setup({
-- ...
sections = {
{
class = 'error',
item = function()
if
vim.bo.filetype == 'go'
and vim.g['nvimgo#lintissues_count'] ~= nil
then
return vim.g['nvimgo#lintissues_count']
else
return ''
end
end,
},
-- ...
}
Show Lint Issues without Focusing
augroup NvimGo
autocmd!
autocmd User NvimGoLintPopupPost wincmd p
augroup END
Or equivalently:
local NvimGo = vim.api.nvimcreateaugroup("NvimGo", {
clear = true,
})
vim.api.nvimcreateautocmd({ "User" }, {
pattern = "NvimGoLintPopupPost",
group = NvimGo,
command = "wincmd p",
})