Description
- Did you upgrade to latest plugin version?
- Did you upgrade to/compile latest binary? Run shell command
- (Neovim users only) Did you check output of
:checkhealth LanguageClient
? - Did you check troubleshooting?
Describe the bug
I had been using an older (stable) version, but wanted to upgrade to get floating window support. Upgrading made LanguageClient-neovim fail to initialize specifically when working with Sorbet.
I bisected the bug (using make release
and git bisect
locally) to isolate the issue to this commit to LanguageClient-neovim: 815e44a which bumps jsonrpc-core
from version 12 to 13.
Environment
- neovim/vim version (
nvim --version
orvim --version
): NVIM v0.4.2 - This plugin version (
git rev-parse --short HEAD
): 4fd272b
To Reproduce
Steps to reproduce the behavior:
vimrc:
let g:LanguageClient_loggingLevel = 'INFO'
let g:LanguageClient_loggingFile = '/tmp/languageclient-neovim.log'
let g:LanguageClient_serverCommands = {}
let g:LanguageClient_serverCommands.ruby = ['bundle', 'exec', 'srb', 'tc', '--lsp', '--debug-log-file=/tmp/sorbet-nvim.log', '.']
project:
# Install Sorbet into an empty folder
mkdir -p ~/foo
cd ~/foo
echo "source 'https://rubygems.org'" > Gemfile
echo "gem 'sorbet'" >> Gemfile
bundle install
# Verify that we installed Sorbet correctly (should see a help message)
bundle exec srb tc -h
# Open vim to trigger the initialization handshake
touch empty.rb
nvim empty.rb
Current behavior
/tmp/languageclient-neovim.log
#######
LanguageClient 0.1.154 4fd272b0dbf96d7a4fd5d9d840780638f514aa7c
#######
16:36:27 INFO writer-None src/rpcclient.rs:215 => None {"jsonrpc":"2.0","method":"eval","params":["[!!get(g:, 'LanguageClient_autoStart', 1), s:GetVar('LanguageClient_serverCommands', {}), get(g:, 'LanguageClient_selectionUI', v:null), get(g:, 'LanguageClient_trace', v:null), expand(get(g:, 'LanguageClient_settingsPath', '.vim/settings.json')), !!get(g:, 'LanguageClient_loadSettings', 1), get(g:, 'LanguageClient_rootMarkers', v:null), get(g:, 'LanguageClient_changeThrottle', v:null), get(g:, 'LanguageClient_waitOutputTimeout', v:null), !!get(g:, 'LanguageClient_diagnosticsEnable', 1), get(g:, 'LanguageClient_diagnosticsList', 'Quickfix'), get(g:, 'LanguageClient_diagnosticsDisplay', {}), get(g:, 'LanguageClient_windowLogMessageLevel', 'Warning'), get(g:, 'LanguageClient_hoverPreview', 'Auto'), get(g:, 'LanguageClient_completionPreferTextEdit', 0), has('nvim')]"],"id":3}
16:36:27 INFO reader-None src/rpcclient.rs:169 <= None {"method": "languageClient/handleCursorMoved", "jsonrpc": "2.0", "params": {"bufnr": 1, "viewport": {"end": 10, "start": 0}, "languageId": "ruby", "buftype": "", "position": {"character": 2, "line": 9}, "filename": "/Users/jez/sandbox/foo/editor.rb"}}
16:36:27 INFO unnamed src/language_server_protocol.rs:2282 Begin languageClient/handleCursorMoved
16:36:27 INFO reader-None src/rpcclient.rs:169 <= None {"id": 3, "jsonrpc": "2.0", "result": [1, {"ruby": ["sorbet", "--lsp", "--enable-experimental-lsp-autocomplete", "--debug-log-file=/tmp/sorbet-nvim.log", "."]}, null, null, ".vim/settings.json", 1, null, null, null, 1, "Quickfix", {"1": {"name": "Error", "signText": "✘", "texthl": "ALEError", "signTexthl": "Error"}, "2": {"name": "Warning", "signText": "▲", "texthl": "ALEWarning", "signTexthl": "Todo"}, "3": {"name": "Information", "signText": "✘", "texthl": "ALEError", "signTexthl": "Error"}, "4": {"name": "Hint", "signText": "➤", "texthl": "ALEWarning", "signTexthl": "Todo"}}, "Warning", "Auto", 0, 1]}
16:36:27 INFO writer-None src/rpcclient.rs:215 => None {"jsonrpc":"2.0","method":"eval","params":["[get(g:, 'LanguageClient_diagnosticsSignsMax', v:null), get(g:, 'LanguageClient_diagnosticsMaxSeverity', 'Hint'), get(g:, 'LanguageClient_documentHighlightDisplay', {}), !!s:GetVar('LanguageClient_selectionUI_autoOpen', 1), s:useVirtualText(), !!s:GetVar('LanguageClient_echoProjectRoot', 1)]"],"id":4}
16:36:27 INFO reader-None src/rpcclient.rs:169 <= None {"id": 4, "jsonrpc": "2.0", "result": [null, "Hint", {}, 1, 1, 1]}
16:36:27 INFO writer-None src/rpcclient.rs:215 => None {"jsonrpc":"2.0","method":"eval","params":["get(g:, 'loaded_fzf')"],"id":5}
16:36:27 INFO reader-None src/rpcclient.rs:169 <= None {"id": 5, "jsonrpc": "2.0", "result": 1}
16:36:27 INFO unnamed src/language_server_protocol.rs:235 End sync settings
16:36:27 INFO unnamed src/language_server_protocol.rs:2835 settings synced
16:36:27 WARN unnamed src/utils.rs:77 Unknown project type. Fallback to use dir as project root: Ok("/Users/jez/sandbox/foo")
16:36:27 INFO unnamed src/language_server_protocol.rs:2861 Project root: /Users/jez/sandbox/foo
16:36:27 INFO writer-None src/rpcclient.rs:215 => None {"jsonrpc":"2.0","method":"s:EchomsgEllipsis","params":["Project root: /Users/jez/sandbox/foo"]}
16:36:27 INFO unnamed src/language_server_protocol.rs:2938 End languageClient/startServer
16:36:27 INFO unnamed src/language_server_protocol.rs:254 Defining signs
16:36:27 INFO unnamed src/language_server_protocol.rs:929 Begin initialize
16:36:27 INFO writer-None src/rpcclient.rs:215 => None {"jsonrpc":"2.0","method":"s:command","params":["sign define LanguageClientWarning text=▲ texthl=Todo","sign define LanguageClientError text=✘ texthl=Error","sign define LanguageClientHint text=➤ texthl=Todo","sign define LanguageClientInformation text=✘ texthl=Error"]}
16:36:27 INFO writer-None src/rpcclient.rs:215 => None {"jsonrpc":"2.0","method":"eval","params":["s:hasSnippetSupport()"],"id":6}
16:36:27 INFO reader-None src/rpcclient.rs:169 <= None {"id": 6, "jsonrpc": "2.0", "result": 0}
16:36:27 WARN unnamed src/language_server_protocol.rs:941 Failed to get initializationOptions: Failed to read file (/Users/jez/sandbox/foo/.vim/settings.json): No such file or directory (os error 2)
16:36:27 INFO writer-Some("ruby") src/rpcclient.rs:215 => Some("ruby") {"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{"textDocument":{"colorProvider":null,"completion":{"completionItem":{"snippetSupport":false}},"declaration":{"linkSupport":true},"definition":{"linkSupport":true},"implementation":{"linkSupport":true},"publishDiagnostics":{"relatedInformation":true},"signatureHelp":{"signatureInformation":{"parameterInformation":{"labelOffsetSupport":true}}},"typeDefinition":{"linkSupport":true}},"workspace":{"applyEdit":true,"didChangeWatchedFiles":{"dynamicRegistration":true}}},"processId":64169,"rootPath":"/Users/jez/sandbox/foo","rootUri":"file:///Users/jez/sandbox/foo","trace":"off"},"id":1}
16:36:27 INFO reader-Some("ruby") src/rpcclient.rs:169 <= Some("ruby") {"jsonrpc":"2.0","id":1,"requestMethod":"initialize","result":{"capabilities":{"textDocumentSync":1,"hoverProvider":true,"completionProvider":{"triggerCharacters":["."]},"definitionProvider":true,"typeDefinitionProvider":true,"referencesProvider":true,"documentSymbolProvider":false,"workspaceSymbolProvider":false}}}
16:36:27 ERROR reader-Some("ruby") src/rpcclient.rs:174 Failed to deserialize output: data did not match any variant of untagged enum RawMessage
Message: {"jsonrpc":"2.0","id":1,"requestMethod":"initialize","result":{"capabilities":{"textDocumentSync":1,"hoverProvider":true,"completionProvider":{"triggerCharacters":["."]},"definitionProvider":true,"typeDefinitionProvider":true,"referencesProvider":true,"documentSymbolProvider":false,"workspaceSymbolProvider":false}}}
Error: Error("data did not match any variant of untagged enum RawMessage", line: 0, column: 0)
/tmp/sorbet-nvim.log
Heads up I'm a Sorbet developer. If you need any help reading this log I'm happy to explain.
The important lines are the Read:
and Write:
lines. Those are lines that the language server process has read from stdin and written to stdout.
[2019-09-23 16:36:27.253] [consoleAndFile] [debug] Running sorbet version 0.4.0 (non-release) with arguments: sorbet --lsp --enable-experimental-lsp-autocomplete --debug-log-file=/tmp/sorbet-nvim.log .
[2019-09-23 16:36:27.253] [consoleAndFile] [debug] Creating 8 worker threads
[2019-09-23 16:36:27.254] [consoleAndFile] [debug] Worker threads created
[2019-09-23 16:36:27.260] [consoleAndFile] [debug] Unpickler::UnPickler: 5.68586ms
[2019-09-23 16:36:27.264] [consoleAndFile] [debug] readFiles: 4.54016ms
[2019-09-23 16:36:27.281] [consoleAndFile] [debug] readSymbols: 15.7838ms
[2019-09-23 16:36:27.282] [consoleAndFile] [debug] unpickleGS: 22.1477ms
[2019-09-23 16:36:27.282] [consoleAndFile] [debug] read_global_state.binary: 28.0529ms
[2019-09-23 16:36:27.282] [consoleAndFile] [debug] Starting sorbet version 0.4.0 (non-release) in LSP server mode. Talk ‘\r\n’-separated JSON-RPC to me. More details at https://microsoft.github.io/language-server-protocol/specification.If you're developing an LSP extension to some editor, make sure to run sorbet with `-v` flag,it will enable outputing the LSP session to stderr(`Write: ` and `Read: ` log lines)
[2019-09-23 16:36:27.282] [consoleAndFile] [debug] Starting monitoring path . with watchman for files with extensions rb,rbi. Subscription id: ruby-typer-64177
[2019-09-23 16:36:27.282] [consoleAndFile] [debug] Read: {"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{"textDocument":{"colorProvider":null,"completion":{"completionItem":{"snippetSupport":false}},"declaration":{"linkSupport":true},"definition":{"linkSupport":true},"implementation":{"linkSupport":true},"publishDiagnostics":{"relatedInformation":true},"signatureHelp":{"signatureInformation":{"parameterInformation":{"labelOffsetSupport":true}}},"typeDefinition":{"linkSupport":true}},"workspace":{"applyEdit":true,"didChangeWatchedFiles":{"dynamicRegistration":true}}},"processId":64169,"rootPath":"/Users/jez/sandbox/foo","rootUri":"file:///Users/jez/sandbox/foo","trace":"off"},"id":1}
[2019-09-23 16:36:27.284] [consoleAndFile] [debug] getNewRequest: 1.39295ms
[2019-09-23 16:36:27.284] [consoleAndFile] [debug] idle: 1.56914ms
[2019-09-23 16:36:27.284] [consoleAndFile] [debug] Write: {"jsonrpc":"2.0","id":1,"requestMethod":"initialize","result":{"capabilities":{"textDocumentSync":1,"hoverProvider":true,"completionProvider":{"triggerCharacters":["."]},"definitionProvider":true,"typeDefinitionProvider":true,"referencesProvider":true,"documentSymbolProvider":false,"workspaceSymbolProvider":false}}}
Diagnosis
The Sorbet language server sends an additional field in it's initialize
response message: requestMethod
. This is not mentioned in the LSP spec; it's an implementation detail that makes it easier for us to generate typed C++ bindings to the spec.
I bisected the issue back to this commit: 815e44a
If I manually revert that commit on master (i.e., downgrade the version of jsonrpc-core from 13 back to 12), everything works as expected.