A minimal implementation of Golang development plugin written in Lua for Neovim.
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.
- 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).
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 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.document_symbol()andvim.lsp.buf.workspace_symbol() - 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 disableauto_lintif this works well with your project.
For details of gopls, please refer to https://github.com/golang/tools/blob/master/gopls/doc/design/design.md#features.
Prerequisites:
- Neovim (>= 0.7)
- npm (for quicktype)
Install with your favorite package manager:
" 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.
Install
quicktypewithyarnorpnpm:
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)-- setup nvim-go
require('go').setup({})
-- setup lsp client
require('lspconfig').gopls.setup({})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 = {},
-- lint_prompt_style: qf (quickfix), vt (virtual text)
lint_prompt_style = 'qf',
-- formatter: goimports, gofmt, gofumpt, lsp
formatter = 'goimports',
-- maintain cursor position after formatting loaded buffer
maintain_cursor_pos = 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,
test_popup_auto_leave = false,
test_popup_width = 80,
test_popup_height = 10,
-- test open
test_open_cmd = 'edit',
-- struct tags
tags_name = 'json',
tags_options = {'json=omitempty'},
tags_transform = 'snakecase',
tags_flags = {'-skip-unexported'},
-- quick type
quick_type_flags = {'--just-types'},
})Display within Neovim with:
:help nvim-gofunction! LintIssuesCount()
if exists('g:nvim_go#lint_issues_count')
return g:nvim_go#lint_issues_count
endif
endfunction
call airline#parts#define_function('nvim_go', 'LintIssuesCount')
call airline#parts#define_condition('nvim_go', '&filetype == "go"')
let g:airline_section_warning = airline#section#create_right(['nvim_go'])function! LintIssuesCount()
if exists('g:nvim_go#lint_issues_count') && &filetype == 'go'
return g:nvim_go#lint_issues_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['nvim_go#lint_issues_count'] ~= nil
then
return vim.g['nvim_go#lint_issues_count']
else
return ''
end
end,
},
-- ...
}augroup NvimGo
autocmd!
autocmd User NvimGoLintPopupPost wincmd p
augroup ENDOr equivalently:
local NvimGo = vim.api.nvim_create_augroup("NvimGo", {
clear = true,
})
vim.api.nvim_create_autocmd({ "User" }, {
pattern = "NvimGoLintPopupPost",
group = NvimGo,
command = "wincmd p",
})