Set my entire Neovim config to:
call lsp#set_log_level("debug")
call lsp#add_filetype_config({
\ 'filetype': 'go',
\ 'name': 'gopls',
\ 'cmd': 'gopls'
\ })
autocmd Filetype go setl omnifunc=lsp#omnifunc
I get this error when opening a Go source file:
LSP[id=1] client has shut down after sending the message
LSP[id=1] 2019/11/13 14:27:32 : reply not invoked with a valid call
This error (as far as I can tell) comes from: https://github.com/go-language-server/jsonrpc2/blob/master/jsonrpc2.go#L334
Setting root_dir to the project dir has no effect.
Running gopls with verbose and logging:
\ 'cmd': 'gopls -v -logfile gopls.log'
Just writes an empty log.
Other details:
go version: go version go1.13.4 darwin/amd64
gopls version: golang.org/x/tools/gopls 0.2.0
golang.org/x/tools/[email protected] h1:ddCHfScTYOG6auAcEKXCFN5iSeKSAnYcPv+7zVJBd+U=
Working coc.nvim config, for reference:
{
"languageserver": {
"golang": {
"command": "gopls",
"args": [],
"rootPatterns": [
"go.mod",
".vim/",
".git/",
".hg/"
],
"filetypes": [
"go"
]
}
}
}
When invoked from coc.nvim, lsof -p <pid> | grep cwd reveals the CWD of gopls is the project directory.
I have got exact same problem. Using neovim with built-in lsp api.
Perhaps this issue is better positioned in the Neovim repository given that this seems to be an issue unrelated to nvim-lsp.
I got some more detailed logging out of gopls:
[Trace - 20:01:50.050 PM] Sending request 'initialize - (1)'.
Params: {"rootUri": "file:///Users/stefan/tmp/hello", "capabilities": {"workspace": {"configuration": true}, "textDocument": {"references": {"dynamicRegistration": false}, "completion": {"completionItem": {"snippetSupport": false, "commitCharactersSupport": false, "preselectSupport": false, "deprecatedSupport": false, "documentationFormat": ["markdown", "plaintext"]}, "contextSupport": false, "dynamicRegistration": false, "completionItemKind": {"valueSet": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]}}, "documentHighlight": {"dynamicRegistration": false}, "hover": {"dynamicRegistration": false, "contentFormat": ["markdown", "plaintext"]}, "synchronization": {"dynamicRegistration": false, "willSaveWaitUntil": false, "willSave": false, "didSave": true}, "signatureHelp": {"signatureInformation": {"documentationFormat": ["markdown", "plaintext"]}, "dynamicRegistration": false}}}, "processId": 49096, "trace": "off"}
[Trace - 20:01:50.052 PM] Received response 'initialize - (1)' in 1ms.
Result: {"capabilities":{"textDocumentSync":{"openClose":true,"change":2,"save":{}},"completionProvider":{"triggerCharacters":["."]},"hoverProvider":true,"signatureHelpProvider":{"triggerCharacters":["(",","]},"definitionProvider":true,"typeDefinitionProvider":true,"implementationProvider":true,"referencesProvider":true,"documentHighlightProvider":true,"documentSymbolProvider":true,"codeActionProvider":true,"codeLensProvider":{},"documentLinkProvider":{},"documentFormattingProvider":true,"documentOnTypeFormattingProvider":{"firstTriggerCharacter":""},"renameProvider":{},"foldingRangeProvider":true,"executeCommandProvider":{"commands":["tidy"]},"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":"workspace/didChangeWorkspaceFolders"}}},"serverInfo":{"name":""}}
[Trace - 20:01:50.055 PM] Sending notification 'initialized'.
Params: []
[Trace - 20:01:50.055 PM] Sending notification 'textDocument/didOpen'.
Params: {"textDocument": {"uri": "file:///Users/stefan/tmp/hello/hello.go", "version": 0, "languageId": "go", "text": "package main\n\n// Hello returns a greeting.\nfunc Hello(name string) string {\n if name == \"\" {\n name = \"Anonymous\"\n }\n return \"Hello, \" + name + \"!\"\n}"}}
[Trace - 20:01:50.057 PM] Received notification 'window/logMessage'.
Params: {"type":1,"message":"2019/11/20 20:01:50 : reply not invoked with a valid call"}
[Trace - 20:01:50.057 PM] Received notification 'window/logMessage'.
Params: {"type":1,"message":"2019/11/20 20:01:50 : no views in the session"}
I promised @norcalli a two minute guide on how to get a Go test environment going in a local directory, so here we go:
# We will dump it all in ~/tmp
$ mkdir ~/tmp
$ cd ~/tmp
# Install Go
$ wget https://dl.google.com/go/go1.13.4.linux-amd64.tar.gz
$ tar xfz go1.13.4.linux-amd64.tar.gz
$ export PATH=$PATH:$HOME/tmp/go/bin
$ go version
go version go1.13.4 linux/amd64
# Create the smallest hello world possible, using go module as project root
$ go mod init hello
go: creating new go.mod: module hello
$ cat > main.go
package main
func main() {
println("Hi!")
}
# Test build
$ go build
$ ./hello
Hi!
# Install gopls
$ go get golang.org/x/tools/gopls@latest
$ export PATH=$PATH:$HOME/go/bin
$ gopls version
golang.org/x/tools/gopls 0.2.0
golang.org/x/tools/[email protected] h1:qXHEqJw4CqROYvoDXinY1ZOkyAFS+jcPOvLRK76dvwY=
You are all setup now, with go and gopls in your PATH and you should be able to simply nvim main.go to see it in action.
To get verbose/tracing output from gopls, use something like:
call nvim_lsp#setup("gopls", {"cmd": "gopls -logfile /tmp/gopls.log -rpc.trace -v")
Perhaps this issue is better positioned in the Neovim repository given that this seems to be an issue unrelated to nvim-lsp.
Yes, most likely. Looking at the trace, it seems gopls is setup correctly and has a good idea of the Go project. Messages are going back & forth, it just doesn't agree about one of them it seems? I agree that is most likely more a core Neovim LSP issue.
Since the LSP support in Neovim obviously works well with other servers, I'll try to find someone on the Go team who can take a peek at the trace to get a better understanding why this specific server is having different expectations about messages.
Asking @stamblerre to take a peek at this issue - hoping we can get a hint about the reply not invoked with a valid call message that we get back from gopls.
Not too familiar with lsp but I did some digging and it looks like gopls expects initialized params to be an (empty) object {} and not an (empty) array []
@seankhliao Oh if that's the case then it's fixed in the LSP follow up PR I made. https://github.com/neovim/neovim/pull/11430. It does change some other things though. So be aware of that, specifically the vim interface was removed in favor of lua and v:lua.
It'll likely be merged this week.
@everyone I can confirm that the new LSP followup fixes gopls.
@norcalli Fantastic - I'll give it a try when it lands!
Just a heads up that neovim/neovim#11430 was merged today. The gopls integration works well now. Thank you @norcalli this is great.
I am playing with this on macOS, and I install the latest Neovim either with brew install neovim --HEAD or brew reinstall neovim after that. It is pretty easy to stay up to date.
Don't forget to also update plugins from within Neovim.
I am not sure how to properly use the LSP integration, but one thing that I noticed is that it now shows inline hints like this one:

While writing code, the messaging seems a bit erratic right now:

Looks like there are lots of opportunities to contribute to make this super awesome.
While writing code, the messaging seems a bit erratic right now
Would be nice with an option to only run diagnostics in normal mode, i.e. when leaving insert mode or when making text changes in normal mode. Some LSP servers are quite heavy (e.g. RLS) and running them continuously will be a huge battery drain and resource hog.
But maybe this is a neovim issue/feature, rather than nvim-lsp.
Also, I guess this can be closed now...?
@st3fan @lithammer that kind of thing can be addressed here. The thing about the diagnostics callback is that it's incredibly simple, meaning that anyone could customize it to their preference as long as the easy utility functions are available. This is the entire function:
M['textDocument/publishDiagnostics'] = function(_, _, result)
if not result then return end
local uri = result.uri
local bufnr = vim.uri_to_bufnr(uri)
if not bufnr then
err_message("LSP.publishDiagnostics: Couldn't find buffer for ", uri)
return
end
util.buf_clear_diagnostics(bufnr)
util.buf_diagnostics_save_positions(bufnr, result.diagnostics)
util.buf_diagnostics_underline(bufnr, result.diagnostics)
util.buf_diagnostics_virtual_text(bufnr, result.diagnostics)
-- util.set_loclist(result.diagnostics)
end
Meaning that if you wanted to control when diagnostics were displayed, or add a debounce or timeout for them, then you just need to modify the default callbacks and set that.
I'd like to improve the examples on how to customize these, but if you're familiar with Lua, you should be able to see how you can leverage InsertLeave and on_attach to set up a custom handler.
Most helpful comment
@everyone I can confirm that the new LSP followup fixes
gopls.