Vim / Neovim

vim-go

Use vim-go ver 1.20+, with the following configuration:

let g:go_def_mode='gopls'
let g:go_info_mode='gopls'

LanguageClient-neovim

Use LanguageClient-neovim, with the following configuration:

" Launch gopls when Go files are in use
let g:LanguageClient_serverCommands = {
       \ 'go': ['gopls']
       \ }
" Run gofmt on save
autocmd BufWritePre *.go :call LanguageClient#textDocument_formatting_sync()

Ale

Use ale:

let g:ale_linters = {
  \ 'go': ['gopls'],
  \}

see this issue

vim-lsp

Use prabirshrestha/vim-lsp, with the following configuration:

augroup LspGo
  au!
  autocmd User lsp_setup call lsp#register_server({
      \ 'name': 'go-lang',
      \ 'cmd': {server_info->['gopls']},
      \ 'whitelist': ['go'],
      \ })
  autocmd FileType go setlocal omnifunc=lsp#complete
  "autocmd FileType go nmap <buffer> gd <plug>(lsp-definition)
  "autocmd FileType go nmap <buffer> ,n <plug>(lsp-next-error)
  "autocmd FileType go nmap <buffer> ,p <plug>(lsp-previous-error)
augroup END

vim-lsc

Use natebosch/vim-lsc, with the following configuration:

let g:lsc_server_commands = {
\  "go": {
\    "command": "gopls serve",
\    "log_level": -1,
\    "suppress_stderr": v:true,
\  },
\}

The log_level and suppress_stderr parts are needed to prevent breakage from logging. See issues #180 and #213.

coc.nvim

Use coc.nvim, with the following coc-settings.json configuration:

  "languageserver": {
    "golang": {
      "command": "gopls",
      "rootPatterns": ["go.work", "go.mod", ".vim/", ".git/", ".hg/"],
      "filetypes": ["go"],
      "initializationOptions": {
        "usePlaceholders": true
      }
    }
  }

If you use go.work files, you may want to set the workspace.workspaceFolderCheckCwd option. This will force coc.nvim to search parent directories for go.work files, even if the current open directory has a go.mod file. See the coc.nvim documentation for more details.

Other settings can be added in initializationOptions too.

The editor.action.organizeImport code action will auto-format code and add missing imports. To run this automatically on save, add the following line to your init.vim:

autocmd BufWritePre *.go :call CocAction('runCommand', 'editor.action.organizeImport')

govim

In vim classic only, use the experimental govim, simply follow the install steps.

Neovim v0.5.0+

To use the new native LSP client in Neovim, make sure you install Neovim v.0.5.0+, the nvim-lspconfig configuration helper plugin, and check the gopls configuration section there.

Installation

You can use Neovim's native plugin system. On a Unix system, you can do that by cloning the nvim-lspconfig repository into the correct directory:

dir="${HOME}/.local/share/nvim/site/pack/nvim-lspconfig/opt/nvim-lspconfig/"
mkdir -p "$dir"
cd "$dir"
git clone 'https://github.com/neovim/nvim-lspconfig.git' .

Custom Configuration

You can add custom configuration using Lua. Here is an example of enabling the unusedparams check as well as staticcheck:

lua <<EOF
  lspconfig = require "lspconfig"
  lspconfig.gopls.setup {
    cmd = {"gopls", "serve"},
    settings = {
      gopls = {
        analyses = {
          unusedparams = true,
        },
        staticcheck = true,
      },
    },
  }
EOF

Imports

To get your imports ordered on save, like goimports does, you can define a helper function in Lua:

lua <<EOF
  -- 

  function goimports(timeout_ms)
    local context = { only = { "source.organizeImports" } }
    vim.validate { context = { context, "t", true } }

    local params = vim.lsp.util.make_range_params()
    params.context = context

    -- See the implementation of the textDocument/codeAction callback
    -- (lua/vim/lsp/handler.lua) for how to do this properly.
    local result = vim.lsp.buf_request_sync(0, "textDocument/codeAction", params, timeout_ms)
    if not result or next(result) == nil then return end
    local actions = result[1].result
    if not actions then return end
    local action = actions[1]

    -- textDocument/codeAction can return either Command[] or CodeAction[]. If it
    -- is a CodeAction, it can have either an edit, a command or both. Edits
    -- should be executed first.
    if action.edit or type(action.command) == "table" then
      if action.edit then
        vim.lsp.util.apply_workspace_edit(action.edit)
      end
      if type(action.command) == "table" then
        vim.lsp.buf.execute_command(action.command)
      end
    else
      vim.lsp.buf.execute_command(action)
    end
  end
EOF

autocmd BufWritePre *.go lua goimports(1000)

(Taken from the discussion on Neovim issue tracker.)

Omnifunc

To make your Ctrl+x,Ctrl+o work, add this to your init.vim:

autocmd FileType go setlocal omnifunc=v:lua.vim.lsp.omnifunc

Additional Links